Completed
Push — master ( ce54b6...5ea837 )
by Vítor
03:37
created

getTemplatingFilesFromEngine()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 6
rs 9.4285
cc 2
eloc 3
nc 2
nop 1
1
<?php
2
/**
3
 * This file is part of the PPI Framework.
4
 *
5
 * @copyright  Copyright (c) 2011-2016 Paul Dragoonis <[email protected]>
6
 * @license    http://opensource.org/licenses/mit-license.php MIT
7
 *
8
 * @link       http://www.ppi.io
9
 */
10
11
namespace PPI\Framework\Console\Command;
12
13
use Symfony\Component\Console\Input\InputArgument;
14
use Symfony\Component\Console\Input\InputInterface;
15
use Symfony\Component\Console\Input\InputOption;
16
use Symfony\Component\Console\Output\OutputInterface;
17
use Symfony\Component\Console\Question\ChoiceQuestion;
18
use Symfony\Component\Console\Question\ConfirmationQuestion;
19
20
/**
21
 * Module Command.
22
 *
23
 * @author      Paul Dragoonis <[email protected]>
24
 * @author      Vítor Brandão <[email protected]>
25
 */
26
class ModuleCreateCommand extends AbstractCommand
27
{
28
    const TPL_ENGINE_LATTE = 'latte';
29
    const TPL_ENGINE_PLATES = 'plates';
30
    const TPL_ENGINE_PHP = 'php';
31
    const TPL_ENGINE_TWIG = 'twig';
32
    const TPL_ENGINE_SMARTY = 'smarty';
33
34
    const ROUTING_ENGINE_SYMFONY = 'symfony';
35
    const ROUTING_ENGINE_AURA = 'aura';
36
    const ROUTING_ENGINE_LARAVEL = 'laravel';
37
    const ROUTING_ENGINE_FASTROUTE = 'fastroute';
38
    const ROUTING_ENGINE_NULL = 'NullRouter';
39
40
    protected $skeletonModuleDir;
41
    protected $modulesDir;
42
    protected $moduleDir;
43
    protected $moduleName;
44
    protected $tplEngine;
45
    protected $routingEngine;
46
    protected $configEnabledTemplatingEngines = [];
47
48
    /**
49
     * @var array
50
     */
51
    protected $coreDirs = [
52
        'src',
53
        'src/Controller',
54
        'tests',
55
        'resources',
56
        'resources/config'
57
    ];
58
59
    /**
60
     * @var array
61
     */
62
    protected $coreFiles = [
63
        'Module.php',
64
        'resources/config/config.php',
65
    ];
66
67
    protected $tplEngineCoreFiles = [
68
        'resources/views',
69
        'resources/views/index'
70
    ];
71
72
    protected $routingEngineCoreFiles = [
73
        'resources/routes'
74
    ];
75
76
    /**
77
     * @var array
78
     */
79
    protected $tplEngineFilesMap = [
80
        self::TPL_ENGINE_LATTE => [
81
            'resources/views/index/index.html.latte',
82
        ],
83
        self::TPL_ENGINE_PLATES => [
84
            'resources/views/index/index.html.plates',
85
        ],
86
        self::TPL_ENGINE_PHP => [
87
            'resources/views/index/index.html.php',
88
        ],
89
        self::TPL_ENGINE_TWIG => [
90
            'resources/views/index/base.html.twig',
91
            'resources/views/index/index.html.twig',
92
        ],
93
        self::TPL_ENGINE_SMARTY => [
94
            'resources/views/index/base.html.smarty',
95
            'resources/views/index/index.html.smarty',
96
        ],
97
    ];
98
99
    protected $routingEngineFilesMap = [
100
        self::ROUTING_ENGINE_SYMFONY => [
101
            'src/Controller/Index.php',
102
            'src/Controller/Shared.php',
103
            'resources/routes/symfony.yml'
104
        ],
105
        self::ROUTING_ENGINE_AURA => [
106
            'src/Controller/Index.php',
107
            'src/Controller/Shared.php',
108
            'resources/routes/aura.php',
109
        ],
110
        self::ROUTING_ENGINE_LARAVEL => [
111
            'src/Controller/Index.php',
112
            'src/Controller/Shared.php',
113
            'resources/routes/laravel.php',
114
        ],
115
        self::ROUTING_ENGINE_FASTROUTE => [
116
            'src/Controller/IndexInvoke.php',
117
            'src/Controller/Shared.php',
118
            'resources/routes/fastroute.php',
119
        ],
120
    ];
121
122
    protected $routingEngineTokenMap = [
123
        self::ROUTING_ENGINE_AURA => [
124
            '[ROUTING_LOAD_METHOD]' => 'loadAuraRoutes',
125
            '[ROUTING_DEF_FILE]' => 'aura.php',
126
            '[ROUTING_GETROUTES_RETVAL]' => '\Aura\Router\Router',
127
        ],
128
        self::ROUTING_ENGINE_LARAVEL => [
129
            '[ROUTING_LOAD_METHOD]' => 'loadLaravelRoutes',
130
            '[ROUTING_DEF_FILE]' => 'laravel.php',
131
            '[ROUTING_GETROUTES_RETVAL]' => '\Illuminate\Routing\Router',
132
        ],
133
        self::ROUTING_ENGINE_FASTROUTE => [
134
            '[ROUTING_LOAD_METHOD]' => 'loadFastRouteRoutes',
135
            '[ROUTING_DEF_FILE]' => 'fastroute.php',
136
            '[ROUTING_GETROUTES_RETVAL]' => '\PPI\FastRoute\Wrapper\FastRouteWrapper',
137
        ],
138
    ];
139
140
    /**
141
     * @param string $moduleDir
142
     */
143
    public function setSkeletonModuleDir($moduleDir)
144
    {
145
        $this->skeletonModuleDir = realpath($moduleDir);
146
    }
147
148
    /**
149
     * @param string $moduleDir
150
     */
151
    public function setTargetModuleDir($moduleDir)
152
    {
153
        $this->modulesDir = realpath($moduleDir);
154
    }
155
156
    /**
157
     * @param array $tplEngines
158
     */
159
    public function setEnabledTemplatingEngines(array $tplEngines)
160
    {
161
        $this->configEnabledTemplatingEngines = $tplEngines;
162
    }
163
164
    /**
165
     */
166
    protected function configure()
167
    {
168
        $this->setName('module:create')
169
            ->setDescription('Create a module')
170
            ->addArgument('name', InputArgument::REQUIRED, 'What is your module name?')
171
            ->addOption('dir', null, InputOption::VALUE_OPTIONAL, 'Specify the modules directory')
172
            ->addOption('tpl', null, InputOption::VALUE_OPTIONAL, 'Specify the templating engine')
173
            ->addOption('routing', null, InputOption::VALUE_OPTIONAL, 'Specify the routing engine');
174
    }
175
176
    /**
177
     * @param InputInterface $input
178
     * @param OutputInterface $output
179
     * @throws \Exception
180
     * @return void
181
     */
182
    protected function execute(InputInterface $input, OutputInterface $output)
183
    {
184
        $this->moduleName = $input->getArgument('name');
185
        $this->moduleDir = $this->modulesDir . DIRECTORY_SEPARATOR . $this->moduleName;
186
187
        // Acquire Module Information
188
        $this->askQuestions($input, $output);
189
        $this->createModuleStructure($this->moduleDir, $this->moduleName);
190
        $output->writeln("<info>Created module successfully</info>");
191
        $output->writeln("Name: <info>{$this->moduleName}</info>");
192
        $output->writeln(sprintf("Path: <info>%s</info>", $this->moduleDir));
193
194
        // Copy the core files
195
        $this->copyFiles($this->skeletonModuleDir, $this->moduleDir, $this->coreFiles);
196
197
        $tokenizedFiles = $this->getTokenizedCoreFiles();
198
        $tokens = [];
199
200
        $tokens['[MODULE_NAME]'] = $this->moduleName;
201
202
        if(null !== $this->tplEngine && $this->isValidTemplatingEngine($this->tplEngine)) {
203
            $this->processTemplatingFiles();
204
            $output->writeln(sprintf("Templating: <info>%s</info>", $this->tplEngine));
205
        }
206
207
        if($this->isValidRoutingEngine($this->routingEngine)) {
208
            $this->processRoutingFiles($tokenizedFiles, $tokens);
209
            $output->writeln(sprintf("Router: <info>%s</info>", $this->routingEngine));
210
        } else {
211
            $tokens['ROUTING_TRAIT'] = '';
212
        }
213
214
        // replace tokens from specified tokenizable files
215
        $this->replaceTokensInFiles($this->moduleDir, $tokenizedFiles, $tokens);
216
217
        $output->writeln("<comment>This module is not enabled. Enable it in <info>config[modules]</info> key</comment>");
218
219
        $this->checkEnabledTemplatingEngines($input, $output);
220
        $this->checkEnabledRouters($input, $output);
221
    }
222
223
    protected function isValidTemplatingEngine($tplEngine)
224
    {
225
        return in_array($tplEngine, [
226
            self::TPL_ENGINE_LATTE,
227
            self::TPL_ENGINE_PLATES,
228
            self::TPL_ENGINE_PHP,
229
            self::TPL_ENGINE_SMARTY,
230
            self::TPL_ENGINE_TWIG,
231
        ]);
232
    }
233
234
    protected function isValidRoutingEngine($routingEngine)
235
    {
236
        return in_array($routingEngine, [
237
            self::ROUTING_ENGINE_SYMFONY,
238
            self::ROUTING_ENGINE_AURA,
239
            self::ROUTING_ENGINE_LARAVEL,
240
            self::ROUTING_ENGINE_FASTROUTE,
241
            self::ROUTING_ENGINE_NULL,
242
        ]);
243
    }
244
245
    /**
246
     * @param string $moduleDir
247
     * @param array  $files
248
     * @param array  $tokens
249
     */
250
    protected function replaceTokensInFiles($moduleDir, $files, $tokens)
251
    {
252
        foreach ($files as $file) {
253
            $file = $moduleDir . DIRECTORY_SEPARATOR . $file;
254
            if (!is_writeable($file)) {
255
                throw new \InvalidArgumentException(sprintf('File %s is not writeable', $file));
256
            }
257
            file_put_contents($file, str_replace(array_keys($tokens), array_values($tokens), file_get_contents($file)));
258
        }
259
    }
260
261
    /**
262
     * @param string $skeletonDir
263
     * @param string $moduleDir
264
     * @param array  $files
265
     *
266
     * @throws \InvalidArgumentException When a file path being created already exists
267
     */
268
    protected function copyFiles($skeletonDir, $moduleDir, $files)
269
    {
270
        foreach ($files as $file) {
271
            $srcFile = $skeletonDir . DIRECTORY_SEPARATOR . $file;
272
            $dstFile = $moduleDir . DIRECTORY_SEPARATOR . $file;
273
            if (!file_exists($srcFile)) {
274
                throw new \InvalidArgumentException(sprintf('File does not exist: %s', $srcFile));
275
            }
276
            if (file_exists($dstFile)) {
277
                throw new \InvalidArgumentException(sprintf('File already exists: %s', $dstFile));
278
            }
279
            copy($srcFile, $dstFile);
280
        }
281
    }
282
283
    /**
284
     * @param string $moduleDir
285
     * @param string $moduleName
286
     *
287
     * @throws \InvalidArgumentException When a dir path being created already exists
288
     */
289
    protected function createModuleStructure($moduleDir, $moduleName)
290
    {
291
        if (is_dir($moduleDir)) {
292
            throw new \InvalidArgumentException(sprintf('Unable to create module: %s it already exists at %s%s', $moduleName, $moduleDir, $moduleName));
293
        }
294
295
        @mkdir($moduleDir);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
296
297
        // Create base structure
298
        foreach ($this->coreDirs as $coreDir) {
299
            $tmpDir = $moduleDir . DIRECTORY_SEPARATOR . $coreDir;
300
            @mkdir($tmpDir);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
301
        }
302
    }
303
304
    /**
305
     * @param InputInterface  $input
306
     * @param OutputInterface $output
307
     */
308
    protected function askQuestions(InputInterface $input, OutputInterface $output)
309
    {
310
        $questionHelper = $this->getHelper('question');
311
312
        // Module DIR
313
        if ($input->getOption('dir') == null) {
314
            $modulesDirQuestion = new ChoiceQuestion('Where is the modules dir?', [1 => $this->modulesDir], $this->modulesDir);
315
            $modulesDirQuestion->setErrorMessage('Modules dir: %s is invalid.');
316
            $this->modulesDir = $questionHelper->ask($input, $output, $modulesDirQuestion);
317
        }
318
319
        if($this->askForTemplating($input, $output)) {
320
            $this->chooseTemplatingEngine($input, $output);
321
        }
322
323
        if($this->askForRouting($input, $output)) {
324
            $this->chooseRouter($input, $output);
325
        }
326
    }
327
328
    /**
329
     * @param InputInterface  $input
330
     * @param OutputInterface $output
331
     */
332
    private function checkEnabledRouters(InputInterface $input, OutputInterface $output)
0 ignored issues
show
Unused Code introduced by
The parameter $input is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
333
    {
334
        // Aura Check
335
        if ($this->routingEngine == self::ROUTING_ENGINE_AURA && !class_exists('\Aura\Router\Router')) {
336
            $output->writeln("<comment>Aura Router doesn't appear to be loaded. Run: <info>composer require ppi/aura-router</info></comment>");
337
        }
338
339
        // Laravel check
340
        if ($this->routingEngine == self::ROUTING_ENGINE_LARAVEL && !class_exists('\PPI\LaravelRouting\LaravelRouter')) {
341
            $output->writeln("<comment>Laravel Router doesn't appear to be loaded. Run: <info>composer require ppi/laravel-router</info></comment>");
342
        }
343
344
        if ($this->routingEngine == self::ROUTING_ENGINE_FASTROUTE && !class_exists('\PPI\FastRoute\Wrapper\FastRouteWrapper')) {
345
            $output->writeln("<comment>FastRoute Router doesn't appear to be loaded. Run: <info>composer require ppi/fast-route</info></comment>");
346
        }
347
    }
348
349
    /**
350
     * @param InputInterface  $input
351
     * @param OutputInterface $output
352
     */
353
    private function checkEnabledTemplatingEngines(InputInterface $input, OutputInterface $output)
0 ignored issues
show
Unused Code introduced by
The parameter $input is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
354
    {
355
        // PHP Templating Engine checks
356
        if ($this->tplEngine == self::TPL_ENGINE_PHP) {
357
            if (!in_array($this->tplEngine, $this->configEnabledTemplatingEngines)) {
358
                $output->writeln(sprintf("<comment>PHP is not an enabled templating engine. Add <info>%s</info> it in <info>config[framework][templating][engines]</info> key</comment>", $this->tplEngine));
359
            }
360
        }
361
362
        // Twig Checks
363 View Code Duplication
        if ($this->tplEngine == self::TPL_ENGINE_TWIG) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
364
            if (!in_array($this->tplEngine, $this->configEnabledTemplatingEngines)) {
365
                $output->writeln(sprintf("<comment>Twig is not an enabled templating engine. Add <info>%s</info> it in <info>config[framework][templating][engines]</info> key</comment>", $this->tplEngine));
366
            }
367
            if (!class_exists('\Twig_Environment')) {
368
                $output->writeln("<comment>Twig doesn't appear to be loaded. Run: <info>composer require ppi/twig-module</info></comment>");
369
            }
370
        }
371
372
        // Smarty Checks
373 View Code Duplication
        if ($this->tplEngine == self::TPL_ENGINE_SMARTY) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
374
            if (!in_array($this->tplEngine, $this->configEnabledTemplatingEngines)) {
375
                $output->writeln(sprintf("<comment>Smarty is not an enabled templating engine. Add <info>%s</info> it in <info>config[framework][templating][engines]</info> key</comment>", $this->tplEngine));
376
            }
377
            if (!class_exists('\Smarty')) {
378
                $output->writeln("<comment>Smarty doesn't appear to be loaded. Run: <info>composer require ppi/smarty-module</info></comment>");
379
            }
380
        }
