Skip to content

Commit

Permalink
Merge pull request #804 from hydephp/add-back-publications-tagGroup-f…
Browse files Browse the repository at this point in the history
…ield

Add back the tagGroup option for publication tag fields
  • Loading branch information
caendesilva authored Jan 4, 2023
2 parents aa95454 + 708b3f3 commit 8a55834
Show file tree
Hide file tree
Showing 13 changed files with 299 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -155,16 +155,17 @@ protected function captureImageFieldInput(PublicationFieldDefinition $field): ?P

protected function captureTagFieldInput(PublicationFieldDefinition $field): ?PublicationFieldValue
{
$this->infoComment('Select a tag for field', $field->name, "from the {$this->publicationType->getIdentifier()} group");
$tagGroup = $field->tagGroup ?? throw new InvalidArgumentException("Tag field '$field->name' is missing the 'tagGroup' property");
$this->infoComment('Select a tag for field', $field->name, "from the $tagGroup group");

$options = PublicationService::getValuesForTagName($this->publicationType->getIdentifier());
$options = PublicationService::getValuesForTagName($tagGroup);
if ($options->isEmpty()) {
return $this->handleEmptyOptionsCollection($field, 'tag', 'No tags for this publication type found in tags.json');
}

$this->tip('You can enter multiple tags separated by commas');

$choice = $this->reloadableChoice($this->getReloadableTagValuesArrayClosure(),
$choice = $this->reloadableChoice($this->getReloadableTagValuesArrayClosure($tagGroup),
'Which tag would you like to use?',
'Reload tags.json',
true
Expand Down Expand Up @@ -210,10 +211,10 @@ protected function tip(string $message): void
}

/** @return Closure<array<string>> */
protected function getReloadableTagValuesArrayClosure(): Closure
protected function getReloadableTagValuesArrayClosure(string $tagGroup): Closure
{
return function (): array {
return PublicationService::getValuesForTagName($this->publicationType->getIdentifier())->toArray();
return function () use ($tagGroup): array {
return PublicationService::getValuesForTagName($tagGroup)->toArray();
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use Hyde\Console\Concerns\ValidatingCommand;
use Hyde\Framework\Actions\CreatesNewPublicationType;
use Hyde\Framework\Features\Publications\Models\PublicationFieldDefinition;
use Hyde\Framework\Features\Publications\Models\PublicationTags;
use Hyde\Framework\Features\Publications\PublicationFieldTypes;
use Hyde\Hyde;
use Illuminate\Support\Collection;
Expand Down Expand Up @@ -103,6 +104,12 @@ protected function captureFieldDefinition(): PublicationFieldDefinition

// TODO: Here we could collect other data like the "rules" array for the field.

if ($fieldType === PublicationFieldTypes::Tag) {
$tagGroup = $this->getTagGroup();

return new PublicationFieldDefinition($fieldType, $fieldName, tagGroup: $tagGroup);
}

return new PublicationFieldDefinition($fieldType, $fieldName);
}

Expand All @@ -126,6 +133,23 @@ protected function getFieldType(): PublicationFieldTypes
return PublicationFieldTypes::from(strtolower($choice));
}

protected function getTagGroup(): string
{
if (empty(PublicationTags::getTagGroups())) {
$this->error('No tag groups have been added to tags.json');
if ($this->confirm('Would you like to add some tags now?')) {
$this->call('make:publicationTag');

$this->newLine();
$this->comment("Okay, we're back on track!");
} else {
throw new InvalidArgumentException('Can not create a tag field without any tag groups defined in tags.json');
}
}

return $this->choice("Enter tag group for field #{$this->getCount()}", PublicationTags::getTagGroups());
}

protected function getCanonicalField(): PublicationFieldDefinition
{
$selectableFields = $this->fields->reject(function (PublicationFieldDefinition $field): bool {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ public function safeHandle(): int
$this->output->write("\n<fg=cyan> Validating publication [$publication->title]</>");
$publication->matter->forget('__createdAt');

foreach ($publication->type->fields as $field) {
foreach ($publication->type->getFieldData() as $field) {
$countFields++;
$fieldName = $field['name'];
$pubTypeField = new PublicationFieldDefinition($field['type'], $fieldName);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ protected function generateFieldData(PublicationFieldDefinition $field): string|
'image' => 'https://picsum.photos/id/'.rand(1, 1000).'/400/400',
'integer' => rand(-100000, 100000),
'string' => substr($this->fakeSentence(10), 0, rand(0, 255)),
'tag' => $this->getTags(),
'tag' => $this->getTags($field->tagGroup),
'text' => $this->getTextValue(rand(3, 20)),
'url' => $this->fakeUrl(),
};
Expand Down Expand Up @@ -128,9 +128,9 @@ protected function getArrayItems(): array
return $arrayItems;
}

protected function getTags(): string
protected function getTags(string $tagGroup): string
{
$tags = PublicationService::getValuesForTagName($this->pubType->getIdentifier());
$tags = PublicationService::getValuesForTagName($tagGroup);

return $tags->isEmpty() ? '' : $tags->random();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,17 +27,19 @@ class PublicationFieldDefinition implements SerializableContract
public readonly PublicationFieldTypes $type;
public readonly string $name;
public readonly array $rules;
public readonly ?string $tagGroup;

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

public function __construct(PublicationFieldTypes|string $type, string $name, array $rules = [])
public function __construct(PublicationFieldTypes|string $type, string $name, array $rules = [], ?string $tagGroup = null)
{
$this->type = $type instanceof PublicationFieldTypes ? $type : PublicationFieldTypes::from(strtolower($type));
$this->name = str_starts_with($name, '__') ? $name : Str::kebab($name);
$this->rules = $rules;
$this->tagGroup = $tagGroup;
}

public function toArray(): array
Expand All @@ -46,6 +48,7 @@ public function toArray(): array
'type' => $this->type->value,
'name' => $this->name,
'rules' => $this->rules,
'tagGroup' => $this->tagGroup,
]);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,16 @@ public static function getValuesForTagName(string $tagName): array
return self::getAllTags()->get($tagName) ?? [];
}

/**
* Get all tag names.
*
* @return array<string>
*/
public static function getTagGroups(): array
{
return self::getAllTags()->keys()->toArray();
}

/**
* Validate the tags.json file is valid.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,14 +96,28 @@ public function getDirectory(): string
return $this->directory;
}

/** @return \Illuminate\Support\Collection<string, \Hyde\Framework\Features\Publications\Models\PublicationFieldDefinition> */
/**
* Get the raw field definitions for this publication type.
*
* @see self::getFields() to get the deserialized field definitions.
*/
public function getFieldData(): array
{
return $this->fields;
}

/**
* Get the publication fields, deserialized to PublicationFieldDefinition objects.
*
* @see self::getFieldData() to get the raw field definitions.
*
* @return \Illuminate\Support\Collection<string, \Hyde\Framework\Features\Publications\Models\PublicationFieldDefinition>
*/
public function getFields(): Collection
{
$result = collect($this->fields)->mapWithKeys(function (array $data): array {
return Collection::make($this->fields)->mapWithKeys(function (array $data): array {
return [$data['name'] => new PublicationFieldDefinition(...$data)];
});

return Collection::make($result);
}

public function getFieldDefinition(string $fieldName): PublicationFieldDefinition
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,10 @@ public function testWithTagType()
{
$tags = ['test-publication' => ['foo', 'bar', 'baz']];
$this->file('tags.json', json_encode($tags));
$this->updateSchema('tag', 'tag');
$this->pubType->fields = [
(new PublicationFieldDefinition('tag', 'tag', tagGroup: 'test-publication'))->toArray(),
];
$this->pubType->save();
(new SeedsPublicationFiles($this->pubType))->create();

$publication = $this->firstPublication();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,7 @@ public function test_command_with_single_tag_input()
'fields' => [[
'type' => 'tag',
'name' => 'tag',
'tagGroup' => 'test-publication',
],
],
]);
Expand All @@ -360,6 +361,7 @@ public function test_command_with_multiple_tag_inputs()
'fields' => [[
'type' => 'tag',
'name' => 'tags',
'tagGroup' => 'test-publication',
],
],
]);
Expand Down Expand Up @@ -434,6 +436,7 @@ public function test_tag_input_with_no_tags()
'fields' => [[
'type' => 'tag',
'name' => 'tag',
'tagGroup' => 'test-publication',
],
],
]);
Expand All @@ -454,6 +457,7 @@ public function test_tag_input_with_no_tags_but_skips()
'fields' => [[
'type' => 'tag',
'name' => 'tag',
'tagGroup' => 'test-publication',
],
],
]);
Expand All @@ -477,6 +481,25 @@ public function test_tag_input_with_no_tags_but_skips()
MARKDOWN, $this->getDatedPublicationContents());
}

