Passed
Push — develop ( ba64a1...18b4ab )
by nguereza
03:11
created

BaseMakeActionCommand::getRoutePrefix()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 5
c 1
b 0
f 0
nc 2
nop 0
dl 0
loc 9
rs 10
1
<?php
2
3
/**
4
 * Platine PHP
5
 *
6
 * Platine Framework is a lightweight, high-performance, simple and elegant
7
 * PHP Web framework
8
 *
9
 * This content is released under the MIT License (MIT)
10
 *
11
 * Copyright (c) 2020 Platine PHP
12
 *
13
 * Permission is hereby granted, free of charge, to any person obtaining a copy
14
 * of this software and associated documentation files (the "Software"), to deal
15
 * in the Software without restriction, including without limitation the rights
16
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17
 * copies of the Software, and to permit persons to whom the Software is
18
 * furnished to do so, subject to the following conditions:
19
 *
20
 * The above copyright notice and this permission notice shall be included in all
21
 * copies or substantial portions of the Software.
22
 *
23
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29
 * SOFTWARE.
30
 */
31
32
/**
33
 *  @file BaseMakeActionCommand.php
34
 *
35
 *  The action base make command class
36
 *
37
 *  @package    Platine\Framework\Console
38
 *  @author Platine Developers team
39
 *  @copyright  Copyright (c) 2020
40
 *  @license    http://opensource.org/licenses/MIT  MIT License
41
 *  @link   https://www.platine-php.com
42
 *  @version 1.0.0
43
 *  @filesource
44
 */
45
46
declare(strict_types=1);
47
48
namespace Platine\Framework\Console;
49
50
use Platine\Console\Input\Reader;
51
use Platine\Console\Output\Writer;
52
use Platine\Filesystem\Filesystem;
53
use Platine\Framework\App\Application;
54
use Platine\Framework\Console\MakeCommand;
55
use Platine\Stdlib\Helper\Json;
56
use Platine\Stdlib\Helper\Str;
57
58
/**
59
 * @class BaseMakeActionCommand
60
 * @package Platine\Framework\Console
61
 */
