MakeResourceActionCommand::__construct()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 4
Bugs 0 Features 0
Metric Value
cc 1
eloc 3
c 4
b 0
f 0
nc 1
nop 2
dl 0
loc 8
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 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\BaseMakeActionCommand;
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\Str;
61
use Platine\Template\Template;
62
63
/**
64
 * @class MakeResourceActionCommand
65
 * @package Platine\Framework\Console\Command
66
 */
67
class MakeResourceActionCommand extends BaseMakeActionCommand
68
{
69
    /**
70
     * {@inheritdoc}
71
     */
72
    protected string $type = 'resource';
73
74
    /**
75
     * Create new instance
76
     * @param Application $application
77
     * @param Filesystem $filesystem
78
     */
79
    public function __construct(
80
        Application $application,
81
        Filesystem $filesystem
82
    ) {
83
        parent::__construct($application, $filesystem);
84
85
        $this->setName('make:resource')
86
              ->setDescription('Command to generate resource action');
87
    }
88
89
    /**
90
     * {@inheritdoc}
91
     */
92
    public function interact(Reader $reader, Writer $writer): void
93
    {
94
        parent::interact($reader, $writer);
95
        $baseClasses = $this->getBaseClasses();
96
97
        foreach ($baseClasses as $value) {
98
            $this->addProperty($value);
99
        }
100
101
        $this->recordProperties();
102
        $this->addProperty($this->repositoryClass);
103
    }
104
105
     /**
106
     * {@inheritdoc}
107
     */
108
    public function getClassTemplate(): string
109
    {
110
        return <<<EOF
111
        <?php
112
        
113
        declare(strict_types=1);
114
        
115
        namespace %namespace%;
116
        
117
        use Exception;
118
        use Platine\Http\ResponseInterface;
119
        use Platine\Http\ServerRequestInterface;
120
        use Platine\Framework\Http\RequestData;
121
        use Platine\Framework\Http\Response\TemplateResponse;
122
        use Platine\Framework\Http\Response\RedirectResponse;
123
        %uses%
124
125
        /**
126
        * @class %classname%
127
        * @package %namespace%
128
        */
129
        class %classname%
130
        {
131
            %properties%
132
            %constructor%
133
        
134
            /**
135
            * List all entities
136
            * @param ServerRequestInterface \$request
137
            * @return ResponseInterface
138
            */
139
            public function index(ServerRequestInterface \$request): ResponseInterface
140
            {
141
                %method_body_index%
142
            }
143
        
144
            /**
145
            * List entity detail
146
            * @param ServerRequestInterface \$request
147
            * @return ResponseInterface
148
            */
149
            public function detail(ServerRequestInterface \$request): ResponseInterface
150
            {
151
                %method_body_detail%
152
            }
153
        
154
            /**
155
            * Create new entity
156
            * @param ServerRequestInterface \$request
157
            * @return ResponseInterface
158
            */
159
            public function create(ServerRequestInterface \$request): ResponseInterface
160
            {
161
                %method_body_create%
162
            }
163
        
164
            /**
165
            * Update existing entity
166
            * @param ServerRequestInterface \$request
167
            * @return ResponseInterface
168
            */
169
            public function update(ServerRequestInterface \$request): ResponseInterface
170
            {
171
                %method_body_update%
172
            }
173
        
174
            /**
175
            * Delete the entity
176
            * @param ServerRequestInterface \$request
177
            * @return ResponseInterface
178
            */
179
            public function delete(ServerRequestInterface \$request): ResponseInterface
180
            {
181
                %method_body_delete%
182
            }
183
        }
184
        
185
        EOF;
186
    }
187
188
    /**
189
     * {@inheritdoc}
190
     */
191
    protected function createClass(): string
192
    {
193
        $content = parent::createClass();
194
195
        $contentIndex = $this->getIndexMethodBody($content);
196
        $contentDetail = $this->getDetailMethodBody($contentIndex);
197
        $contentCreate = $this->getCreateMethodBody($contentDetail);
198
        $contentUpdate = $this->getUpdateMethodBody($contentCreate);
199
        $contentDelete = $this->getDeleteMethodBody($contentUpdate);
200
201
        return $contentDelete;
202
    }
203
204
    /**
205
     * Return the index method body
206
     * @param string $content
207
     * @return string
208
     */
209
    protected function getIndexMethodBody(string $content): string
210
    {
211
        $repositoryName = $this->getPropertyName($this->repositoryClass);
212
        $templatePrefix = $this->getTemplatePrefix();
213
        $orderByTemplate = $this->getOrderByTemplate();
214
215
        $result = <<<EOF
216
        \$context = [];
217
                \$param = new RequestData(\$request);
218
                \$totalItems = \$this->{$repositoryName}->query()
219
                                                       ->count('id');
220
221
                \$currentPage = (int) \$param->get('page', 1);
222
223
                \$this->pagination->setTotalItems(\$totalItems)
224
                                ->setCurrentPage(\$currentPage);
225
226
                \$limit = \$this->pagination->getItemsPerPage();
227
                \$offset = \$this->pagination->getOffset();
228
229
                \$results = \$this->{$repositoryName}->query()
230
                                                    ->offset(\$offset)
231
                                                    ->limit(\$limit)
232
                                                    $orderByTemplate
233
                                                    ->all();
234
                
235
                \$context['list'] = \$results;
236
                \$context['pagination'] = \$this->pagination->render();
237
238
239
                return new TemplateResponse(
240
                    \$this->template,
241
                    '$templatePrefix/list',
242
                    \$context
243
                );
244
        EOF;
245
246
        return str_replace('%method_body_index%', $result, $content);
247
    }
248
249
    /**
250
     * Return the detail method body
251
     * @param string $content
252
     * @return string
253
     */
254
    protected function getDetailMethodBody(string $content): string
255
    {
256
        $repositoryName = $this->getPropertyName($this->repositoryClass);
257
        $entityBaseClass = $this->getClassBaseName($this->entityClass);
258
        $templatePrefix = $this->getTemplatePrefix();
259
        $notFoundMessage = $this->getMessage('messageNotFound');
260
        $listRoute = $this->getRouteName('list');
261
        $entityContextKey = $this->getEntityContextKey(true);
262
        $entityContextName = $this->getEntityContextKey(false);
263
264
        $result = <<<EOF
265
        \$context = [];
266
                \$id = (int) \$request->getAttribute('id');
267
268
                /** @var $entityBaseClass|null \$$entityContextName */
269
                \$$entityContextName = \$this->{$repositoryName}->find(\$id);
270
271
                if (\$$entityContextName === null) {
272
                    \$this->flash->setError(\$this->lang->tr('$notFoundMessage'));
273
274
                    return new RedirectResponse(
275
                        \$this->routeHelper->generateUrl('$listRoute')
276
                    );
277
                }
278
                \$context['$entityContextKey'] = \$$entityContextName;
279
                        
280
                return new TemplateResponse(
281
                    \$this->template,
282
                    '$templatePrefix/detail',
283
                    \$context
284
                );
285
        EOF;
286
287
288
        return str_replace('%method_body_detail%', $result, $content);
289
    }
290
291
    /**
292
     * Return the create method body
293
     * @param string $content
294
     * @return string
295
     */
296
    protected function getCreateMethodBody(string $content): string
297
    {
298
        $repositoryName = $this->getPropertyName($this->repositoryClass);
299
        $formParamBaseClass = $this->getClassBaseName($this->paramClass);
300
        $validatorBaseClass = $this->getClassBaseName($this->validatorClass);
301
        $entityBaseClass = $this->getClassBaseName($this->entityClass);
302
        $templatePrefix = $this->getTemplatePrefix();
303
        $listRoute = $this->getRouteName('list');
304
        $createMessage = $this->getMessage('messageCreate');
305
        $processErrorMessage = $this->getMessage('messageProcessError');
306
        $uniqueCheckStr = $this->getUniqueFieldCheckTemplate(true);
307
        $fieldTemplates = $this->getEntityFieldsTemplate(true);
308
        $entityContextName = $this->getEntityContextKey(false);
309
310
        $result = <<<EOF
311
        \$context = [];
312
                \$param = new RequestData(\$request);
313
                
314
                \$formParam = new $formParamBaseClass(\$param->posts());
315
                \$context['param'] = \$formParam;
316
                
317
                if (\$request->getMethod() === 'GET') {
318
                    return new TemplateResponse(
319
                        \$this->template,
320
                        '$templatePrefix/create',
321
                        \$context
322
                    );
323
                }
324
                
325
                \$validator = new $validatorBaseClass(\$formParam, \$this->lang);
326
                if (\$validator->validate() === false) {
327
                    \$context['errors'] = \$validator->getErrors();
328
329
                    return new TemplateResponse(
330
                        \$this->template,
331
                        '$templatePrefix/create',
332
                        \$context
333
                    );
334
                }
335
                
336
                $uniqueCheckStr
337
338
                /** @var $entityBaseClass \$$entityContextName */
339
                \$$entityContextName = \$this->{$repositoryName}->create([
340
                   $fieldTemplates
341
                ]);
342
                
343
                try {
344
                    \$this->{$repositoryName}->save(\$$entityContextName);
345
346
                    \$this->flash->setSuccess(\$this->lang->tr('$createMessage'));
347
348
                    return new RedirectResponse(
349
                        \$this->routeHelper->generateUrl('$listRoute')
350
                    );
351
                } catch (Exception \$ex) {
352
                    \$this->logger->error('Error when saved the data {error}', ['error' => \$ex->getMessage()]);
353
354
                    \$this->flash->setError(\$this->lang->tr('$processErrorMessage'));
355
356
                    return new TemplateResponse(
357
                        \$this->template,
358
                        '$templatePrefix/create',
359
                        \$context
360
                    );
361
                }
362
        EOF;
363
364
365
        return str_replace('%method_body_create%', $result, $content);
366
    }
367
368
    /**
369
     * Return the update method body
370
     * @param string $content
371
     * @return string
372
     */
373
    protected function getUpdateMethodBody(string $content): string
374
    {
375
        $repositoryName = $this->getPropertyName($this->repositoryClass);
376
        $formParamBaseClass = $this->getClassBaseName($this->paramClass);
377
        $validatorBaseClass = $this->getClassBaseName($this->validatorClass);
378
        $entityBaseClass = $this->getClassBaseName($this->entityClass);
379
        $templatePrefix = $this->getTemplatePrefix();
380
        $listRoute = $this->getRouteName('list');
381
        $detailRoute = $this->getRouteName('detail');
382
        $notFoundMessage = $this->getMessage('messageNotFound');
383
        $updateMessage = $this->getMessage('messageUpdate');
384
        $processErrorMessage = $this->getMessage('messageProcessError');
385
        $uniqueCheckStr = $this->getUniqueFieldCheckTemplate(false);
386
        $fieldTemplates = $this->getEntityFieldsTemplate(false);
387
        $entityContextKey = $this->getEntityContextKey(true);
388
        $entityContextName = $this->getEntityContextKey(false);
389
390
        $result = <<<EOF
391
        \$context = [];
392
                \$param = new RequestData(\$request);
393
                
394
                \$id = (int) \$request->getAttribute('id');
395
396
                /** @var $entityBaseClass|null \$$entityContextName */
397
                \$$entityContextName = \$this->{$repositoryName}->find(\$id);
398
399
                if (\$$entityContextName === null) {
400
                    \$this->flash->setError(\$this->lang->tr('$notFoundMessage'));
401
402
                    return new RedirectResponse(
403
                        \$this->routeHelper->generateUrl('$listRoute')
404
                    );
405
                }
406
                \$context['$entityContextKey'] = \$$entityContextName;
407
                \$context['param'] = (new $formParamBaseClass())->fromEntity(\$$entityContextName);
408
                if (\$request->getMethod() === 'GET') {
409
                    return new TemplateResponse(
410
                        \$this->template,
411
                        '$templatePrefix/update',
412
                        \$context
413
                    );
414
                }
415
                \$formParam = new $formParamBaseClass(\$param->posts());
416
                \$context['param'] = \$formParam;
417
                
418
                \$validator = new $validatorBaseClass(\$formParam, \$this->lang);
419
                if (\$validator->validate() === false) {
420
                    \$context['errors'] = \$validator->getErrors();
421
422
                    return new TemplateResponse(
423
                        \$this->template,
424
                        '$templatePrefix/update',
425
                        \$context
426
                    );
427
                }
428
                
429
                $uniqueCheckStr
430
431
                $fieldTemplates
432
                
433
                try {
434
                    \$this->{$repositoryName}->save(\$$entityContextName);
435
436
                    \$this->flash->setSuccess(\$this->lang->tr('$updateMessage'));
437
438
                    return new RedirectResponse(
439
                        \$this->routeHelper->generateUrl('$detailRoute', ['id' => \$id])
440
                    );
441
                } catch (Exception \$ex) {
442
                    \$this->logger->error('Error when saved the data {error}', ['error' => \$ex->getMessage()]);
443
444
                    \$this->flash->setError(\$this->lang->tr('$processErrorMessage'));
445
446
                    return new TemplateResponse(
447
                        \$this->template,
448
                        '$templatePrefix/update',
449
                        \$context
450
                    );
451
                }
452
        EOF;
453
454
455
        return str_replace('%method_body_update%', $result, $content);
456
    }
457
458
    /**
459
     * Return the delete method body
460
     * @param string $content
461
     * @return string
462
     */
463
    protected function getDeleteMethodBody(string $content): string
464
    {
465
        $repositoryName = $this->getPropertyName($this->repositoryClass);
466
        $entityBaseClass = $this->getClassBaseName($this->entityClass);
467
        $notFoundMessage = $this->getMessage('messageNotFound');
468
        $deleteMessage = $this->getMessage('messageDelete');
469
        $processErrorMessage = $this->getMessage('messageProcessError');
470
        $listRoute = $this->getRouteName('list');
471
        $entityContextName = $this->getEntityContextKey(false);
472
473
        $result = <<<EOF
474
        \$id = (int) \$request->getAttribute('id');
475
476
                /** @var $entityBaseClass|null \$$entityContextName */
477
                \$$entityContextName = \$this->{$repositoryName}->find(\$id);
478
479
                if (\$$entityContextName === null) {
480
                    \$this->flash->setError(\$this->lang->tr('$notFoundMessage'));
481
482
                    return new RedirectResponse(
483
                        \$this->routeHelper->generateUrl('$listRoute')
484
                    );
485
                }
486
487
                try {
488
                    \$this->{$repositoryName}->delete(\$$entityContextName);
489
490
                    \$this->flash->setSuccess(\$this->lang->tr('$deleteMessage'));
491
492
                    return new RedirectResponse(
493
                        \$this->routeHelper->generateUrl('$listRoute')
494
                    );
495
                } catch (Exception \$ex) {
496
                    \$this->logger->error('Error when delete the data {error}', ['error' => \$ex->getMessage()]);
497
498
                    \$this->flash->setError(\$this->lang->tr('$processErrorMessage'));
499
500
                    return new RedirectResponse(
501
                        \$this->routeHelper->generateUrl('$listRoute')
502
                    );
503
                }
504
        EOF;
505
506
507
        return str_replace('%method_body_delete%', $result, $content);
508
    }
509
510
    /**
511
     * Return the template for unique field check
512
     * @param bool $create
513
     * @return string
514
     */
515
    protected function getUniqueFieldCheckTemplate(bool $create = true): string
516
    {
517
        $repositoryName = $this->getPropertyName($this->repositoryClass);
518
        $templatePrefix = $this->getTemplatePrefix();
519
        $uniqueFields = $this->getOptionValue('fieldsUnique');
520
        $uniqueCheckStr = '';
521
        if ($uniqueFields !== null) {
522
            $duplicateMessage = $this->getMessage('messageDuplicate');
523
524
            $fields = explode(',', $uniqueFields);
525
            $i = 1;
526
            $result = '';
527
            foreach ($fields as $field) {
528
                $param = $field;
529
                $uniqueField = (array) explode(':', $field);
530
                $column = $uniqueField[0];
531
532
                if (isset($uniqueField[1])) {
533
                    $param = $uniqueField[1];
534
                }
535
536
                $result .= ($i > 1 ? "\t\t\t\t\t       " : '') .
537
                        $this->getFormParamEntityFieldTemplate($column, $param, count($fields) > $i);
538
                $i++;
539
            }
540
541
            $updateStr = $create ? '' : ' && $entityExist->id !== $id';
542
            $templateName = $create ? 'create' : 'update';
543
544
            $uniqueCheckStr = <<<EOF
545
            \$entityExist = \$this->{$repositoryName}->findBy([
546
                                                           $result
547
                                                       ]);
548
                    
549
                    if(\$entityExist !== null$updateStr){
550
                        \$this->flash->setError(\$this->lang->tr('$duplicateMessage'));
551
552
                        return new TemplateResponse(
553
                            \$this->template,
554
                            '$templatePrefix/$templateName',
555
                            \$context
556
                        );
557
                    }
558
            EOF;
559
        }
560
561
        return $uniqueCheckStr;
562
    }
563
564
    /**
565
     * Return the template for order by
566
     * @return string
567
     */
568
    protected function getOrderByTemplate(): string
569
    {
570
        $result = '';
571
        $orderFields = $this->getOptionValue('fieldsOrder');
572
573
        if ($orderFields !== null) {
574
            $fields = (array) explode(',', $orderFields);
575
            $i = 1;
576
            foreach ($fields as $field) {
577
                $dir = 'ASC';
578
                $orderField = (array) explode(':', $field);
579
                $column = $orderField[0];
580
581
                if (isset($orderField[1]) && in_array(strtolower($orderField[1]), ['asc', 'desc'])) {
582
                    $dir = $orderField[1];
583
                }
584
585
                $result .= ($i > 1 ? "\t\t\t\t\t    " : '') .
586
                        sprintf('->orderBy(\'%s\', \'%s\')', $column, Str::upper($dir)) .
587
                        (count($fields) > $i ? PHP_EOL : '');
588
                $i++;
589
            }
590
        }
591
592
        return $result;
593
    }
594
595
    /**
596
     * Return the template for entity field for saving
597
     * @param bool $create
598
     * @return string
599
     */
600
    protected function getEntityFieldsTemplate(bool $create = true): string
601
    {
602
        $fields = $this->getOptionValue('fields');
603
        $result = '';
604
        if ($fields !== null) {
605
            $fields = (array) explode(',', $fields);
606
            $i = 1;
607
608
            foreach ($fields as $field) {
609
                $param = $field;
610
                $entityField = (array) explode(':', $field);
611
                $column = $entityField[0];
612
613
                if (isset($entityField[1])) {
614
                    $param = $entityField[1];
615
                }
616
617
                $result .= ($i > 1 ? "\t   " : '') .
618
                        $this->getEntityRecordFieldTemplate($column, $param, count($fields) > $i, $create);
619
                $i++;
620
            }
621
        }
622
623
        return $result;
624
    }
625
626
    /**
627
     * {@inheritdoc}
628
     */
629
    protected function getUsesContent(): string
630
    {
631
        $uses = parent::getUsesContent();
632
633
        $uses .= $this->getUsesTemplate($this->entityClass);
634
        $uses .= $this->getUsesTemplate($this->paramClass);
635
        $uses .= $this->getUsesTemplate($this->validatorClass);
636
637
        return <<<EOF
638
        $uses
639
        EOF;
640
    }
641
642
    /**
643
     * Return the base classes
644
     * @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...
645
     */
646
    protected function getBaseClasses(): array
647
    {
648
        return [
649
            Lang::class,
650
            Pagination::class,
651
            Template::class,
652
            Flash::class,
653
            RouteHelper::class,
654
            LoggerInterface::class,
655
        ];
656
    }
657
658
    /**
659
     * Return the template for entity record fields
660
     * @param string $field
661
     * @param string $param
662
     * @param bool $isLast
663
     * @param bool $create
664
     * @return string
665
     */
666
    protected function getEntityRecordFieldTemplate(
667
        string $field,
668
        string $param,
669
        bool $isLast = false,
670
        bool $create = true
671
    ): string {
672
        $fieldMethodName = $this->getFormParamMethodName($param);
673
        if ($create) {
674
            return sprintf(
675
                '\'%s\' => $formParam->%s(),',
676
                $field,
677
                $fieldMethodName
678
            ) . ($isLast ? PHP_EOL : '');
679
        }
680
        $entityContextName = $this->getEntityContextKey(false);
681
682
        return sprintf(
683
            '$%s->%s = $formParam->%s();',
684
            $entityContextName,
685
            $field,
686
            $fieldMethodName
687
        ) . ($isLast ? PHP_EOL : '');
688
    }
689
}
690