public function test_tag_input_for_field_without_tagGroup_specified()
{
config(['app.throw_on_console_exception' => false]);
$this->makeSchemaFile([
'canonicalField' => '__createdAt',
'fields' => [[
'type' => 'tag',
'name' => 'tag',
],
],
]);

$this->artisan('make:publication test-publication')
->expectsOutput("Error: Tag field 'tag' is missing the 'tagGroup' property")
->assertExitCode(1);

$this->assertFileDoesNotExist(Hyde::path('test-publication/2022-01-01-000000.md'));
}

public function test_handleEmptyOptionsCollection_for_required_field()
{
config(['app.throw_on_console_exception' => false]);
Expand All @@ -486,6 +509,7 @@ public function test_handleEmptyOptionsCollection_for_required_field()
'type' => 'tag',
'name' => 'tag',
'rules' => ['required'],
'tagGroup' => 'test-publication',
],
],
]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
namespace Hyde\Framework\Testing\Feature\Commands;

use function config;
use Hyde\Console\Commands\Helpers\InputStreamHandler;
use Hyde\Facades\Filesystem;
use Hyde\Framework\Features\Publications\Models\PublicationTags;
use Hyde\Framework\Features\Publications\PublicationFieldTypes;
use Hyde\Hyde;
use Hyde\Testing\TestCase;
Expand Down Expand Up @@ -158,4 +160,98 @@ public function test_with_existing_publication_of_the_same_name()
->expectsOutput('Error: Storage path [test-publication] already exists')
->assertExitCode(1);
}

