Completed
Push — master ( 7b9d9c...6bacbf )
by Neomerx
08:04
created

MakeCommand::composeApi()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 23
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 23
ccs 12
cts 12
cp 1
rs 9.0856
c 0
b 0
f 0
cc 1
eloc 17
nc 1
nop 4
crap 1
1
<?php namespace Limoncello\Application\Commands;
2
3
/**
4
 * Copyright 2015-2017 [email protected]
5
 *
6
 * Licensed under the Apache License, Version 2.0 (the "License");
7
 * you may not use this file except in compliance with the License.
8
 * You may obtain a copy of the License at
9
 *
10
 * http://www.apache.org/licenses/LICENSE-2.0
11
 *
12
 * Unless required by applicable law or agreed to in writing, software
13
 * distributed under the License is distributed on an "AS IS" BASIS,
14
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
 * See the License for the specific language governing permissions and
16
 * limitations under the License.
17
 */
18
19
use Limoncello\Application\Exceptions\InvalidArgumentException;
20
use Limoncello\Contracts\Commands\CommandInterface;
21
use Limoncello\Contracts\Commands\IoInterface;
22
use Limoncello\Contracts\FileSystem\FileSystemInterface;
23
use Limoncello\Contracts\Settings\Packages\AuthorizationSettingsInterface;
24
use Limoncello\Contracts\Settings\Packages\DataSettingsInterface;
25
use Limoncello\Contracts\Settings\Packages\FluteSettingsInterface;
26
use Limoncello\Contracts\Settings\SettingsProviderInterface;
27
use Psr\Container\ContainerExceptionInterface;
28
use Psr\Container\ContainerInterface;
29
use Psr\Container\NotFoundExceptionInterface;
30
31
/**
32
 * @package Limoncello\Application
33
 *
34
 * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
35
 */