381
382
        // Plates Checks
383 View Code Duplication
        if ($this->tplEngine == self::TPL_ENGINE_PLATES) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
384
            if (!in_array($this->tplEngine, $this->configEnabledTemplatingEngines)) {
385
                $output->writeln(sprintf("<comment>Plates is not an enabled templating engine. Add <info>%s</info> it in <info>config[framework][templating][engines]</info> key</comment>", $this->tplEngine));
386
            }
387
            if (!class_exists('\PPI\PlatesModule\Wrapper\PlatesWrapper')) {
388
                $output->writeln("<comment>Plates doesn't appear to be loaded. Run: <info>composer require ppi/plates-module</info></comment>");
389
            }
390
        }
391
392
        // Plates Checks
393 View Code Duplication
        if ($this->tplEngine == self::TPL_ENGINE_LATTE) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
394
            if (!in_array($this->tplEngine, $this->configEnabledTemplatingEngines)) {
395
                $output->writeln(sprintf("<comment>Latte is not an enabled templating engine. Add <info>%s</info> it in <info>config[framework][templating][engines]</info> key</comment>", $this->tplEngine));
396
            }
397
            if (!class_exists('\PPI\LatteModule\Wrapper\LatteWrapper')) {
398
                $output->writeln("<comment>Latte doesn't appear to be loaded. Run: <info>composer require ppi/latte-module</info></comment>");
399
            }