public function testWithTagFieldInput()
{
$this->directory('test-publication');

(new PublicationTags())->addTagGroups([
'foo' => ['bar', 'baz'],
'bar' => ['foo', 'baz'],
])->save();

$this->artisan('make:publicationType "Test Publication" --use-defaults')
->expectsQuestion('Enter name for field #1', 'MyTag')
->expectsChoice('Enter type for field #1', 'Tag',
['String', 'Datetime', 'Boolean', 'Integer', 'Float', 'Image', 'Array', 'Text', 'Url', 'Tag'])
->expectsChoice('Enter tag group for field #1', 'foo', ['bar', 'foo'], true)
->assertSuccessful();

$this->assertFileExists(Hyde::path('test-publication/schema.json'));
$this->assertFileEqualsString(
<<<'JSON'
{
"name": "Test Publication",
"canonicalField": "__createdAt",
"detailTemplate": "detail.blade.php",
"listTemplate": "list.blade.php",
"pagination": {
"sortField": "__createdAt",
"sortAscending": true,
"prevNextLinks": true,
"pageSize": 25
},
"fields": [
{
"type": "datetime",
"name": "__createdAt"
},
{
"type": "tag",
"name": "my-tag",
"tagGroup": "foo"
}
]
}
JSON,
'test-publication/schema.json');

unlink(Hyde::path('tags.json'));
}

public function testWithTagFieldInputButNoTags()
{
config(['app.throw_on_console_exception' => false]);
$this->directory('test-publication');

$this->artisan('make:publicationType "Test Publication" --use-defaults')
->expectsQuestion('Enter name for field #1', 'MyTag')
->expectsChoice('Enter type for field #1', 'Tag',
['String', 'Datetime', 'Boolean', 'Integer', 'Float', 'Image', 'Array', 'Text', 'Url', 'Tag'], true)
->expectsOutput('No tag groups have been added to tags.json')
->expectsConfirmation('Would you like to add some tags now?')
->expectsOutput('Error: Can not create a tag field without any tag groups defined in tags.json')
->assertExitCode(1);

$this->assertFileDoesNotExist(Hyde::path('test-publication/schema.json'));
}

public function testWithTagFieldInputButNoTagsCanPromptToCreateTags()
{
$this->directory('test-publication');
$this->cleanUpWhenDone('tags.json');
InputStreamHandler::mockInput("foo\nbar\nbaz\n");

$this->artisan('make:publicationType "Test Publication"')
->expectsQuestion('Enter name for field #1', 'MyTag')
->expectsChoice('Enter type for field #1', 'Tag',
['String', 'Datetime', 'Boolean', 'Integer', 'Float', 'Image', 'Array', 'Text', 'Url', 'Tag'])
->expectsOutput('No tag groups have been added to tags.json')
->expectsConfirmation('Would you like to add some tags now?', 'yes')
->expectsQuestion('Tag name', 'foo')
->expectsOutput("Okay, we're back on track!")
->expectsChoice('Enter tag group for field #1', 'foo', ['foo'], true)
->expectsConfirmation('Field #1 added! Add another field?')
->expectsConfirmation('Do you want to configure pagination settings?')
->expectsChoice('Choose a canonical name field (this will be used to generate filenames, so the values need to be unique)', '__createdAt', ['__createdAt'])
->doesntExpectOutput('Error: Can not create a tag field without any tag groups defined in tags.json')
->assertSuccessful();

$this->assertCommandCalled('make:publicationTag');
$this->assertFileExists(Hyde::path('tags.json'));
$this->assertSame(
json_encode(['foo' => ['foo', 'bar', 'baz']], 128),
file_get_contents(Hyde::path('tags.json'))
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -107,4 +107,22 @@ public function test_get_rules_with_custom_type_rules()
$field = new PublicationFieldDefinition('string', 'test', ['required', 'foo']);
$this->assertSame(['string', 'required', 'foo'], $field->getRules());
}

public function test_can_construct_with_tag_group()
{
$field = new PublicationFieldDefinition('tag', 'test', [], 'myTags');
$this->assertSame('myTags', $field->tagGroup);
}

public function test_can_serialize_tag_group()
{
$field = new PublicationFieldDefinition('tag', 'test', [], 'myTags');
$this->assertSame([
'type' => 'tag',
'name' => 'test',
'tagGroup' => 'myTags',
], $field->toArray());

$this->assertSame('{"type":"tag","name":"test","tagGroup":"myTags"}', json_encode($field));
}
}
Loading

0 comments on commit 8a55834

Please sign in to comment.