Passed
Push — develop ( eb4ec0...91df1a )
by nguereza
02:57
created

getEntityFieldsTemplate()   A

Complexity

Conditions 6
Paths 2

Size

Total Lines 27
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 6
eloc 17
c 1
b 0
f 0
nc 2
nop 1
dl 0
loc 27
rs 9.0777
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 MakeResourceActionCommand.php
34
 *
35
 *  The Command to generate new resource action class
36
 *
37
 *  @package    Platine\Framework\Console\Command
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\Command;
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\Framework\Helper\Flash;
56
use Platine\Framework\Http\RouteHelper;
57
use Platine\Lang\Lang;
58
use Platine\Logger\LoggerInterface;
59
use Platine\Pagination\Pagination;
60
use Platine\Stdlib\Helper\Json;
61
use Platine\Stdlib\Helper\Str;
62
use Platine\Template\Template;
63
64
/**
65
 * @class MakeResourceActionCommand
66
 * @package Platine\Framework\Console\Command
67
 */
68
class MakeResourceActionCommand extends MakeCommand
69
{
70
    /**
71
     * {@inheritdoc}
72
     */
73
    protected string $type = 'resource';
74
75
    /**
76
     * The form parameter class name
77
     * @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...
78
     */
79
    protected string $paramClass;
80
81
    /**
82
     * The form validator class name
83
     * @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...
84
     */
85
    protected string $validatorClass;
86
87
    /**
88
     * The entity class name
89
     * @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...
90
     */
91
    protected string $entityClass;
92
93
    /**
94
     * The repository class name
95
     * @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...
96
     */
97
    protected string $repositoryClass;
98
99
    /**
100
     * Create new instance
101
     * @param Application $application
102
     * @param Filesystem $filesystem
103
     */
104
    public function __construct(
105
        Application $application,
106
        Filesystem $filesystem
107
    ) {
108
        parent::__construct($application, $filesystem);
109
        $this->setName('make:resource')
110
              ->setDescription('Command to generate platine resource action');
111
112
        $this->addOption(
113
            '-c|--fields',
114
            'The entity fields. Example field1:param1,field2:param2,field3',
115
            null,
116
            false
117
        );
118
119
        $this->addOption(
120
            '-i|--fields-unique',
121
            'The entity unique fields. Example field1:param1,field2:param2,field3',
122
            null,
123
            false
124
        );
125
126
        $this->addOption(
127
            '-o|--fields-order',
128
            'The entity orders fields. Example field1:ASC,field2:DESC,field3',
129
            null,
130
            false
131
        );
132
133
        $this->addOption(
134
            '-t|--template-prefix',
135
            'The template prefix',
136
            null,
137
            false
138
        );
139
140
        $this->addOption(
141
            '-r|--route-prefix',
142
            'The route name prefix',
143
            null,
144
            false
145
        );
146
147
        $this->addOption(
148
            '-e|--message-not-found',
149
            'The entity not found error message',
150
            'This record doesn\'t exist',
151
            false
152
        );
153
154
        $this->addOption(
155
            '-l|--message-duplicate',
156
            'The entity duplicate error message',
157
            'This record already exist',
158
            false
159
        );
160
161
        $this->addOption(
162
            '-a|--message-create',
163
            'The entity successfully create message',
164
            'Data successfully created',
165
            false
166
        );
167
168
        $this->addOption(
169
            '-u|--message-update',
170
            'The entity successfully update message',
171
            'Data successfully updated',
172
            false
173
        );
174
175
        $this->addOption(
176
            '-d|--message-delete',
177
            'The entity successfully delete message',
178
            'Data successfully deleted',
179
            false
180
        );
181
182
        $this->addOption(
183
            '-p|--message-process-error',
184
            'The entity processing error message',
185
            'Data processing error',
186
            false
187
        );
188
189
        $this->addOption(
190
            '-j|--config',
191
            'Use JSON config file for options',
192
            null,
193
            false
194
        );
195
196
        $this->addOption(
197
            '-b|--entity-context-key',
198
            'The entity context key name',
199
            'entity',
200
            false
201
        );
202
    }
203
204
    /**
205
     * {@inheritdoc}
206
     */
207
    public function interact(Reader $reader, Writer $writer): void
208
    {
209
        parent::interact($reader, $writer);
210
211
        // Load configuration file if exist
212
        $this->loadConfig();
213
214
        $baseClasses = $this->getBaseClasses();
215
216
        foreach ($baseClasses as $value) {
217
            $this->addProperty($value);
218
        }
219
220
        $this->recordResourceClasses();
221
222
        $this->recordProperties();
223
224
        $this->addProperty($this->repositoryClass);
225
    }
226
227
     /**
228
     * {@inheritdoc}
229
     */
230
    public function getClassTemplate(): string
231
    {
232
        return <<<EOF
233
        <?php
234
        
235
        declare(strict_types=1);
236
        
237
        namespace %namespace%;
238
        
239
        use Exception;
240
        use Platine\Http\ResponseInterface;
241
        use Platine\Http\ServerRequestInterface;
242
        use Platine\Framework\Http\RequestData;
243
        use Platine\Framework\Http\Response\TemplateResponse;
244
        use Platine\Framework\Http\Response\RedirectResponse;
245
        %uses%
246
247
        /**
248
        * @class %classname%
249
        * @package %namespace%
250
        */
251
        class %classname%
252
        {
253
            
254
            %properties%
255
        
256
            %constructor%
257
        
258
            /**
259
            * List all entities
260
            * @param ServerRequestInterface \$request
261
            * @return ResponseInterface
262
            */
263
            public function index(ServerRequestInterface \$request): ResponseInterface
264
            {
265
                %method_body_index%
266
            }
267
        
268
            /**
269
            * List entity detail
270
            * @param ServerRequestInterface \$request
271
            * @return ResponseInterface
272
            */
273
            public function detail(ServerRequestInterface \$request): ResponseInterface
274
            {
275
                %method_body_detail%
276
            }
277
        
278
            /**
279
            * Create new entity
280
            * @param ServerRequestInterface \$request
281
            * @return ResponseInterface
282
            */
283
            public function create(ServerRequestInterface \$request): ResponseInterface
284
            {
285
                %method_body_create%
286
            }
287
        
288
            /**
289
            * Update existing entity
290
            * @param ServerRequestInterface \$request
291
            * @return ResponseInterface
292
            */
293
            public function update(ServerRequestInterface \$request): ResponseInterface
294
            {
295
                %method_body_update%
296
            }
297
        
298
            /**
299
            * Delete the entity
300
            * @param ServerRequestInterface \$request
301
            * @return ResponseInterface
302
            */
303
            public function delete(ServerRequestInterface \$request): ResponseInterface
304
            {
305
                %method_body_delete%
306
            }
307
        }
308
        
309
        EOF;
310
    }
311
312
    /**
313
     * Record class properties
314
     * @return void
315
     */
316
    protected function recordProperties(): void
317
    {
318
        $io = $this->io();
319
320
        $writer = $io->writer();
321
322
        $writer->boldYellow('Enter the properties list (empty value to finish):', true);
323
        $value = '';
324
        while ($value !== null) {
325
            $value = $io->prompt('Property full class name', null, null, false);
326
327
            if (!empty($value)) {
328
                $value = trim($value);
329
                if (!class_exists($value) && !interface_exists($value)) {
330
                    $writer->boldWhiteBgRed(sprintf('The class [%s] does not exists', $value), true);
331
                } else {
332
                    $shortClass = $this->getClassBaseName($value);
333
                    $name = Str::camel($shortClass, true);
334
                    //replace"interface", "abstract"
335
                    $nameClean = str_ireplace(['interface', 'abstract'], '', $name);
336
337
                    $this->properties[$value] = [
338
                        'name' => $nameClean,
339
                        'short' => $shortClass,
340
                    ];
341
                }
342
            }
343
        }
344
    }
345
346
    /**
347
     * Record the resource classes
348
     * @return void
349
     */
350
    protected function recordResourceClasses(): void
351
    {
352
        $io = $this->io();
353
354
        $paramClass = $io->prompt('Enter the form parameter full class name', null);
355
        while (!class_exists($paramClass)) {
356
            $paramClass = $io->prompt('Class does not exists, please enter the form parameter full class name', null);
357
        }
358
359
        $this->paramClass = $paramClass;
360
361
        $validatorClass = $io->prompt('Enter the form validator full class name', null);
362
        while (!class_exists($validatorClass)) {
363
            $validatorClass = $io->prompt(
364
                'Class does not exists, please enter the form validator full class name',
365
                null
366
            );
367
        }
368
369
        $this->validatorClass = $validatorClass;
370
371
        $entityClass = $io->prompt('Enter the entity full class name', null);
372
        while (!class_exists($entityClass)) {
373
            $entityClass = $io->prompt('Class does not exists, please enter the entity full class name', null);
374
        }
375
376
        $this->entityClass = $entityClass;
377
378
        $repositoryClass = $io->prompt('Enter the repository full class name', null);
379
        while (!class_exists($repositoryClass)) {
380
            $repositoryClass = $io->prompt('Class does not exists, please enter the repository full class name', null);
381
        }
382
383
        $this->repositoryClass = $repositoryClass;
384
    }
385
386
    /**
387
     * {@inheritdoc}
388
     */
389
    protected function createClass(): string
390
    {
391
        $content = parent::createClass();
392
393
394
        $contentIndex = $this->getIndexMethodBody($content);
395
        $contentDetail = $this->getDetailMethodBody($contentIndex);
396
        $contentCreate = $this->getCreateMethodBody($contentDetail);
397
        $contentUpdate = $this->getUpdateMethodBody($contentCreate);
398
        $contentDelete = $this->getDeleteMethodBody($contentUpdate);
399
400
        return $contentDelete;
401
    }
402
403
    /**
404
     * Return the index method body
405
     * @param string $content
406
     * @return string
407
     */
408
    protected function getIndexMethodBody(string $content): string
409
    {
410
        $repositoryName = $this->getPropertyName($this->repositoryClass);
411
        $templatePrefix = $this->getTemplatePrefix();
412
413
        $orderByTemplate = $this->getOrderByTemplate();
414
415
        $result = <<<EOF
416
        \$context = [];
417
                \$param = new RequestData(\$request);
418
                \$totalItems = \$this->{$repositoryName}->query()
419
                                                       ->count('id');
420
421
                \$currentPage = (int) \$param->get('page', 1);
422
423
                \$this->pagination->setTotalItems(\$totalItems)
424
                                ->setCurrentPage(\$currentPage);
425
426
                \$limit = \$this->pagination->getItemsPerPage();
427
                \$offset = \$this->pagination->getOffset();
428
429
                \$results = \$this->{$repositoryName}->query()
430
                                                    ->offset(\$offset)
431
                                                    ->limit(\$limit)
432
                                                    $orderByTemplate
433
                                                    ->all();
434
                
435
                \$context['list'] = \$results;
436
                \$context['pagination'] = \$this->pagination->render();
437
438
439
                return new TemplateResponse(
440
                    \$this->template,
441
                    '$templatePrefix/list',
442
                    \$context
443
                );
444
        EOF;
445
446
        return str_replace('%method_body_index%', $result, $content);
447
    }
448
449
    /**
450
     * Return the detail method body
451
     * @param string $content
452
     * @return string
453
     */
454
    protected function getDetailMethodBody(string $content): string
455
    {
456
        $repositoryName = $this->getPropertyName($this->repositoryClass);
457
        $entityBaseClass = $this->getClassBaseName($this->entityClass);
458
        $templatePrefix = $this->getTemplatePrefix();
459
        $notFoundMessage = $this->getMessage('messageNotFound');
460
461
        $listRoute = $this->getRouteName('list');
462
463
        $entityContextKey = $this->getEntityContextKey(true);
464
        $entityContextName = $this->getEntityContextKey(false);
465
466
        $result = <<<EOF
467
        \$context = [];
468
                \$id = (int) \$request->getAttribute('id');
469
470
                /** @var $entityBaseClass|null \$$entityContextName */
471
                \$$entityContextName = \$this->{$repositoryName}->find(\$id);
472
473
                if (\$$entityContextName === null) {
474
                    \$this->flash->setError(\$this->lang->tr('$notFoundMessage'));
475
476
                    return new RedirectResponse(
477
                        \$this->routeHelper->generateUrl('$listRoute')
478
                    );
479
                }
480
                \$context['$entityContextKey'] = \$$entityContextName;
481
                        
482
                return new TemplateResponse(
483
                    \$this->template,
484
                    '$templatePrefix/detail',
485
                    \$context
486
                );
487
        EOF;
488
489
490
        return str_replace('%method_body_detail%', $result, $content);
491
    }
492
493
    /**
494
     * Return the create method body
495
     * @param string $content
496
     * @return string
497
     */
498
    protected function getCreateMethodBody(string $content): string
499
    {
500
        $repositoryName = $this->getPropertyName($this->repositoryClass);
501
        $formParamBaseClass = $this->getClassBaseName($this->paramClass);
502
        $validatorBaseClass = $this->getClassBaseName($this->validatorClass);
503
        $entityBaseClass = $this->getClassBaseName($this->entityClass);
504
        $templatePrefix = $this->getTemplatePrefix();
505
        $listRoute = $this->getRouteName('list');
506
        $createMessage = $this->getMessage('messageCreate');
507
        $processErrorMessage = $this->getMessage('messageProcessError');
508
509
        $uniqueCheckStr = $this->getUniqueFieldCheckTemplate(true);
510
        $fieldTemplates = $this->getEntityFieldsTemplate(true);
511
512
        $entityContextName = $this->getEntityContextKey(false);
513
514
        $result = <<<EOF
515
        \$context = [];
516
                \$param = new RequestData(\$request);
517
                
518
                \$formParam = new $formParamBaseClass(\$param->posts());
519
                \$context['param'] = \$formParam;
520
                
521
                if (\$request->getMethod() === 'GET') {
522
                    return new TemplateResponse(
523
                        \$this->template,
524
                        '$templatePrefix/create',
525
                        \$context
526
                    );
527
                }
528
                
529
                \$validator = new $validatorBaseClass(\$formParam, \$this->lang);
530
                if (\$validator->validate() === false) {
531
                    \$context['errors'] = \$validator->getErrors();
532
533
                    return new TemplateResponse(
534
                        \$this->template,
535
                        '$templatePrefix/create',
536
                        \$context
537
                    );
538
                }
539
                
540
                $uniqueCheckStr
541
542
                /** @var $entityBaseClass \$$entityContextName */
543
                \$$entityContextName = \$this->{$repositoryName}->create([
544
                   $fieldTemplates
545
                ]);
546
                
547
                try {
548
                    \$this->{$repositoryName}->save(\$$entityContextName);
549
550
                    \$this->flash->setSuccess(\$this->lang->tr('$createMessage'));
551
552
                    return new RedirectResponse(
553
                        \$this->routeHelper->generateUrl('$listRoute')
554
                    );
555
                } catch (Exception \$ex) {
556
                    \$this->logger->error('Error when saved the data {error}', ['error' => \$ex->getMessage()]);
557
558
                    \$this->flash->setError(\$this->lang->tr('$processErrorMessage'));
559
560
                    return new TemplateResponse(
561
                        \$this->template,
562
                        '$templatePrefix/create',
563
                        \$context
564
                    );
565
                }
566
        EOF;
567
568
569
        return str_replace('%method_body_create%', $result, $content);
570
    }
571
572
    /**
573
     * Return the update method body
574
     * @param string $content
575
     * @return string
576
     */
577
    protected function getUpdateMethodBody(string $content): string
578
    {
579
        $repositoryName = $this->getPropertyName($this->repositoryClass);
580
        $formParamBaseClass = $this->getClassBaseName($this->paramClass);
581
        $validatorBaseClass = $this->getClassBaseName($this->validatorClass);
582
        $entityBaseClass = $this->getClassBaseName($this->entityClass);
583
        $templatePrefix = $this->getTemplatePrefix();
584
        $listRoute = $this->getRouteName('list');
585
        $detailRoute = $this->getRouteName('detail');
586
        $notFoundMessage = $this->getMessage('messageNotFound');
587
        $updateMessage = $this->getMessage('messageUpdate');
588
        $processErrorMessage = $this->getMessage('messageProcessError');
589
590
        $uniqueCheckStr = $this->getUniqueFieldCheckTemplate(false);
591
        $fieldTemplates = $this->getEntityFieldsTemplate(false);
592
593
        $entityContextKey = $this->getEntityContextKey(true);
594
        $entityContextName = $this->getEntityContextKey(false);
595
596
        $result = <<<EOF
597
        \$context = [];
598
                \$param = new RequestData(\$request);
599
                
600
                \$id = (int) \$request->getAttribute('id');
601
602
                /** @var $entityBaseClass|null \$$entityContextName */
603
                \$$entityContextName = \$this->{$repositoryName}->find(\$id);
604
605
                if (\$$entityContextName === null) {
606
                    \$this->flash->setError(\$this->lang->tr('$notFoundMessage'));
607
608
                    return new RedirectResponse(
609
                        \$this->routeHelper->generateUrl('$listRoute')
610
                    );
611
                }
612
                \$context['$entityContextKey'] = \$$entityContextName;
613
                \$context['param'] = (new $formParamBaseClass())->fromEntity(\$$entityContextName);
614
                if (\$request->getMethod() === 'GET') {
615
                    return new TemplateResponse(
616
                        \$this->template,
617
                        '$templatePrefix/update',
618
                        \$context
619
                    );
620
                }
621
                \$formParam = new $formParamBaseClass(\$param->posts());
622
                \$context['param'] = \$formParam;
623
                
624
                \$validator = new $validatorBaseClass(\$formParam, \$this->lang);
625
                if (\$validator->validate() === false) {
626
                    \$context['errors'] = \$validator->getErrors();
627
628
                    return new TemplateResponse(
629
                        \$this->template,
630
                        '$templatePrefix/update',
631
                        \$context
632
                    );
633
                }
634
                
635
                $uniqueCheckStr
636
637
                $fieldTemplates
638
                
639
                try {
640
                    \$this->{$repositoryName}->save(\$$entityContextName);
641
642
                    \$this->flash->setSuccess(\$this->lang->tr('$updateMessage'));
643
644
                    return new RedirectResponse(
645
                        \$this->routeHelper->generateUrl('$detailRoute', ['id' => \$id])
646
                    );
647
                } catch (Exception \$ex) {
648
                    \$this->logger->error('Error when saved the data {error}', ['error' => \$ex->getMessage()]);
649
650
                    \$this->flash->setError(\$this->lang->tr('$processErrorMessage'));
651
652
                    return new TemplateResponse(
653
                        \$this->template,
654
                        '$templatePrefix/update',
655
                        \$context
656
                    );
657
                }
658
        EOF;
659
660
661
        return str_replace('%method_body_update%', $result, $content);
662
    }
663
664
    /**
665
     * Return the delete method body
666
     * @param string $content
667
     * @return string
668
     */
669
    protected function getDeleteMethodBody(string $content): string
670
    {
671
        $repositoryName = $this->getPropertyName($this->repositoryClass);
672
        $entityBaseClass = $this->getClassBaseName($this->entityClass);
673
        $notFoundMessage = $this->getMessage('messageNotFound');
674
        $deleteMessage = $this->getMessage('messageDelete');
675
        $processErrorMessage = $this->getMessage('messageProcessError');
676
677
        $listRoute = $this->getRouteName('list');
678
679
        $entityContextName = $this->getEntityContextKey(false);
680
681
        $result = <<<EOF
682
        \$id = (int) \$request->getAttribute('id');
683
684
                /** @var $entityBaseClass|null \$$entityContextName */
685
                \$$entityContextName = \$this->{$repositoryName}->find(\$id);
686
687
                if (\$$entityContextName === null) {
688
                    \$this->flash->setError(\$this->lang->tr('$notFoundMessage'));
689
690
                    return new RedirectResponse(
691
                        \$this->routeHelper->generateUrl('$listRoute')
692
                    );
693
                }
694
695
                try {
696
                    \$this->{$repositoryName}->delete(\$$entityContextName);
697
698
                    \$this->flash->setSuccess(\$this->lang->tr('$deleteMessage'));
699
700
                    return new RedirectResponse(
701
                        \$this->routeHelper->generateUrl('$listRoute')
702
                    );
703
                } catch (Exception \$ex) {
704
                    \$this->logger->error('Error when delete the data {error}', ['error' => \$ex->getMessage()]);
705
706
                    \$this->flash->setError(\$this->lang->tr('$processErrorMessage'));
707
708
                    return new RedirectResponse(
709
                        \$this->routeHelper->generateUrl('$listRoute')
710
                    );
711
                }
712
        EOF;
713
714
715
        return str_replace('%method_body_delete%', $result, $content);
716
    }
717
718
    /**
719
     * Return the template for unique field check
720
     * @param bool $create
721
     * @return string
722
     */
723
    protected function getUniqueFieldCheckTemplate(bool $create = true): string
724
    {
725
        $repositoryName = $this->getPropertyName($this->repositoryClass);
726
        $templatePrefix = $this->getTemplatePrefix();
727
        $uniqueFields = $this->getOptionValue('fieldsUnique');
728
        $uniqueCheckStr = '';
729
        if ($uniqueFields !== null) {
730
            $duplicateMessage = $this->getMessage('messageDuplicate');
731
732
            $fields = (array) explode(',', $uniqueFields);
733
            $i = 1;
734
            $result = '';
735
            foreach ($fields as $field) {
736
                $column = $field;
737
                $param = $field;
738
                $uniqueField = (array) explode(':', $field);
739
                if (isset($uniqueField[0])) {
740
                    $column = $uniqueField[0];
741
                }
742
743
                if (isset($uniqueField[1])) {
744
                    $param = $uniqueField[1];
745
                }
746
747
                $result .= ($i > 1 ? "\t\t\t\t\t       " : '') .
748
                        $this->getFormParamEntityFieldTemplate($column, $param, count($fields) > $i);
749
                $i++;
750
            }
751
752
            $updateStr = $create ? '' : ' && $entityExist->id !== $id';
753
            $templateName = $create ? 'create' : 'update';
754
755
            $uniqueCheckStr = <<<EOF
756
            \$entityExist = \$this->{$repositoryName}->findBy([
757
                                                           $result
758
                                                       ]);
759
                    
760
                    if(\$entityExist !== null$updateStr){
761
                        \$this->flash->setError(\$this->lang->tr('$duplicateMessage'));
762
763
                        return new TemplateResponse(
764
                            \$this->template,
765
                            '$templatePrefix/$templateName',
766
                            \$context
767
                        );
768
                    }
769
            EOF;
770
        }
771
772
        return $uniqueCheckStr;
773
    }
774
775
    /**
776
     * Return the template for order by
777
     * @return string
778
     */
779
    protected function getOrderByTemplate(): string
780
    {
781
        $result = '';
782
        $orderFields = $this->getOptionValue('fieldsOrder');
783
784
        if ($orderFields !== null) {
785
            $fields = (array) explode(',', $orderFields);
786
            $i = 1;
787
            foreach ($fields as $field) {
788
                $column = $field;
789
                $dir = 'ASC';
790
                $orderField = (array) explode(':', $field);
791
                if (isset($orderField[0])) {
792
                    $column = $orderField[0];
793
                }
794
795
                if (isset($orderField[1]) && in_array(strtolower($orderField[1]), ['asc', 'desc'])) {
796
                    $dir = $orderField[1];
797
                }
798
799
                $result .= ($i > 1 ? "\t\t\t\t\t    " : '') .
800
                        sprintf('->orderBy(\'%s\', \'%s\')', $column, Str::upper($dir)) .
801
                        (count($fields) > $i ? PHP_EOL : '');
802
                $i++;
803
            }
804
        }
805
806
        return $result;
807
    }
808
809
    /**
810
     * Return the template for entity field for saving
811
     * @param bool $create
812
     * @return string
813
     */
814
    protected function getEntityFieldsTemplate(bool $create = true): string
815
    {
816
        $fields = $this->getOptionValue('fields');
817
        $result = '';
818
        if ($fields !== null) {
819
            $fields = (array) explode(',', $fields);
820
            $i = 1;
821
822
            foreach ($fields as $field) {
823
                $column = $field;
824
                $param = $field;
825
                $entityField = (array) explode(':', $field);
826
                if (isset($entityField[0])) {
827
                    $column = $entityField[0];
828
                }
829
830
                if (isset($entityField[1])) {
831
                    $param = $entityField[1];
832
                }
833
834
                $result .= ($i > 1 ? "\t   " : '') .
835
                        $this->getEntityRecordFieldTemplate($column, $param, count($fields) > $i, $create);
836
                $i++;
837
            }
838
        }
839
840
        return $result;
841
    }
842
843
    /**
844
     * {@inheritdoc}
845
     */
846
    protected function getUsesContent(): string
847
    {
848
        $uses = parent::getUsesContent();
849
850
        $uses .= $this->getUsesTemplate($this->entityClass);
851
        $uses .= $this->getUsesTemplate($this->paramClass);
852
        $uses .= $this->getUsesTemplate($this->validatorClass);
853
854
        return <<<EOF
855
        $uses
856
        EOF;
857
    }
858
859
    /**
860
     * Add new property
861
     * @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...
862
     * @return $this
863
     */
864
    protected function addProperty(string $value): self
865
    {
866
        $shortClass = $this->getClassBaseName($value);
867
        $name = Str::camel($shortClass, true);
868
        //replace"interface", "abstract"
869
        $nameClean = str_ireplace(['interface', 'abstract'], '', $name);
870
871
        $this->properties[$value] = [
872
            'name' => $nameClean,
873
            'short' => $shortClass,
874
        ];
875
876
        return $this;
877
    }
878
879
    /**
880
     * Return the property name
881
     * @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...
882
     * @return string
883
     */
884
    protected function getPropertyName(string $value): string
885
    {
886
        if (!isset($this->properties[$value])) {
887
            return '';
888
        }
889
890
        return $this->properties[$value]['name'];
891
    }
892
893
894
    /**
895
     * Return the route prefix
896
     * @return string
897
     */
898
    protected function getTemplatePrefix(): string
899
    {
900
        $templatePrefix = $this->getOptionValue('templatePrefix');
901
        if ($templatePrefix === null) {
902
            $actionName = $this->getShortClassName($this->className);
903
            $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

903
            $templatePrefix = Str::snake(/** @scrutinizer ignore-type */ str_ireplace('action', '', $actionName));
Loading history...
904
        }
905
906
        return $templatePrefix;
907
    }
908
909
    /**
910
     * Return the entity context key
911
     * @param bool $isKey
912
     * @return string
913
     */
914
    protected function getEntityContextKey(bool $isKey = true): string
915
    {
916
        $key = (string) $this->getOptionValue('entityContextKey');
917
        if (!empty($key)) {
918
            if ($isKey) {
919
                $key = Str::snake($key, '_');
920
            } else {
921
                $key = Str::camel($key, true);
922
            }
923
        }
924
925
        return $key;
926
    }
927
928
    /**
929
     * Return the route prefix
930
     * @return string
931
     */
932
    protected function getRoutePrefix(): string
933
    {
934
        $routePrefix = $this->getOptionValue('routePrefix');
935
        if ($routePrefix === null) {
936
            $actionName = $this->getShortClassName($this->className);
937
            $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

937
            $routePrefix = Str::snake(/** @scrutinizer ignore-type */ str_ireplace('action', '', $actionName));
Loading history...
938
        }
939
940
        return $routePrefix;
941
    }
942
943
    /**
944
     * Return the route name
945
     * @param string $value
946
     * @return string
947
     */
948
    protected function getRouteName(string $value): string
949
    {
950
        $routePrefix = $this->getRoutePrefix();
951
        return sprintf('%s_%s', $routePrefix, $value);
952
    }
953
954
    /**
955
     * Return the form parameter method name of the given name
956
     * @param string $field
957
     * @return string
958
     */
959
    protected function getFormParamMethodName(string $field): string
960
    {
961
        return sprintf('get%s', Str::camel($field, false));
962
    }
963
964
    /**
965
     * Return the base classes
966
     * @return array<class-string>
0 ignored issues
show
Documentation Bug introduced by
The doc comment array<class-string> at position 2 could not be parsed: Unknown type name 'class-string' at position 2 in array<class-string>.
Loading history...
967
     */
968
    protected function getBaseClasses(): array
969
    {
970
        return [
971
            Lang::class,
972
            Pagination::class,
973
            Template::class,
974
            Flash::class,
975
            RouteHelper::class,
976
            LoggerInterface::class,
977
        ];
978
    }
979
980
    /**
981
     * Return the message
982
     * @param string $option
983
     * @return string|null
984
     */
985
    protected function getMessage(string $option): ?string
986
    {
987
        $message = (string) $this->getOptionValue($option);
988
        if (!empty($message)) {
989
            $message = addslashes($message);
990
        }
991
992
        return $message;
993
    }
994
995
    /**
996
     * Return the template for entity record fields
997
     * @param string $field
998
     * @param string $param
999
     * @param bool $isLast
1000
     * @param bool $create
1001
     * @return string
1002
     */
1003
    protected function getEntityRecordFieldTemplate(
1004
        string $field,
1005
        string $param,
1006
        bool $isLast = false,
1007
        $create = true
1008
    ): string {
1009
        $fieldMethodName = $this->getFormParamMethodName($param);
1010
        if ($create) {
1011
            return sprintf('\'%s\' => $formParam->%s(),', $field, $fieldMethodName) . ($isLast ? PHP_EOL : '');
1012
        }
1013
        $entityContextName = $this->getEntityContextKey(false);
1014
        return sprintf(
1015
            '$%s->%s = $formParam->%s();',
1016
            $entityContextName,
1017
            $field,
1018
            $fieldMethodName
1019
        ) . ($isLast ? PHP_EOL : '');
1020
    }
1021
1022
    /**
1023
     * Return the template for form parameter entity field
1024
     * @param string $field
1025
     * @param string $param
1026
     * @param bool $isLast
1027
     * @return string
1028
     */
1029
    protected function getFormParamEntityFieldTemplate(
1030
        string $field,
1031
        string $param,
1032
        bool $isLast = false
1033
    ): string {
1034
        $fieldMethodName = $this->getFormParamMethodName($param);
1035
        return sprintf('\'%s\' => $formParam->%s(),', $field, $fieldMethodName) . ($isLast ? PHP_EOL : '');
1036
    }
1037
1038
    /**
1039
     * Load JSON configuration file if exist
1040
     * @return void
1041
     */
1042
    protected function loadConfig(): void
1043
    {
1044
        $filename = $this->getOptionValue('config');
1045
        if (!empty($filename)) {
1046
            $file = $this->filesystem->file($filename);
1047
            if ($file->exists() && $file->isReadable()) {
1048
                $content = $file->read();
1049
                /** @var array<string, string> $config */
1050
                $config = Json::decode($content, true);
1051
                foreach ($config as $option => $value) {
1052
                    $optionKey = Str::camel($option, true);
1053
                    $this->values[$optionKey] = $value;
1054
                }
1055
            }
1056
        }
1057
    }
1058
}
1059