400
        }
401
    }
402
403
    /**
404
     * @param InputInterface $input
405
     * @param OutputInterface $output
406
     * @return boolean
407
     */
408 View Code Duplication
    private function askForTemplating(InputInterface $input, OutputInterface $output)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
409
    {
410
        $questionHelper = $this->getHelper('question');
411
        $question = new ConfirmationQuestion("Do you need templates? (yes/no):\n", false);
412
413
        return $questionHelper->ask($input, $output, $question);
414
    }
415
416 View Code Duplication
    private function askForRouting(InputInterface $input, OutputInterface $output)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
417
    {
418
        $questionHelper = $this->getHelper('question');
419
        $question = new ConfirmationQuestion("Do you need routing? (yes/no):\n", false);
420
421
        return $questionHelper->ask($input, $output, $question);
422
    }
423
424
    private function chooseTemplatingEngine($input, $output)
425
    {
426
        $tplQuestion = new ChoiceQuestion('Choose your templating engine [php]',
427
            [
428
                1 => 'php',
429
                2 => 'twig',
430
                3 => 'smarty',
431
                4 => 'plates',
432
                5 => 'latte',
433
                99 => 'skip'
434
            ]
435
        );
436
        $tplQuestion->setErrorMessage('Templating engine %s is invalid.');
437
        if(99 !== ($tplEngine = $this->getHelper('question')->ask($input, $output, $tplQuestion))) {
438
            $this->tplEngine = $tplEngine;
439
        }
440
    }
