Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
100.00% |
65 / 65 |
|
100.00% |
14 / 14 |
CRAP | |
100.00% |
1 / 1 |
MakePublicationTypeCommand | |
100.00% |
65 / 65 |
|
100.00% |
14 / 14 |
22 | |
100.00% |
1 / 1 |
safeHandle | |
100.00% |
15 / 15 |
|
100.00% |
1 / 1 |
2 | |||
getTitle | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
2 | |||
validateStorageDirectory | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
4 | |||
captureFieldsDefinitions | |
100.00% |
7 / 7 |
|
100.00% |
1 / 1 |
1 | |||
captureFieldDefinition | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
1 | |||
getFieldName | |
100.00% |
8 / 8 |
|
100.00% |
1 / 1 |
3 | |||
getFieldType | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
1 | |||
getCanonicalField | |
100.00% |
6 / 6 |
|
100.00% |
1 / 1 |
1 | |||
getSortField | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getSortDirection | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
getPageSize | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
1 | |||
checkIfFieldIsDuplicate | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
2 | |||
getCount | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
availableCanonicableFieldNames | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
1 |
1 | <?php |
2 | |
3 | declare(strict_types=1); |
4 | |
5 | namespace Hyde\Publications\Commands; |
6 | |
7 | use Hyde\Hyde; |
8 | use Illuminate\Support\Str; |
9 | use InvalidArgumentException; |
10 | use Illuminate\Support\Collection; |
11 | use LaravelZero\Framework\Commands\Command; |
12 | use Hyde\Publications\Concerns\PublicationFieldTypes; |
13 | use Hyde\Publications\Actions\CreatesNewPublicationType; |
14 | use Hyde\Publications\Models\PublicationFieldDefinition; |
15 | |
16 | use function trim; |
17 | use function count; |
18 | use function is_dir; |
19 | use function is_file; |
20 | use function scandir; |
21 | use function sprintf; |
22 | use function in_array; |
23 | use function array_keys; |
24 | use function strtolower; |
25 | |
26 | /** |
27 | * Hyde command to create a new publication type. |
28 | * |
29 | * @see \Hyde\Publications\Actions\CreatesNewPublicationType |
30 | * @see \Hyde\Publications\Testing\Feature\MakePublicationTypeCommandTest |
31 | */ |
32 | class MakePublicationTypeCommand extends ValidatingCommand |
33 | { |
34 | /** @var string */ |
35 | protected $signature = 'make:publicationType {name? : The name of the publication type to create}'; |
36 | |
37 | /** @var string */ |
38 | protected $description = 'Create a new publication type'; |
39 | |
40 | protected Collection $fields; |
41 | |
42 | public function safeHandle(): int |
43 | { |
44 | $this->title('Creating a new Publication Type!'); |
45 | |
46 | $title = $this->getTitle(); |
47 | $this->validateStorageDirectory(Str::slug($title)); |
48 | |
49 | $this->captureFieldsDefinitions(); |
50 | |
51 | $canonicalField = $this->getCanonicalField(); |
52 | $sortField = $this->getSortField(); |
53 | $sortAscending = $this->getSortDirection(); |
54 | $pageSize = $this->getPageSize(); |
55 | |
56 | if ($this->fields->first()->name === '__createdAt') { |
57 | $this->fields->shift(); |
58 | } |
59 | |
60 | $creator = new CreatesNewPublicationType($title, $this->fields, $canonicalField->name, $sortField, $sortAscending, $pageSize); |
61 | $this->output->writeln("Saving publication data to [{$creator->getOutputPath()}]"); |
62 | $creator->create(); |
63 | |
64 | $this->info('Publication type created successfully!'); |
65 | |
66 | return Command::SUCCESS; |
67 | } |
68 | |
69 | protected function getTitle(): string |
70 | { |
71 | return $this->argument('name') ?: trim($this->askWithValidation('name', 'Publication type name', ['required', 'string'])); |
72 | } |
73 | |
74 | protected function validateStorageDirectory(string $directoryName): void |
75 | { |
76 | $path = Hyde::path($directoryName); |
77 | if (is_file($path) || (is_dir($path) && (count(scandir($path)) > 2))) { |
78 | throw new InvalidArgumentException("Storage path [$directoryName] already exists"); |
79 | } |
80 | } |
81 | |
82 | protected function captureFieldsDefinitions(): void |
83 | { |
84 | $this->line('Now please define the fields for your publication type:'); |
85 | |
86 | $this->fields = Collection::make([ |
87 | new PublicationFieldDefinition(PublicationFieldTypes::Datetime, '__createdAt'), |
88 | ]); |
89 | |
90 | do { |
91 | $this->fields->add($this->captureFieldDefinition()); |
92 | |
93 | $addAnother = $this->confirm(sprintf('Field #%d added! Add another field?', $this->getCount() - 1), $this->input->isInteractive()); |
94 | } while ($addAnother); |
95 | } |
96 | |
97 | protected function captureFieldDefinition(): PublicationFieldDefinition |
98 | { |
99 | $this->line(''); |
100 | |
101 | $fieldName = $this->getFieldName(); |
102 | $fieldType = $this->getFieldType(); |
103 | |
104 | return new PublicationFieldDefinition($fieldType, $fieldName); |
105 | } |
106 | |
107 | protected function getFieldName(?string $message = null): string |
108 | { |
109 | $message ??= "Enter name for field #{$this->getCount()}"; |
110 | $default = $this->input->isInteractive() ? null : 'Example Field'; |
111 | |
112 | $selected = Str::kebab(trim($this->askWithValidation( |
113 | 'name', $message, ['required'], default: $default |
114 | ))); |
115 | |
116 | if ($this->checkIfFieldIsDuplicate($selected)) { |
117 | return $this->getFieldName("Try again: Enter name for field #{$this->getCount()}"); |
118 | } |
119 | |
120 | return $selected; |
121 | } |
122 | |
123 | protected function getFieldType(): PublicationFieldTypes |
124 | { |
125 | return PublicationFieldTypes::from(strtolower($this->choice( |
126 | "Enter type for field #{$this->getCount()}", |
127 | PublicationFieldTypes::names(), |
128 | 'String' |
129 | ))); |
130 | } |
131 | |
132 | protected function getCanonicalField(): PublicationFieldDefinition |
133 | { |
134 | $options = $this->availableCanonicableFieldNames(); |
135 | |
136 | return $this->fields->firstWhere('name', $this->choice( |
137 | 'Choose a canonical name field <fg=gray>(this will be used to generate filenames, so the values need to be unique)</>', |
138 | $options->toArray(), |
139 | $options->first() |
140 | )); |
141 | } |
142 | |
143 | protected function getSortField(): string |
144 | { |
145 | return $this->choice('Choose the field you wish to sort by', $this->availableCanonicableFieldNames()->toArray(), 0); |
146 | } |
147 | |
148 | protected function getSortDirection(): bool |
149 | { |
150 | $options = ['Ascending' => true, 'Descending' => false]; |
151 | |
152 | return $options[$this->choice('Choose the sort direction', array_keys($options), 'Ascending')]; |
153 | } |
154 | |
155 | protected function getPageSize(): int |
156 | { |
157 | return (int) $this->askWithValidation('pageSize', |
158 | 'How many links should be shown on the listing page? <fg=gray>(any value above 0 will enable <href=https://docs.hydephp.com/search?query=pagination>pagination</>)</>', |
159 | ['required', 'integer', 'between:0,100'], |
160 | 0 |
161 | ); |
162 | } |
163 | |
164 | protected function checkIfFieldIsDuplicate(string $name): bool |
165 | { |
166 | if ($this->fields->where('name', $name)->count() > 0) { |
167 | $this->error("Field name [$name] already exists!"); |
168 | |
169 | return true; |
170 | } |
171 | |
172 | return false; |
173 | } |
174 | |
175 | protected function getCount(): int |
176 | { |
177 | return $this->fields->count(); |
178 | } |
179 | |
180 | protected function availableCanonicableFieldNames(): Collection |
181 | { |
182 | return $this->fields->reject(function (PublicationFieldDefinition $field): bool { |
183 | return ! in_array($field->type, PublicationFieldTypes::canonicable()); |
184 | })->pluck('name'); |
185 | } |
186 | } |