36
class MakeCommand implements CommandInterface
37
{
38
    /**
39
     * Command name.
40
     */
41
    const NAME = 'l:make';
42
43
    /** Argument name */
44
    const ARG_ITEM = 'item';
45
46
    /** Argument name */
47
    const ARG_SINGULAR = 'singular';
48
49
    /** Argument name */
50
    const ARG_PLURAL = 'plural';
51
52
    /** Command action */
53
    const ITEM_DATA_RESOURCE = 'data-resource';
54
55
    /** Command action */
56
    const ITEM_WEB_RESOURCE = 'web-resource';
57
58
    /** Command action */
59
    const ITEM_JSON_API_RESOURCE = 'json-resource';
60
61
    /** Command action */
62
    const ITEM_FULL_RESOURCE = 'resource';
63
64
    /**
65
     * Taken from http://php.net/manual/en/language.oop5.basic.php
66
     */
67
    protected const VALID_CLASS_NAME_REGEX = '/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/';
68
69
    /**
70
     * @inheritdoc
71
     */
72 1
    public static function getName(): string
73
    {
74 1
        return static::NAME;
75
    }
76
77
    /**
78
     * @inheritdoc
79
     */
80 1
    public static function getDescription(): string
81
    {
82 1
        return 'Creates necessary classes for models, migrations and data seeds.';
83
    }
84
85
    /**
86
     * @inheritdoc
87
     */
88 1
    public static function getHelp(): string
89
    {
90 1
        return 'This command creates necessary classes for models, migrations and data seeds.';
91
    }
92
93
    /**
94
     * @inheritdoc
95
     */
96 1
    public static function getArguments(): array
97
    {
98 1
        $data     = static::ITEM_DATA_RESOURCE;
99 1
        $web      = static::ITEM_WEB_RESOURCE;
100 1
        $json     = static::ITEM_JSON_API_RESOURCE;
101 1
        $resource = static::ITEM_FULL_RESOURCE;
102
103
        return [
104
            [
105 1
                static::ARGUMENT_NAME        => static::ARG_ITEM,
106 1
                static::ARGUMENT_DESCRIPTION => "Action such as `$data`, `$web`, `$json` or `$resource`.",
107 1
                static::ARGUMENT_MODE        => static::ARGUMENT_MODE__REQUIRED,
108
            ],
109
            [
110 1
                static::ARGUMENT_NAME        => static::ARG_SINGULAR,
111 1
                static::ARGUMENT_DESCRIPTION => 'Singular name in camel case (e.g. `Post`).',
112 1
                static::ARGUMENT_MODE        => static::ARGUMENT_MODE__REQUIRED,
113
            ],
114
            [
115 1
                static::ARGUMENT_NAME        => static::ARG_PLURAL,
116 1
                static::ARGUMENT_DESCRIPTION => 'Plural name in camel case (e.g. `Posts`).',
117 1
                static::ARGUMENT_MODE        => static::ARGUMENT_MODE__REQUIRED,
118
            ],
119
        ];
120
    }
121
122
    /**
123
     * @inheritdoc
124
     */
125 1
    public static function getOptions(): array
126
    {
127 1
        return [];
128
    }
129
130
    /**
131
     * @inheritdoc
132
     */
133 10
    public static function execute(ContainerInterface $container, IoInterface $inOut): void
134
    {
135 10
        (new static())->run($container, $inOut);
136
    }
137
138
    /**
139
     * @param ContainerInterface $container
140
     * @param IoInterface        $inOut
141
     *
142
     * @return void
143
     *
144
     * @throws ContainerExceptionInterface
145
     * @throws NotFoundExceptionInterface
146
     */
147 10
    protected function run(ContainerInterface $container, IoInterface $inOut): void
148
    {
149 10
        $item     = $inOut->getArguments()[static::ARG_ITEM];
150 10
        $singular = $inOut->getArguments()[static::ARG_SINGULAR];
151 10
        $plural   = $inOut->getArguments()[static::ARG_PLURAL];
152
153 10
        if ($this->isValidShortClassName($singular) === false) {
154 1
            throw new InvalidArgumentException("`$singular` is not a valid class name.");
155
        }
156 9
        if ($this->isValidShortClassName($plural) === false) {
157 1
            throw new InvalidArgumentException("`$plural` is not a valid class name.");
158
        }
159
160
        /** @var FileSystemInterface $fileSystem */
161 8
        $fileSystem = $container->get(FileSystemInterface::class);
162
        /** @var SettingsProviderInterface $settingsProvider */
163 8
        $settingsProvider = $container->get(SettingsProviderInterface::class);
164
165 8
        $dataTemplates = function () use ($settingsProvider, $fileSystem, $singular, $plural) : array {
166
            return [
167 7
                $this->composeMigration($settingsProvider, $fileSystem, $singular, $plural),
168 7
                $this->composeSeed($settingsProvider, $fileSystem, $singular, $plural),
169 7
                $this->composeModel($settingsProvider, $fileSystem, $singular, $plural),
170
            ];
171 8
        };
172
173 8
        $basicTemplates = function () use ($settingsProvider, $fileSystem, $singular, $plural) : array {
174
            return [
175 3
                $this->composeSchema($settingsProvider, $fileSystem, $singular, $plural),
176 3
                $this->composeAuthorization($settingsProvider, $fileSystem, $singular, $plural),
177 3
                $this->composeApi($settingsProvider, $fileSystem, $singular, $plural),
178 3
                $this->composeValidationRules($settingsProvider, $fileSystem, $singular, $plural),
179 3
                $this->composeQueryValidationOnReadRules($settingsProvider, $fileSystem, $singular, $plural),
180
            ];
181 8
        };
182
183 8
        $webTemplates = function () use ($settingsProvider, $fileSystem, $singular, $plural) : array {
184
            return [
185 2
                $this->composeWebValidationOnCreateRules($settingsProvider, $fileSystem, $singular),
186 2
                $this->composeWebValidationOnUpdateRules($settingsProvider, $fileSystem, $singular),
187 2
                $this->composeWebController($settingsProvider, $fileSystem, $singular, $plural),
188 2
                $this->composeWebRoute($settingsProvider, $fileSystem, $singular, $plural),
189
            ];
190 8
        };
191
192 8
        $jsonTemplates = function () use ($settingsProvider, $fileSystem, $singular, $plural) : array {
193
            return [
194 2
                $this->composeJsonValidationOnCreateRules($settingsProvider, $fileSystem, $singular),
195 2
                $this->composeJsonValidationOnUpdateRules($settingsProvider, $fileSystem, $singular),
196 2
                $this->composeJsonController($settingsProvider, $fileSystem, $singular, $plural),
197 2
                $this->composeJsonRoute($settingsProvider, $fileSystem, $singular, $plural),
198
            ];
199 8
        };
200
201
        switch ($item) {
202 8
            case static::ITEM_DATA_RESOURCE:
203 4
                $this->createTemplates($fileSystem, array_merge(
204 4
                    $dataTemplates()
205
                ));
206 1
                break;
207 4
            case static::ITEM_WEB_RESOURCE:
208 1
                $this->createTemplates($fileSystem, array_merge(
209 1
                    $dataTemplates(),
210 1
                    $basicTemplates(),
211 1
                    $webTemplates()
212
                ));
213 1
                break;
214 3
            case static::ITEM_JSON_API_RESOURCE:
215 1
                $this->createTemplates($fileSystem, array_merge(
216 1
                    $dataTemplates(),
217 1
                    $basicTemplates(),
218 1
                    $jsonTemplates()
219
                ));
220 1
                break;
221 2
            case static::ITEM_FULL_RESOURCE:
222 1
                $this->createTemplates($fileSystem, array_merge(
223 1
                    $dataTemplates(),
224 1
                    $basicTemplates(),
225 1
                    $webTemplates(),
226 1
                    $jsonTemplates()
227
                ));
228 1
                break;
229
            default:
230 1
                $inOut->writeError("Unsupported item type `$item`." . PHP_EOL);
231 1
                break;
232
        }
233
    }
234
235
    /**
236
     * @param SettingsProviderInterface $settingsProvider
237
     * @param FileSystemInterface       $fileSystem
238
     * @param string                    $singular
239
     * @param string                    $plural
240
     *
241
     * @return TemplateOutput
242
     */
243 7
    private function composeMigration(
244
        SettingsProviderInterface $settingsProvider,
245
        FileSystemInterface $fileSystem,
246
        string $singular,
247
        string $plural
248
    ): TemplateOutput {
249 7
        $folder = $settingsProvider->get(DataSettingsInterface::class)[DataSettingsInterface::KEY_MIGRATIONS_FOLDER];
250
251 7
        $outputRootFolder = $this->filterOutFolderMask($folder);
252 7
        $outputFileName   = $plural . 'Migration.php';
253 7
        $outputContent    = $this->composeTemplateContent(
254 7
            $fileSystem,
255 7
            $this->getTemplatePath('Migration.txt'),
256
            [
0 ignored issues
show
Documentation introduced by
array('{%SINGULAR_CC%}' ...LURAL_CC%}' => $plural) is of type array<string,string,{"{%...PLURAL_CC%}":"string"}>, but the function expects a object<Limoncello\Application\Commands\iterable>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
257 7
                '{%SINGULAR_CC%}' => $singular,
258 7
                '{%PLURAL_CC%}'   => $plural,
259
            ]
260
        );
261
262 7
        return new TemplateOutput($outputRootFolder, $outputFileName, $outputContent);
263
    }
264
265
    /**
266
     * @param SettingsProviderInterface $settingsProvider
267
     * @param FileSystemInterface       $fileSystem
268
     * @param string                    $singular
269
     * @param string                    $plural
270
     *
271
     * @return TemplateOutput
272
     */
273 7
    private function composeSeed(
274
        SettingsProviderInterface $settingsProvider,
275
        FileSystemInterface $fileSystem,
276
        string $singular,
277
        string $plural
278
    ): TemplateOutput {
279 7
        $folder = $settingsProvider->get(DataSettingsInterface::class)[DataSettingsInterface::KEY_SEEDS_FOLDER];
280
281 7
        $outputRootFolder = $this->filterOutFolderMask($folder);
282 7
        $outputFileName   = $plural . 'Seed.php';
283 7
        $outputContent    = $this->composeTemplateContent(
284 7
            $fileSystem,
285 7
            $this->getTemplatePath('Seed.txt'),
286
            [
0 ignored issues
show
Documentation introduced by
array('{%SINGULAR_CC%}' ...LURAL_CC%}' => $plural) is of type array<string,string,{"{%...PLURAL_CC%}":"string"}>, but the function expects a object<Limoncello\Application\Commands\iterable>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
287 7
                '{%SINGULAR_CC%}' => $singular,
288 7
                '{%PLURAL_CC%}'   => $plural,
289
            ]
290
        );
291
292 7
        return new TemplateOutput($outputRootFolder, $outputFileName, $outputContent);
293
    }
294
295
    /**
296
     * @param SettingsProviderInterface $settingsProvider
297
     * @param FileSystemInterface       $fileSystem
298
     * @param string                    $singular
299
     * @param string                    $plural
300
     *
301
     * @return TemplateOutput
302
     */
303 7
    private function composeModel(
304
        SettingsProviderInterface $settingsProvider,
305
        FileSystemInterface $fileSystem,
306
        string $singular,
307
        string $plural
308
    ): TemplateOutput {
309 7
        $folder = $settingsProvider->get(DataSettingsInterface::class)[DataSettingsInterface::KEY_MODELS_FOLDER];
310
311 7
        $outputRootFolder = $this->filterOutFolderMask($folder);
312 7
        $outputFileName   = $singular . '.php';
313 7
        $outputContent    = $this->composeTemplateContent(
314 7
            $fileSystem,
315 7
            $this->getTemplatePath('Model.txt'),
316
            [
0 ignored issues
show
Documentation introduced by
array('{%SINGULAR_CC%}' ...=> strtoupper($plural)) is of type array<string,string,{"{%...PLURAL_UC%}":"string"}>, but the function expects a object<Limoncello\Application\Commands\iterable>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
317 7
                '{%SINGULAR_CC%}' => $singular,
318 7
                '{%SINGULAR_LC%}' => strtolower($singular),
319 7
                '{%SINGULAR_UC%}' => strtoupper($singular),
320 7
                '{%PLURAL_LC%}'   => strtolower($plural),
321 7
                '{%PLURAL_UC%}'   => strtoupper($plural),
322
            ]
323
        );
324
325 7
        return new TemplateOutput($outputRootFolder, $outputFileName, $outputContent);
326
    }
327
328
    /**
329
     * @param SettingsProviderInterface $settingsProvider
330
     * @param FileSystemInterface       $fileSystem
331
     * @param string                    $singular
332
     * @param string                    $plural
333
     *
334
     * @return TemplateOutput
335
     */
336 3
    private function composeSchema(
337
        SettingsProviderInterface $settingsProvider,
338
        FileSystemInterface $fileSystem,
339
        string $singular,
340
        string $plural
341
    ): TemplateOutput {
342 3
        $folder = $settingsProvider->get(FluteSettingsInterface::class)[FluteSettingsInterface::KEY_SCHEMAS_FOLDER];
343
344 3
        $outputRootFolder = $this->filterOutFolderMask($folder);
345 3
        $outputFileName   = $singular . 'Schema.php';
346 3
        $outputContent    = $this->composeTemplateContent(
347 3
            $fileSystem,
348 3
            $this->getTemplatePath('Schema.txt'),
349
            [
0 ignored issues
show
Documentation introduced by
array('{%SINGULAR_CC%}' ...=> strtolower($plural)) is of type array<string,string,{"{%...PLURAL_LC%}":"string"}>, but the function expects a object<Limoncello\Application\Commands\iterable>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
350 3
                '{%SINGULAR_CC%}' => $singular,
351 3
                '{%PLURAL_LC%}'   => strtolower($plural),
352
            ]
353
        );
354
355 3
        return new TemplateOutput($outputRootFolder, $outputFileName, $outputContent);
356
    }
357
358
    /**
359
     * @param SettingsProviderInterface $settingsProvider
360
     * @param FileSystemInterface       $fileSystem
361
     * @param string                    $singular
362
     * @param string                    $plural
363
     *
364
     * @return TemplateOutput
365
     */
366 3
    private function composeApi(
367
        SettingsProviderInterface $settingsProvider,
368
        FileSystemInterface $fileSystem,
369
        string $singular,
370
        string $plural
371
    ): TemplateOutput {
372 3
        $folder = $settingsProvider->get(FluteSettingsInterface::class)[FluteSettingsInterface::KEY_API_FOLDER];
373
374 3
        $outputRootFolder = $this->filterOutFolderMask($folder);
375 3
        $outputFileName   = $plural . 'Api.php';
376 3
        $outputContent    = $this->composeTemplateContent(
377 3
            $fileSystem,
378 3
            $this->getTemplatePath('Api.txt'),
379
            [
0 ignored issues
show
Documentation introduced by
array('{%SINGULAR_CC%}' ...=> strtoupper($plural)) is of type array<string,string,{"{%...PLURAL_UC%}":"string"}>, but the function expects a object<Limoncello\Application\Commands\iterable>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
380 3
                '{%SINGULAR_CC%}' => $singular,
381 3
                '{%PLURAL_CC%}'   => $plural,
382 3
                '{%SINGULAR_UC%}' => strtoupper($singular),
383 3
                '{%PLURAL_UC%}'   => strtoupper($plural),
384
            ]
385
        );
386
387 3
        return new TemplateOutput($outputRootFolder, $outputFileName, $outputContent);
388
    }
389
390
    /**
391
     * @param SettingsProviderInterface $settingsProvider
392
     * @param FileSystemInterface       $fileSystem
393
     * @param string                    $singular
394
     * @param string                    $plural
395
     *
396
     * @return TemplateOutput
397
     */
398 3
    private function composeAuthorization(
399
        SettingsProviderInterface $settingsProvider,
400
        FileSystemInterface $fileSystem,
401
        string $singular,
402
        string $plural
403
    ): TemplateOutput {
404
        $folder = $settingsProvider
405 3
                      ->get(AuthorizationSettingsInterface::class)[AuthorizationSettingsInterface::KEY_POLICIES_FOLDER];
406
407 3
        $outputRootFolder = $this->filterOutFolderMask($folder);
408 3
        $outputFileName   = $singular . 'Rules.php';
409 3
        $outputContent    = $this->composeTemplateContent(
410 3
            $fileSystem,
411 3
            $this->getTemplatePath('ApiAuthorization.txt'),
412
            [
0 ignored issues
show
Documentation introduced by
array('{%SINGULAR_CC%}' ... strtoupper($singular)) is of type array<string,string,{"{%...NGULAR_UC%}":"string"}>, but the function expects a object<Limoncello\Application\Commands\iterable>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
413 3
                '{%SINGULAR_CC%}' => $singular,
414 3
                '{%PLURAL_CC%}'   => $plural,
415 3
                '{%SINGULAR_LC%}' => strtolower($singular),
416 3
                '{%PLURAL_UC%}'   => strtoupper($plural),
417 3
                '{%SINGULAR_UC%}' => strtoupper($singular),
418
            ]
419
        );
420
421 3
        return new TemplateOutput($outputRootFolder, $outputFileName, $outputContent);
422
    }
423
424
    /**
425
     * @param SettingsProviderInterface $settingsProvider
426
     * @param FileSystemInterface       $fileSystem
427
     * @param string                    $singular
428
     * @param string                    $plural
429
     *
430
     * @return TemplateOutput
431
     */
432 3
    private function composeValidationRules(
433
        SettingsProviderInterface $settingsProvider,
434
        FileSystemInterface $fileSystem,
435
        string $singular,
436
        string $plural
437
    ): TemplateOutput {
438
        $folder = $settingsProvider
439 3
                      ->get(FluteSettingsInterface::class)[FluteSettingsInterface::KEY_JSON_VALIDATION_RULES_FOLDER];
440
441 3
        $outputRootFolder = $this->filterOutFolderMask($folder);
442 3
        $outputFileName   = $singular . 'Rules.php';
443 3
        $outputContent    = $this->composeTemplateContent(
444 3
            $fileSystem,
445 3
            $this->getTemplatePath('ValidationRules.txt'),
446
            [
0 ignored issues
show
Documentation introduced by
array('{%SINGULAR_CC%}' ...=> strtolower($plural)) is of type array<string,string,{"{%...PLURAL_LC%}":"string"}>, but the function expects a object<Limoncello\Application\Commands\iterable>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
447 3
                '{%SINGULAR_CC%}' => $singular,
448 3
                '{%SINGULAR_LC%}' => strtolower($singular),
449 3
                '{%PLURAL_LC%}'   => strtolower($plural),
450
            ]
451
        );
452
453 3
        return new TemplateOutput($outputRootFolder, $outputFileName, $outputContent, $singular);
454
    }
455
456
    /**
457
     * @param SettingsProviderInterface $settingsProvider
458
     * @param FileSystemInterface       $fileSystem
459
     * @param string                    $singular
460
     *
461
     * @return TemplateOutput
462
     */
463 2
    private function composeJsonValidationOnCreateRules(
464
        SettingsProviderInterface $settingsProvider,
465
        FileSystemInterface $fileSystem,
466
        string $singular
467
    ): TemplateOutput {
468
        $folder = $settingsProvider
469 2
                      ->get(FluteSettingsInterface::class)[FluteSettingsInterface::KEY_JSON_VALIDATORS_FOLDER];
470
471 2
        $outputRootFolder = $this->filterOutFolderMask($folder);
472 2
        $outputFileName   = $singular . 'CreateJson.php';
473 2
        $outputContent    = $this->composeTemplateContent(
474 2
            $fileSystem,
475 2
            $this->getTemplatePath('JsonRulesOnCreate.txt'),
476
            [
0 ignored issues
show
Documentation introduced by
array('{%SINGULAR_CC%}' ... strtolower($singular)) is of type array<string,string,{"{%...NGULAR_LC%}":"string"}>, but the function expects a object<Limoncello\Application\Commands\iterable>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
477 2
                '{%SINGULAR_CC%}' => $singular,
478 2
                '{%SINGULAR_LC%}' => strtolower($singular),
479
            ]
480
        );
481
482 2
        return new TemplateOutput($outputRootFolder, $outputFileName, $outputContent, $singular);
483
    }
484
485
    /**
486
     * @param SettingsProviderInterface $settingsProvider
487
     * @param FileSystemInterface       $fileSystem
488
     * @param string                    $singular
489
     *
490
     * @return TemplateOutput
491
     */
492 2
    private function composeJsonValidationOnUpdateRules(
493
        SettingsProviderInterface $settingsProvider,
494
        FileSystemInterface $fileSystem,
495
        string $singular
496
    ): TemplateOutput {
497
        $folder = $settingsProvider
498 2
                      ->get(FluteSettingsInterface::class)[FluteSettingsInterface::KEY_JSON_VALIDATORS_FOLDER];
499
500 2
        $outputRootFolder = $this->filterOutFolderMask($folder);
501 2
        $outputFileName   = $singular . 'UpdateJson.php';
502 2
        $outputContent    = $this->composeTemplateContent(
503 2
            $fileSystem,
504 2
            $this->getTemplatePath('JsonRulesOnUpdate.txt'),
505
            [
0 ignored issues
show
Documentation introduced by
array('{%SINGULAR_CC%}' ... strtolower($singular)) is of type array<string,string,{"{%...NGULAR_LC%}":"string"}>, but the function expects a object<Limoncello\Application\Commands\iterable>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
506 2
                '{%SINGULAR_CC%}' => $singular,
507 2
                '{%SINGULAR_LC%}' => strtolower($singular),
508
            ]
509
        );
510
511 2
        return new TemplateOutput($outputRootFolder, $outputFileName, $outputContent, $singular);
512
    }
513
514
    /**
515
     * @param SettingsProviderInterface $settingsProvider
516
     * @param FileSystemInterface       $fileSystem
517
     * @param string                    $singular
518
     * @param string                    $plural
519
     *
520
     * @return TemplateOutput
521
     *
522
     */
523 3
    private function composeQueryValidationOnReadRules(
524
        SettingsProviderInterface $settingsProvider,
525
        FileSystemInterface $fileSystem,
526
        string $singular,
527
        string $plural
528
    ): TemplateOutput {
529
        $folder = $settingsProvider
530 3
                      ->get(FluteSettingsInterface::class)[FluteSettingsInterface::KEY_JSON_VALIDATORS_FOLDER];
531
532 3
        $outputRootFolder = $this->filterOutFolderMask($folder);
533 3
        $outputFileName   = $plural . 'ReadQuery.php';
534 3
        $outputContent    = $this->composeTemplateContent(
535 3
            $fileSystem,
536 3
            $this->getTemplatePath('QueryRulesOnRead.txt'),
537
            [
0 ignored issues
show
Documentation introduced by
array('{%SINGULAR_CC%}' ...LURAL_CC%}' => $plural) is of type array<string,string,{"{%...PLURAL_CC%}":"string"}>, but the function expects a object<Limoncello\Application\Commands\iterable>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
538 3
                '{%SINGULAR_CC%}' => $singular,
539 3
                '{%PLURAL_CC%}'   => $plural,
540
            ]
541
        );
542
543 3
        return new TemplateOutput($outputRootFolder, $outputFileName, $outputContent, $singular);
544
    }
545
546
    /**
547
     * @param SettingsProviderInterface $settingsProvider
548
     * @param FileSystemInterface       $fileSystem
549
     * @param string                    $singular
550
     * @param string                    $plural
551
     *
552
     * @return TemplateOutput
553
     */
554 2
    private function composeJsonController(
555
        SettingsProviderInterface $settingsProvider,
556
        FileSystemInterface $fileSystem,
557
        string $singular,
558
        string $plural
559
    ): TemplateOutput {
560
        $folder = $settingsProvider
561 2
                      ->get(FluteSettingsInterface::class)[FluteSettingsInterface::KEY_JSON_CONTROLLERS_FOLDER];
562
563 2
        $outputRootFolder = $this->filterOutFolderMask($folder);
564 2
        $outputFileName   = $plural . 'Controller.php';
565 2
        $outputContent    = $this->composeTemplateContent(
566 2
            $fileSystem,
567 2
            $this->getTemplatePath('JsonController.txt'),
568
            [
0 ignored issues
show
Documentation introduced by
array('{%SINGULAR_CC%}' ...LURAL_CC%}' => $plural) is of type array<string,string,{"{%...PLURAL_CC%}":"string"}>, but the function expects a object<Limoncello\Application\Commands\iterable>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
569 2
                '{%SINGULAR_CC%}' => $singular,
570 2
                '{%PLURAL_CC%}'   => $plural,
571
            ]
572
        );
573
574 2
        return new TemplateOutput($outputRootFolder, $outputFileName, $outputContent);
575
    }
576
577
    /**
578
     * @param SettingsProviderInterface $settingsProvider
579
     * @param FileSystemInterface       $fileSystem
580
     * @param string                    $singular
581
     * @param string                    $plural
582
     *
583
     * @return TemplateOutput
584
     */
585 2
    private function composeJsonRoute(
586
        SettingsProviderInterface $settingsProvider,
587
        FileSystemInterface $fileSystem,
588
        string $singular,
589
        string $plural
590
    ): TemplateOutput {
591 2
        $folder = $settingsProvider->get(FluteSettingsInterface::class)[FluteSettingsInterface::KEY_ROUTES_FOLDER];
592
593 2
        $outputRootFolder = $this->filterOutFolderMask($folder);
594 2
        $outputFileName   = $singular . 'ApiRoutes.php';
595 2
        $outputContent    = $this->composeTemplateContent(
596 2
            $fileSystem,
597 2
            $this->getTemplatePath('JsonRoutes.txt'),
598
            [
0 ignored issues
show
Documentation introduced by
array('{%SINGULAR_CC%}' ...LURAL_CC%}' => $plural) is of type array<string,string,{"{%...PLURAL_CC%}":"string"}>, but the function expects a object<Limoncello\Application\Commands\iterable>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
599 2
                '{%SINGULAR_CC%}' => $singular,
600 2
                '{%PLURAL_CC%}'   => $plural,
601
            ]
602
        );
603
604 2
        return new TemplateOutput($outputRootFolder, $outputFileName, $outputContent);
605
    }
606
607
    /**
608
     * @param SettingsProviderInterface $settingsProvider
609
     * @param FileSystemInterface       $fileSystem
610
     * @param string                    $singular
611
     *
612
     * @return TemplateOutput
613
     */
614 2
    private function composeWebValidationOnCreateRules(
615
        SettingsProviderInterface $settingsProvider,
616
        FileSystemInterface $fileSystem,
617
        string $singular
618
    ): TemplateOutput {
619
        $folder = $settingsProvider
620 2
                      ->get(FluteSettingsInterface::class)[FluteSettingsInterface::KEY_JSON_VALIDATORS_FOLDER];
621
622 2
        $outputRootFolder = $this->filterOutFolderMask($folder);
623 2
        $outputFileName   = $singular . 'CreateForm.php';
624 2
        $outputContent    = $this->composeTemplateContent(
625 2
            $fileSystem,
626 2
            $this->getTemplatePath('WebRulesOnCreate.txt'),
627
            [
0 ignored issues
show
Documentation introduced by
array('{%SINGULAR_CC%}' => $singular) is of type array<string,string,{"{%SINGULAR_CC%}":"string"}>, but the function expects a object<Limoncello\Application\Commands\iterable>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
628 2
                '{%SINGULAR_CC%}' => $singular,
629
            ]
630
        );
631
632 2
        return new TemplateOutput($outputRootFolder, $outputFileName, $outputContent, $singular);
633
    }
634
635
    /**
636
     * @param SettingsProviderInterface $settingsProvider
637
     * @param FileSystemInterface       $fileSystem
638
     * @param string                    $singular
639
     *
640
     * @return TemplateOutput
641
     */
642 2
    private function composeWebValidationOnUpdateRules(
643
        SettingsProviderInterface $settingsProvider,
644
        FileSystemInterface $fileSystem,
645
        string $singular
646
    ): TemplateOutput {
647
        $folder = $settingsProvider
648 2
                      ->get(FluteSettingsInterface::class)[FluteSettingsInterface::KEY_JSON_VALIDATORS_FOLDER];
649
650 2
        $outputRootFolder = $this->filterOutFolderMask($folder);
651 2
        $outputFileName   = $singular . 'UpdateForm.php';
652 2
        $outputContent    = $this->composeTemplateContent(
653 2
            $fileSystem,
654 2
            $this->getTemplatePath('WebRulesOnUpdate.txt'),
655
            [
0 ignored issues
show
Documentation introduced by
array('{%SINGULAR_CC%}' => $singular) is of type array<string,string,{"{%SINGULAR_CC%}":"string"}>, but the function expects a object<Limoncello\Application\Commands\iterable>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
656 2
                '{%SINGULAR_CC%}' => $singular,
657
            ]
658
        );
659
660 2
        return new TemplateOutput($outputRootFolder, $outputFileName, $outputContent, $singular);
661
    }
662
663
    /**
664
     * @param SettingsProviderInterface $settingsProvider
665
     * @param FileSystemInterface       $fileSystem
666
     * @param string                    $singular
667
     * @param string                    $plural
668
     *
669
     * @return TemplateOutput
670
     */
671 2
    private function composeWebController(
672
        SettingsProviderInterface $settingsProvider,
673
        FileSystemInterface $fileSystem,
674
        string $singular,
675
        string $plural
676
    ): TemplateOutput {
677
        $folder = $settingsProvider
678 2
                      ->get(FluteSettingsInterface::class)[FluteSettingsInterface::KEY_WEB_CONTROLLERS_FOLDER];
679
680 2
        $outputRootFolder = $this->filterOutFolderMask($folder);
681 2
        $outputFileName   = $plural . 'Controller.php';
682 2
        $outputContent    = $this->composeTemplateContent(
683 2
            $fileSystem,
684 2
            $this->getTemplatePath('WebController.txt'),
685
            [
0 ignored issues
show
Documentation introduced by
array('{%SINGULAR_CC%}' ...=> strtoupper($plural)) is of type array<string,string,{"{%...PLURAL_UC%}":"string"}>, but the function expects a object<Limoncello\Application\Commands\iterable>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
686 2
                '{%SINGULAR_CC%}' => $singular,
687 2
                '{%PLURAL_CC%}'   => $plural,
688 2
                '{%PLURAL_LC%}'   => strtolower($plural),
689 2
                '{%PLURAL_UC%}'   => strtoupper($plural),
690
            ]
691
        );
692
693 2
        return new TemplateOutput($outputRootFolder, $outputFileName, $outputContent);
694
    }
695
696
    /**
697
     * @param SettingsProviderInterface $settingsProvider
698
     * @param FileSystemInterface       $fileSystem
699
     * @param string                    $singular
700
     * @param string                    $plural
701
     *
702
     * @return TemplateOutput
703
     */
704 2
    private function composeWebRoute(
705
        SettingsProviderInterface $settingsProvider,
706
        FileSystemInterface $fileSystem,
707
        string $singular,
708
        string $plural
709
    ): TemplateOutput {
710 2
        $folder = $settingsProvider->get(FluteSettingsInterface::class)[FluteSettingsInterface::KEY_ROUTES_FOLDER];
711
712 2
        $outputRootFolder = $this->filterOutFolderMask($folder);
713 2
        $outputFileName   = $singular . 'WebRoutes.php';
714 2
        $outputContent    = $this->composeTemplateContent(
715 2
            $fileSystem,
716 2
            $this->getTemplatePath('WebRoutes.txt'),
717
            [
0 ignored issues
show
Documentation introduced by
array('{%SINGULAR_CC%}' ...LURAL_CC%}' => $plural) is of type array<string,string,{"{%...PLURAL_CC%}":"string"}>, but the function expects a object<Limoncello\Application\Commands\iterable>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
718 2
                '{%SINGULAR_CC%}' => $singular,
719 2
                '{%PLURAL_CC%}'   => $plural,
720
            ]
721
        );
722
723 2
        return new TemplateOutput($outputRootFolder, $outputFileName, $outputContent);
724
    }
725
726
    /**
727
     * @param FileSystemInterface $fileSystem
728
     * @param TemplateOutput[]    $templateOutputs
729
     *
730
     * @return void
731
     *
732
     * @SuppressWarnings(PHPMD.ElseExpression)
733
     */
734 7
    private function createTemplates(FileSystemInterface $fileSystem, array $templateOutputs): void
735
    {
736
        // before making any changes in the filesystem we have to check there is a good chance we can make it
737 7
        foreach ($templateOutputs as $templateOutput) {
738 7
            if ($fileSystem->exists($templateOutput->getOutputRootFolder()) === false) {
739 1
                $rootFolder = $templateOutput->getOutputRootFolder();
740 1
                throw new InvalidArgumentException("Folder `$rootFolder` do not exist.");
741
            }
742
743 7
            if ($fileSystem->exists($templateOutput->getOutputPath()) === true) {
744 1
                $filePath = $templateOutput->getOutputPath();
745 1
                throw new InvalidArgumentException("File `$filePath` already exists.");
746
            }
747
748 7
            $outFolder = $templateOutput->getOutputFolder();
749 7
            if ($fileSystem->exists($outFolder) === true) {
750
                // the folder already exist so we have to check it is writable
751 7
                if ($fileSystem->isWritable($outFolder) === false) {
752 7
                    throw new InvalidArgumentException("Folder `$outFolder` is not writable.");
753
                }
754
            } else {
755
                // it should be a root folder with not yet existing sub-folder so root should be writable
756 3
                $rootFolder = $templateOutput->getOutputRootFolder();
757 3
                if ($fileSystem->isWritable($rootFolder) === false) {
758 7
                    throw new InvalidArgumentException("Folder `$rootFolder` is not writable.");
759
                }
760
            }
761
        }
762
763 4
        foreach ($templateOutputs as $templateOutput) {
764 4
            if ($fileSystem->exists($templateOutput->getOutputFolder()) === false) {
765 3
                $fileSystem->createFolder($templateOutput->getOutputFolder());
766
            }
767 4
            $fileSystem->write($templateOutput->getOutputPath(), $templateOutput->getOutputContent());
768
        }
769
    }
770
771
    /**
772
     * @param FileSystemInterface $fileSystem
773
     * @param string              $templatePath
774
     * @param iterable            $templateParams
775
     *
776
     * @return string
777
     */
778 7
    private function composeTemplateContent(
779
        FileSystemInterface $fileSystem,
780
        string $templatePath,
781
        iterable $templateParams
782
    ): string {
783 7
        $templateContent = $fileSystem->read($templatePath);
784
785 7
        foreach ($templateParams as $key => $value) {
786 7
            $templateContent = str_replace($key, $value, $templateContent);
787
        }
788
789 7
        return $templateContent;
790
    }
791
792
    /**
793
     * @param string $name
794
     *
795
     * @return bool
796
     */
797 10
    private function isValidShortClassName(string $name): bool
798
    {
799 10
        return empty($name) === false && preg_match(static::VALID_CLASS_NAME_REGEX, $name) === 1;
800
    }
801
802
    /**
803
     * @param string $fileName
804
     *
805
     * @return string
806
     */
807 7
    private function getTemplatePath(string $fileName): string
808
    {
809 7
        return implode(DIRECTORY_SEPARATOR, [__DIR__, '..', '..', 'res', 'CodeTemplates', $fileName]);
810
    }
811
812
    /**
813
     * Folder paths might include masks such as `**`. This function tries to filter them out.
814
     *
815
     * @param string $folder
816
     *
817
     * @return string
818
     */
819 7
    private function filterOutFolderMask(string $folder): string
820
    {
821 7
        $mask = '**';
822
823 7
        $folder = str_replace($mask . DIRECTORY_SEPARATOR, '', $folder);
824 7
        $folder = str_replace($mask, '', $folder);
825
826 7
        return $folder;
827
    }
828
}
829