441
442
    private function chooseRouter(InputInterface $input, OutputInterface $output)
443
    {
444
        $routingQuestion = new ChoiceQuestion('Choose your routing engine:',
445
            [
446
                1 => self::ROUTING_ENGINE_SYMFONY,
447
                2 => self::ROUTING_ENGINE_AURA,
448
                3 => self::ROUTING_ENGINE_LARAVEL,
449
                4 => self::ROUTING_ENGINE_FASTROUTE,
450
                99 => 'skip'
451
            ]
452
        );
453
454
        // @todo - test question when you don't choose any option, or an invalid one (like -1)
455
        $routingQuestion->setErrorMessage('Routing engine %s is invalid.');
456
        $chosenRouter = $this->getHelper('question')->ask($input, $output, $routingQuestion);
457
        if(99 == $chosenRouter) {
458
            $chosenRouter = 'NullRouter';
459
        }
460
        $this->routingEngine = $chosenRouter;
461
    }
462
463
    private function getTemplatingFilesFromEngine($tplEngine)
464
    {
465
        if(!isset($this->tplEngineFilesMap[$tplEngine])) {
466
            throw new \InvalidArgumentException('Invalid templating engine specified for map files: ' . $tplEngine);
467
        }
468
    }
469
470
    private function processTemplatingFiles()