62
abstract class BaseMakeActionCommand extends MakeCommand
63
{
64
    /**
65
     * The form parameter class name
66
     * @var class-string
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string.
Loading history...
67
     */
68
    protected string $paramClass;
69
70
    /**
71
     * The form validation class name
72
     * @var class-string
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string.
Loading history...
73
     */
74
    protected string $validatorClass;
75
76
    /**
77
     * The entity class name
78
     * @var class-string
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string.
Loading history...
79
     */
80
    protected string $entityClass;
81
82
    /**
83
     * The repository class name
84
     * @var class-string
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string.
Loading history...
85
     */
86
    protected string $repositoryClass;
87
88
    /**
89
     * Create new instance
90
     * @param Application $application
91
     * @param Filesystem $filesystem
92
     */
93
    public function __construct(
94
        Application $application,
95
        Filesystem $filesystem
96
    ) {
97
        parent::__construct($application, $filesystem);
98
99
        $this->addOption(
100
            '-c|--fields',
101
            'The entity fields. Example field1:param1,field2:param2,field3',
102
            null,
103
            false
104
        );
105
106
        $this->addOption(
107
            '-i|--fields-unique',
108
            'The entity unique fields. Example field1:param1,field2:param2,field3',
109
            null,
110
            false
111
        );
112
113
        $this->addOption(
114
            '-o|--fields-order',
115
            'The entity orders fields. Example field1:ASC,field2:DESC,field3',
116
            null,
117
            false
118
        );
119
120
        $this->addOption(
121
            '-t|--template-prefix',
122
            'The template prefix',
123
            null,
124
            false
125
        );
126
127
        $this->addOption(
128
            '-r|--route-prefix',
129
            'The route name prefix',
130
            null,
131
            false
132
        );
133
134
        $this->addOption(
135
            '-e|--message-not-found',
136
            'The entity not found error message',
137
            'This record doesn\'t exist',
138
            false
139
        );
140
141
        $this->addOption(
142
            '-l|--message-duplicate',
143
            'The entity duplicate error message',
144
            'This record already exist',
145
            false
146
        );
147
148
        $this->addOption(
149
            '-a|--message-create',
150
            'The entity successfully create message',
151
            'Data successfully created',
152
            false
153
        );
154
155
        $this->addOption(
156
            '-u|--message-update',
157
            'The entity successfully update message',
158
            'Data successfully updated',
159
            false
160
        );
161
162
        $this->addOption(
163
            '-d|--message-delete',
164
            'The entity successfully delete message',
165
            'Data successfully deleted',
166
            false
167
        );
168
169
        $this->addOption(
170
            '-p|--message-process-error',
171
            'The entity processing error message',
172
            'Data processing error',
173
            false
174
        );
175
176
        $this->addOption(
177
            '-j|--config',
178
            'Use JSON config file for options',
179
            null,
180
            false
181
        );
182
183
        $this->addOption(
184
            '-b|--entity-context-key',
185
            'The entity context key name',
186
            'entity',
187
            false
188
        );
189
    }
190
191
    /**
192
     * {@inheritdoc}
193
     */
194
    public function interact(Reader $reader, Writer $writer): void
195
    {
196
        parent::interact($reader, $writer);
197
198
        // Load configuration file if exist
199
        $this->loadConfig();
200
201
        $this->recordResourceClasses();
202
    }
203
204
    /**
205
     * Record class properties
206
     * @return void
207
     */
208
    protected function recordProperties(): void
209
    {
210
        $io = $this->io();
211
212
        $writer = $io->writer();
213
214
        $writer->boldYellow('Enter the properties list (empty value to finish):', true);
215
        $value = '';
216
        while ($value !== null) {
217
            $value = $io->prompt('Property full class name', null, null, false);
218
219
            if (!empty($value)) {
220
                $value = trim($value);
221
                if (!class_exists($value) && !interface_exists($value)) {
222
                    $writer->boldWhiteBgRed(sprintf('The class [%s] does not exists', $value), true);
223
                } else {
224
                    $shortClass = $this->getClassBaseName($value);
225
                    $name = Str::camel($shortClass, true);
226
                    //replace"interface", "abstract"
227
                    $nameClean = str_ireplace(['interface', 'abstract'], '', $name);
228
229
                    $this->properties[$value] = [
230
                        'name' => $nameClean,
231
                        'short' => $shortClass,
232
                    ];
233
                }
234
            }
235
        }
236
    }
237
238
    /**
239
     * Record the resource classes
240
     * @return void
241
     */
242
    protected function recordResourceClasses(): void
243
    {
244
        $io = $this->io();
245
246
        $paramClass = $io->prompt('Enter the form parameter full class name', null);
247
        while (!class_exists($paramClass)) {
248
            $paramClass = $io->prompt('Class does not exists, please enter the form parameter full class name', null);
249
        }
250
251
        $this->paramClass = $paramClass;
252
253
        $validatorClass = $io->prompt('Enter the form validator full class name', null);
254
        while (!class_exists($validatorClass)) {
255
            $validatorClass = $io->prompt(
256
                'Class does not exists, please enter the form validator full class name',
257
                null
258
            );
259
        }
260
261
        $this->validatorClass = $validatorClass;
262
263
        $entityClass = $io->prompt('Enter the entity full class name', null);
264
        while (!class_exists($entityClass)) {
265
            $entityClass = $io->prompt('Class does not exists, please enter the entity full class name', null);
266
        }
267
268
        $this->entityClass = $entityClass;
269
270
        $repositoryClass = $io->prompt('Enter the repository full class name', null);
271
        while (!class_exists($repositoryClass)) {
272
            $repositoryClass = $io->prompt('Class does not exists, please enter the repository full class name', null);
273
        }
274
275
        $this->repositoryClass = $repositoryClass;
276
    }
277
278
    /**
279
     * Add new property
280
     * @param class-string $value
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string.
Loading history...
281
     * @param string|null $name
282
     * @return $this
283
     */
284
    protected function addProperty(string $value, ?string $name = null): self
285
    {
286
        $shortClass = $this->getClassBaseName($value);
287
        if ($name === null) {
288
            $name = Str::camel($shortClass, true);
289
        }
290
291
        //replace"interface", "abstract"
292
        $nameClean = str_ireplace(['interface', 'abstract'], '', $name);
293
294
        $this->properties[$value] = [
295
            'name' => $nameClean,
296
            'short' => $shortClass,
297
        ];
298
299
        return $this;
300
    }
301
302
    /**
303
     * Return the property name
304
     * @param class-string $value
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string.
Loading history...
305
     * @return string
306
     */
307
    protected function getPropertyName(string $value): string
308
    {
309
        if (!isset($this->properties[$value])) {
310
            return '';
311
        }
312
313
        return $this->properties[$value]['name'];
314
    }
315
316
317
    /**
318
     * Return the route prefix
319
     * @return string
320
     */
321
    protected function getTemplatePrefix(): string
322
    {
323
        $templatePrefix = $this->getOptionValue('templatePrefix');
324
        if ($templatePrefix === null) {
325
            $actionName = $this->getShortClassName($this->className);
326
            $templatePrefix = Str::snake(str_ireplace('action', '', $actionName));
0 ignored issues
show
Bug introduced by
It seems like str_ireplace('action', '', $actionName) can also be of type array; however, parameter $value of Platine\Stdlib\Helper\Str::snake() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

326
            $templatePrefix = Str::snake(/** @scrutinizer ignore-type */ str_ireplace('action', '', $actionName));
Loading history...
327
        }
328
329
        return $templatePrefix;
330
    }
331
332
    /**
333
     * Return the entity context key
334
     * @param bool $isKey
335
     * @return string
336
     */
337
    protected function getEntityContextKey(bool $isKey = true): string
338
    {
339
        $key = (string) $this->getOptionValue('entityContextKey');
340
        if (!empty($key)) {
341
            if ($isKey) {
342
                $key = Str::snake($key, '_');
343
            } else {
344
                $key = Str::camel($key, true);
345
            }
346
        }
347
348
        return $key;
349
    }
350
351
    /**
352
     * Return the route prefix
353
     * @return string
354
     */
355
    protected function getRoutePrefix(): string
356
    {
357
        $routePrefix = $this->getOptionValue('routePrefix');
358
        if ($routePrefix === null) {
359
            $actionName = $this->getShortClassName($this->className);
360
            $routePrefix = Str::snake(str_ireplace('action', '', $actionName));
0 ignored issues
show
Bug introduced by
It seems like str_ireplace('action', '', $actionName) can also be of type array; however, parameter $value of Platine\Stdlib\Helper\Str::snake() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

360
            $routePrefix = Str::snake(/** @scrutinizer ignore-type */ str_ireplace('action', '', $actionName));
Loading history...
361
        }
362
363
        return $routePrefix;
364
    }
365
366
    /**
367
     * Return the route name
368
     * @param string $value
369
     * @return string
370
     */
371
    protected function getRouteName(string $value): string
372
    {
373
        $routePrefix = $this->getRoutePrefix();
374
        return sprintf('%s_%s', $routePrefix, $value);
375
    }
376
377
    /**
378
     * Return the form parameter method name of the given name
379
     * @param string $field
380
     * @return string
381
     */
382
    protected function getFormParamMethodName(string $field): string
383
    {
384
        return sprintf('get%s', Str::camel($field, false));
385
    }
386
387
    /**
388
     * Return the message
389
     * @param string $option
390
     * @return string|null
391
     */
392
    protected function getMessage(string $option): ?string
393
    {
394
        $message = (string) $this->getOptionValue($option);
395
        if (!empty($message)) {
396
            $message = addslashes($message);
397
        }
398
399
        return $message;
400
    }
401
402
    /**
403
     * Return the template for form parameter entity field
404
     * @param string $field
405
     * @param string $param
406
     * @param bool $isLast
407
     * @return string
408
     */
409
    protected function getFormParamEntityFieldTemplate(
410
        string $field,
411
        string $param,
412
        bool $isLast = false
413
    ): string {
414
        $fieldMethodName = $this->getFormParamMethodName($param);
415
        return sprintf('\'%s\' => $formParam->%s(),', $field, $fieldMethodName) . ($isLast ? PHP_EOL : '');
416
    }
417
418
    /**
419
     * Format option fields
420
     * @param string $values
421
     * @return array<string|int, string>
422
     */
423
    protected function formatFields(string $values): array
424
    {
425
        $result = [];
426
        $fields = (array) explode(',', $values);
427
        foreach ($fields as $field) {
428
            $column = $field;
429
            $param = $field;
430
            $value = (array) explode(':', $field);
431
            if (isset($value[0])) {
432
                $column = $value[0];
433
            }
434
435
            if (isset($value[1])) {
436
                $param = $value[1];
437
            }
438
439
            $result[$column] = $param;
440
        }
441
442
        return $result;
443
    }
444
445
    /**
446
     * Format fields
447
     * @param array<string, string> $values
448
     * @param bool $orderField
449
     * @return string
450
     */
451
    protected function formatFieldStr(array $fields, bool $orderField = false): string
452
    {
453
        $result = '';
454
        foreach ($fields as $field => $param) {
455
            if ($orderField) {
456
                $order = 'ASC';
457
                if ($param === 'DESC') {
458
                    $order = 'DESC';
459
                }
460
461
                if ($order === 'ASC') {
462
                    $result .= sprintf('\'%s\', ', $field);
463
                } else {
464
                    $result .= sprintf('\'%s\' => \'DESC\', ', $field);
465
                }
466
            } else {
467
                if ($field === $param) {
468
                    $result .= sprintf('\'%s\', ', $field);
469
                } else {
470
                    $result .= sprintf('\'%s\' => \'%s\', ', $field, $param);
471
                }
472
            }
473
        }
474
475
        return rtrim($result, ', ');
476
    }
477
478
    /**
479
     * Load JSON configuration file if exist
480
     * @return void
481
     */
482
    protected function loadConfig(): void
483
    {
484
        $filename = $this->getOptionValue('config');
485
        if (!empty($filename)) {
486
            $file = $this->filesystem->file($filename);
487
            if ($file->exists() && $file->isReadable()) {
488
                $content = $file->read();
489
                /** @var array<string, string> $config */
490
                $config = Json::decode($content, true);
491
                foreach ($config as $option => $value) {
492
                    $optionKey = Str::camel($option, true);
493
                    $this->values[$optionKey] = $value;
494
                }
495
            }
496
        }
497
    }
498
}
499