Skip to content

Commit

Permalink
Merge pull request #716 from rgasch/publications-feature
Browse files Browse the repository at this point in the history
Committing code to 'tag' field type.
  • Loading branch information
caendesilva authored Nov 28, 2022
2 parents 15f2831 + 1314bb6 commit da64143
Show file tree
Hide file tree
Showing 10 changed files with 403 additions and 267 deletions.
372 changes: 184 additions & 188 deletions composer.lock

Large diffs are not rendered by default.

42 changes: 29 additions & 13 deletions packages/framework/src/Console/Commands/MakePublicationCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ public function safeHandle(): int
return Command::SUCCESS;
}

protected function captureFieldInput(PublicationFieldType $field, Collection $mediaFiles): string|array
protected function captureFieldInput(PublicationFieldType $field, PublicationType $pubType): string|array
{
if ($field->type === 'text') {
$lines = [];
Expand All @@ -70,7 +70,7 @@ protected function captureFieldInput(PublicationFieldType $field, Collection $me
$lines[] = $line;
} while (true);

return implode("\n", $lines);
return $lines;
}

if ($field->type === 'array') {
Expand All @@ -81,25 +81,43 @@ protected function captureFieldInput(PublicationFieldType $field, Collection $me
if ($line === '') {
break;
}
$lines[] = $line;
$lines[] = trim($line);
} while (true);

return $lines;
}

if ($field->type === 'image') {
$this->output->writeln($field->name.' (end with an empty line)');
$offset = 0;
foreach ($mediaFiles as $index => $file) {
$offset = $index + 1;
$this->output->writeln(" $offset: $file");
}
$selected = $this->askWithValidation($field->name, $field->name, ['required', 'integer', "between:1,$offset"]);
do {
$offset = 0;
$mediaFiles = PublicationService::getMediaForPubType($pubType);
foreach ($mediaFiles as $index => $file) {
$offset = $index + 1;
$this->output->writeln(" $offset: $file");
}
$selected = (int) $this->askWithValidation($field->name, $field->name, ['required', 'integer', "between:1,$offset"]);
} while ($selected == 0);
$file = $mediaFiles->{$selected - 1};

return '_media/'.Str::of($file)->after('media/')->toString();
}

if ($field->type === 'tag') {
$this->output->writeln($field->name.' (enter 0 to reload tag definitions)');
do {
$offset = 0;
$tagsForGroup = PublicationService::getAllTags()->{$field->tagGroup};
foreach ($tagsForGroup as $index=>$value) {
$offset = $index + 1;
$this->output->writeln(" $offset: $value");
}
$selected = (int) $this->askWithValidation($field->name, $field->name, ['required', 'integer', "between:0,$offset"]);
} while ($selected == 0);

return $tagsForGroup->{$selected - 1};
}

// Fields which are not of type array, text or image
$fieldRules = Collection::create(PublicationFieldType::DEFAULT_RULES)->{$field->type};
if ($fieldRules->contains('between')) {
Expand Down Expand Up @@ -151,10 +169,8 @@ protected function collectFieldData(PublicationType $pubType): Collection
{
$this->output->writeln("\n<bg=magenta;fg=white>Now please enter the field data:</>");

$mediaFiles = PublicationService::getMediaForPubType($pubType);

return Collection::make($pubType->fields)->mapWithKeys(function ($field) use ($mediaFiles) {
return [$field['name'] => $this->captureFieldInput(PublicationFieldType::fromArray($field), $mediaFiles)];
return Collection::make($pubType->fields)->mapWithKeys(function ($field) use ($pubType) {
return [$field['name'] => $this->captureFieldInput(PublicationFieldType::fromArray($field), $pubType)];
});
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<?php

declare(strict_types=1);

namespace Hyde\Console\Commands;

use Hyde\Console\Commands\Interfaces\CommandHandleInterface;
use Hyde\Console\Concerns\ValidatingCommand;
use Hyde\Framework\Features\Publications\PublicationService;
use Hyde\Hyde;
use Illuminate\Support\Str;
use LaravelZero\Framework\Commands\Command;
use function Safe\file_put_contents;
use function Safe\json_encode;

/**
* Hyde Command to create a new publication type.
*
* @see \Hyde\Framework\Testing\Feature\Commands\MakePublicationTypeCommandTest
*/
class MakePublicationTagCommand extends ValidatingCommand implements CommandHandleInterface
{
/** @var string */
protected $signature = 'make:publicationTag';

/** @var string */
protected $description = 'Create a new publication type tag definition';

public function handle(): int
{
$this->title('Creating a new Publication Type Tag!');

$filename = Hyde::pathToRelative('tags.json');
$tags = PublicationService::getAllTags();
$tagName = $this->askWithValidation('name', 'Tag name', ['required', 'string']);
if (isset($tags[$tagName])) {
$this->output->error("Tag [$tagName] already exists");

return Command::FAILURE;
}

$lines = [];
$this->output->writeln('<bg=magenta;fg=white>Enter the tag values (end with an empty line):</>');
do {
$line = Str::replace(["\n", "\r"], '', fgets(STDIN));
if ($line === '') {
break;
}
$lines[] = trim($line);
} while (true);
$tags[$tagName] = $lines;

$this->output->writeln(sprintf('Saving tag data to [%s]', $filename));
file_put_contents($filename, json_encode($tags, JSON_PRETTY_PRINT));

return Command::SUCCESS;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use Hyde\Console\Commands\Interfaces\CommandHandleInterface;
use Hyde\Console\Concerns\ValidatingCommand;
use Hyde\Framework\Actions\CreatesNewPublicationType;
use Hyde\Framework\Features\Publications\PublicationService;
use Illuminate\Support\Str;
use InvalidArgumentException;
use LaravelZero\Framework\Commands\Command;
Expand Down Expand Up @@ -76,14 +77,16 @@ public function handle(): int
);

$this->output->writeln('<bg=magenta;fg=white>Choose a canonical name field (the values of this field have to be unique!):</>');
$fieldNames = [];
foreach ($fields as $k => $v) {
if ($fields->first()->type != 'image') {
if ($v->type != 'image' && $v->type != 'tag') {
$fieldNames[] = $v->name;
$offset = $k + 1;
$this->line(" $offset: $v->name");
}
}
$selected = (int) $this->askWithValidation('selected', "Canonical field (1-$offset)", ['required', 'integer', "between:1,$offset"], 1);
$canonicalField = $fields[$selected - 1]['name'];
$canonicalField = $fieldNames[$selected - 1];

try {
$creator = new CreatesNewPublicationType($title, $fields, $canonicalField, $sortField, $sortDirection, $pageSize, $prevNextLinks, $this->output);
Expand All @@ -109,41 +112,64 @@ protected function captureFieldsDefinitions(): Collection
$this->output->writeln("<bg=cyan;fg=white>Field #$count:</>");

$field = Collection::create();
$field->name = $this->askWithValidation('name', 'Field name', ['required']);
do {
$field->name = trim($this->askWithValidation('name', 'Field name', ['required']));
$duplicate = $fields->where('name', $field->name)->count();
if ($duplicate) {
$this->error("Field name [$field->name] already exists!");
}
} while ($duplicate);

$this->line('Field type:');
$this->line(' 1 - String');
$this->line(' 2 - Boolean ');
$this->line(' 3 - Integer');
$this->line(' 4 - Float');
$this->line(' 5 - Datetime');
$this->line(' 5 - Datetime (YYYY-MM-DD (HH:MM:SS))');
$this->line(' 6 - URL');
$this->line(' 7 - Array');
$this->line(' 8 - Text');
$this->line(' 9 - Local Image');
$type = (int) $this->askWithValidation('type', 'Field type (1-9)', ['required', 'integer', 'between:1,9'], 1);
do {
// TODO This should only be done for types that can have length restrictions right?
$field->min = $this->askWithValidation('min', 'Min value (for strings, this refers to string length)', ['required', 'string'], 0);
$field->max = $this->askWithValidation('max', 'Max value (for strings, this refers to string length)', ['required', 'string'], 0);
$lengthsValid = true;
if ($field->max < $field->min) {
$lengthsValid = false;
$this->output->warning('Field length [max] must be [>=] than [min]');
$this->line(' 10 - Tag (select value from list)');
$type = (int) $this->askWithValidation('type', 'Field type (1-10)', ['required', 'integer', 'between:1,10'], 1);

if ($type < 10) {
do {
$field->min = trim($this->askWithValidation('min', 'Min value (for strings, this refers to string length)', ['required', 'string'], 0));
$field->max = trim($this->askWithValidation('max', 'Max value (for strings, this refers to string length)', ['required', 'string'], 0));
$lengthsValid = true;
if ($field->max < $field->min) {
$lengthsValid = false;
$this->output->warning('Field length [max] must be [>=] than [min]');
}
} while (! $lengthsValid);
} else {
$allTags = PublicationService::getAllTags();
$offset = 1;
foreach ($allTags as $k=>$v) {
$this->line(" $offset - $k");
$offset++;
}
} while (! $lengthsValid);
$addAnother = $this->askWithValidation('addAnother', 'Add another field (y/n)', ['required', 'string', 'in:y,n'], 'y');
$offset--; // The above loop overcounts by 1
$selected = $this->askWithValidation('tagGroup', 'Tag Group', ['required', 'integer', "between:1,$offset"], 0);
$field->tagGroup = $allTags->keys()->{$selected - 1};
$field->min = 0;
$field->max = 0;
}
$addAnother = $this->askWithValidation('addAnother', '<bg=magenta;fg=white>Add another field (y/n)</>', ['required', 'string', 'in:y,n'], 'y');

// map field choice to actual field type
$field->type = match ($type) {
1 => 'string',
2 => 'boolean',
3 => 'integer',
4 => 'float',
5 => 'datetime',
6 => 'url',
7 => 'array',
8 => 'text',
9 => 'image',
1 => 'string',
2 => 'boolean',
3 => 'integer',
4 => 'float',
5 => 'datetime',
6 => 'url',
7 => 'array',
8 => 'text',
9 => 'image',
10 => 'tag',
};

$fields->add($field);
Expand Down
18 changes: 8 additions & 10 deletions packages/framework/src/Console/Concerns/ValidatingCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,13 @@ public function askWithValidation(
array $rules = [],
mixed $default = null,
int $retryCount = 0
): mixed {
$answer = $this->ask(ucfirst($question), $default);
): string {
if ($retryCount >= self::MAX_RETRIES) {
// Prevent infinite loops that may happen, for example when testing. The retry count is high enough to not affect normal usage.
throw new RuntimeException(sprintf("Too many validation errors trying to validate '$name' with rules: [%s]", implode(', ', $rules)));
}

$answer = trim((string) $this->ask(ucfirst($question), $default));
$validator = Validator::make([$name => $answer], [$name => $rules]);

if ($validator->passes()) {
Expand All @@ -75,14 +80,7 @@ public function askWithValidation(
$this->error($this->translate($name, $error));
}

$retryCount++;

if ($retryCount >= self::MAX_RETRIES) {
// Prevent infinite loops that may happen, for example when testing. The retry count is high enough to not affect normal usage.
throw new RuntimeException(sprintf("Too many validation errors trying to validate '$name' with rules: [%s]", implode(', ', $rules)));
}

return $this->askWithValidation($name, $question, $rules, $default, $retryCount);
return $this->askWithValidation($name, $question, $rules, $default, $retryCount + 1);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ public function register(): void

Commands\MakePageCommand::class,
Commands\MakePostCommand::class,
Commands\MakePublicationTagCommand::class,
Commands\MakePublicationTypeCommand::class,
Commands\MakePublicationCommand::class,

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class PublicationFieldType implements SerializableContract
{
use Serializable;

public final const TYPES = ['string', 'boolean', 'integer', 'float', 'datetime', 'url', 'array', 'text', 'image'];
public final const TYPES = ['string', 'boolean', 'integer', 'float', 'datetime', 'url', 'array', 'text', 'image', 'tag'];
public final const DEFAULT_RULES = [
'string' => ['required', 'string', 'between'],
'boolean' => ['required', 'boolean'],
Expand All @@ -29,27 +29,29 @@ class PublicationFieldType implements SerializableContract
];

public readonly string $type;
public readonly ?int $max;
public readonly ?int $min;
public readonly string $max;
public readonly string $min;
public readonly string $name;
public readonly ?string $tagGroup;

public static function fromArray(array $array): static
{
return new static(...$array);
}

public function __construct(string $type, string $name, int|string|null $min, int|string|null $max)
public function __construct(string $type, string $name, int|string|null $min, int|string|null $max, ?string $tagGroup = null)
{
$this->type = strtolower($type);
$this->name = Str::kebab($name);
$this->min = $this->parseInt($min);
$this->max = $this->parseInt($max);
$this->min = (string) $min;
$this->max = (string) $max;
$this->tagGroup = $tagGroup;

if (! in_array(strtolower($type), self::TYPES)) {
throw new InvalidArgumentException(sprintf("The type '$type' is not a valid type. Valid types are: %s.", implode(', ', self::TYPES)));
}

if (($min !== null) && ($max !== null) && $max < $min) {
if ($max < $min) {
throw new InvalidArgumentException("The 'max' value cannot be less than the 'min' value.");
}
}
Expand Down
Loading

0 comments on commit da64143

Please sign in to comment.