471
    {
472
        $tplFiles = $this->getTemplatingFilesFromEngine($this->tplEngine);
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $tplFiles is correct as $this->getTemplatingFile...ngine($this->tplEngine) (which targets PPI\Framework\Console\Co...latingFilesFromEngine()) seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
473
474
        // Copy core templating files over
475
        foreach($this->tplEngineCoreFiles as $coreFile) {
476
            $tplFiles[] = $coreFile;
477
        }
478
479
        // Copy templating files over relevant to the specified engine
480
        $this->copyFiles($this->skeletonModuleDir, $this->moduleDir, $tplFiles);
0 ignored issues
show
Documentation introduced by
$tplFiles is of type null, but the function expects a array.

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...
481
482
        // Setting up templating tokens
483
        $tokenizedFiles = [];
484
        foreach ($tplFiles as $tplFile) {
0 ignored issues
show
Bug introduced by
The expression $tplFiles of type null is not traversable.
Loading history...
485
            $tokenizedFiles[] = $tplFile;
486
        }
487
488
        $tokens['[TPL_ENGINE_EXT]'] = $this->tplEngine;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$tokens was never initialized. Although not strictly required by PHP, it is generally a good practice to add $tokens = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
489
490
491
        $this->replaceTokensInFiles($this->moduleDir, $tokenizedFiles, $tokens);
492
493
494
    }
495
496
    /**
497
     * @throws \Exception
498
     */
499
    private function processRoutingFiles($tokenizedFiles, $tokens)
500
    {
501
502
        if(!isset($this->routingEngineFilesMap[$this->routingEngine])) {
503
            throw new \Exception('Routing engine not found in routing files map: ' . $this->routingEngine);
504
        }
505
506
        // Copy routing files over
507
        $routingFiles = $this->routingEngineFilesMap[$this->routingEngine];
508
509
        // If a valid routing engine and that's not null router
510
        if($this->routingEngine !== 99) {
511
            // Create core routing directories
512
            foreach($this->routingEngineCoreFiles as $coreFile) {
513
                @mkdir($this->moduleDir . DIRECTORY_SEPARATOR . $coreFile);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
514
            }
515
        }
516
517
518
//var_dump(__METHOD__, __LINE__, $routingFiles); exit;
0 ignored issues
show
Unused Code Comprehensibility introduced by
72% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
519
        $this->copyFiles($this->skeletonModuleDir, $this->moduleDir, $routingFiles);
520
521
        // Setting up routing tokenizable files
522
        foreach ($routingFiles as $routingFile) {
523
            $tokenizedFiles[] = $routingFile;
524
        }
525
526
        // Get all the tokens for this routing engine and the values the map to.
527
        $routingTokensMap = $this->getRoutingTokenMap($this->routingEngine);
528
        foreach ($routingTokensMap as $routingTokenKey => $routingTokenVal) {
529
            $tokens[$routingTokenKey] = $routingTokenVal;
530
        }
531
532
        // Replace tokens in all files
533
        $this->replaceTokensInFiles($this->moduleDir, $tokenizedFiles, $tokens);
534
535
        // Replace the ROUTING placeholder with this heredoc
536
537
        // Prepare the fastroute route file
538
        if ($this->routingEngine === self::ROUTING_ENGINE_FASTROUTE) {
539
            rename(
540
                $moduleDir . DIRECTORY_SEPARATOR . $routingFiles[0],
0 ignored issues
show
Bug introduced by
The variable $moduleDir does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
541
                str_replace('IndexInvoke', 'Index', $moduleDir . DIRECTORY_SEPARATOR . $routingFiles[0]
542
                ));
543
        }
544
    }
545
546
    protected function getTokenizedCoreFiles()
547
    {
548
        $files = [];
549
        foreach ($this->coreFiles as $coreFile) {
550
            $files[] = $coreFile;
551
        }
552
        return $files;
553
    }
554
555
    private function getRoutingTokenMap($routingEngine) {
556
557
//        if(!isset($this->routingEngineTokenMap[$routingEngine])) {
0 ignored issues
show
Unused Code Comprehensibility introduced by
62% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
558
//            throw new \Exception('No routing engine tokenizable files found for routing engine: ' . $this->routingEngine);
559
//        }
560
561
        $tokenMap = [];
562
563
        switch($routingEngine) {
564
            case self::ROUTING_ENGINE_SYMFONY:
565
                $tokenMap['[ROUTING_TRAIT]'] = 'use \PPI\Framework\Module\Routing\SymfonyTrait;';
566
                break;
567
568
            default:
569
                throw new \Exception('Unimplemented routing engine: ' . $routingEngine);
570
                break;
0 ignored issues
show
Unused Code introduced by
break; does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
571
        }
572
573
        return $tokenMap;
574
    }
575
576
577
}
578