Completed
Push — master ( 239a7d...29ee36 )
by Tom
9s
created

Application   F

Complexity

Total Complexity 92

Size/Duplication

Total Lines 836
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 13

Importance

Changes 0
Metric Value
wmc 92
lcom 2
cbo 13
dl 0
loc 836
rs 2.6666
c 0
b 0
f 0

40 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 1
A getDefaultInputDefinition() 0 50 1
A setAutoExit() 0 5 1
A detectMagento() 0 15 4
B registerHelpers() 0 20 5
B registerMagentoCoreCommands() 0 26 4
A add() 0 8 2
A setPharMode() 0 4 1
A isPharMode() 0 4 1
B checkVarDir() 0 56 8
A initMagento() 0 15 3
A getHelp() 0 4 1
A getLongVersion() 0 4 1
A isMagentoEnterprise() 0 4 1
B getMagentoRootFolder() 0 16 5
A setMagentoRootFolder() 0 4 1
A getMagentoMajorVersion() 0 4 2
A getAutoloader() 0 4 1
A setAutoloader() 0 4 1
A getConfig() 0 5 1
A setConfig() 0 4 1
A isMagerunStopFileFound() 0 6 1
A doRun() 0 18 2
C run() 0 38 7
B init() 0 53 8
A reinit() 0 7 1
A registerEventSubscribers() 0 9 2
A _checkSkipConfigOption() 0 4 1
A _checkSkipMagento2CoreCommandsOption() 0 4 2
A _checkRootDirOption() 0 7 2
A setRootDir() 0 12 4
A requireOnce() 0 11 2
A _initMagento1() 0 4 1
A _initMagento2() 0 17 1
B outputMagerunCompatibilityNotice() 0 35 2
A getDispatcher() 0 4 1
A setConfigurationLoader() 0 10 2
A _addOutputStyles() 0 5 1
A getObjectManager() 0 4 1
B getDetectionResult() 0 24 5

How to fix   Complexity   

Complex Class

Complex classes like Application often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Application, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace N98\Magento;
4
5
use BadMethodCallException;
6
use Composer\Autoload\ClassLoader;
7
use Exception;
8
use Magento\Framework\ObjectManager\ObjectManager;
9
use N98\Magento\Application\Config;
10
use N98\Magento\Application\ConfigurationLoader;
11
use N98\Magento\Application\Console\Events;
12
use N98\Magento\Application\DetectionResult;
13
use N98\Util\Console\Helper\MagentoHelper;
14
use N98\Util\Console\Helper\TwigHelper;
15
use N98\Util\OperatingSystem;
16
use RuntimeException;
17
use Symfony\Component\Console\Application as BaseApplication;
18
use Symfony\Component\Console\Command\Command;
19
use Symfony\Component\Console\Event\ConsoleEvent;
20
use Symfony\Component\Console\Formatter\OutputFormatterStyle;
21
use Symfony\Component\Console\Helper\FormatterHelper;
22
use Symfony\Component\Console\Input\ArgvInput;
23
use Symfony\Component\Console\Input\InputDefinition;
24
use Symfony\Component\Console\Input\InputInterface;
25
use Symfony\Component\Console\Input\InputOption;
26
use Symfony\Component\Console\Output\ConsoleOutput;
27
use Symfony\Component\Console\Output\OutputInterface;
28
use Symfony\Component\EventDispatcher\EventDispatcher;
29
use UnexpectedValueException;
30
31
class Application extends BaseApplication
32
{
33
    /**
34
     * @var string
35
     */
36
    const APP_NAME = 'n98-magerun2';
37
38
    /**
39
     * @var string
40
     */
41
    const APP_VERSION = '1.3.0';
42
43
    /**
44
     * @var int
45
     */
46
    const MAGENTO_MAJOR_VERSION_1 = 1;
47
    const MAGENTO_MAJOR_VERSION_2 = 2;
48
49
    /**
50
     * @var string
51
     */
52
    private static $logo = "
53
     ___ ___                                       ___
54
 _ _/ _ ( _ )___ _ __  __ _ __ _ ___ _ _ _  _ _ _ |_  )
55
| ' \\_, / _ \\___| '  \\/ _` / _` / -_) '_| || | ' \\ / /
56
|_||_/_/\\___/   |_|_|_\\__,_\\__, \\___|_|  \\_,_|_||_/___|
57
                           |___/
58
";
59
    /**
60
     * @var ClassLoader
61
     */
62
    protected $autoloader;
63
64
    /**
65
     * @var Config
66
     */
67
    protected $config;
68
69
    /**
70
     * @see \N98\Magento\Application::setConfigurationLoader()
71
     * @var ConfigurationLoader
72
     */
73
    private $configurationLoaderInjected;
74
75
    /**
76
     * @var string [optional] root folder not detected, but set via public setter
77
     * @see setMagentoRootFolder()
78
     */
79
    private $magentoRootFolderInjected;
80
81
    /**
82
     * @var int Magento Major Version to operate on by this Magerun application
83
     */
84
    private $magerunMajorVersion = self::MAGENTO_MAJOR_VERSION_2;
85
86
    /**
87
     * @var bool
88
     */
89
    protected $_isPharMode = false;
90
91
    /**
92
     * @var bool
93
     */
94
    protected $_isInitialized = false;
95
96
    /**
97
     * @var EventDispatcher
98
     */
99
    protected $dispatcher;
100
101
    /**
102
     * If root dir is set by root-dir option this flag is true
103
     *
104
     * @var bool
105
     */
106
    protected $_directRootDir = false;
107
108
    /**
109
     * @var DetectionResult of the Magento application (e.g. v1/v2, Enterprise/Community, root-path)
110
     */
111
    private $detectionResult;
112
113
    /**
114
     * @var ObjectManager
115
     */
116
    protected $_objectManager = null;
117
118
    /**
119
     * @var boolean
120
     */
121
    private $autoExit = true;
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
122
123
    /**
124
     * @param ClassLoader $autoloader
0 ignored issues
show
Documentation introduced by
Should the type for parameter $autoloader not be ClassLoader|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
125
     */
126
    public function __construct($autoloader = null)
127
    {
128
        $this->autoloader = $autoloader;
129
        parent::__construct(self::APP_NAME, self::APP_VERSION);
130
    }
131
132
    /**
133
     * @return InputDefinition
134
     */
135
    protected function getDefaultInputDefinition()
136
    {
137
        $inputDefinition = parent::getDefaultInputDefinition();
138
139
        /**
140
         * Root dir
141
         */
142
        $rootDirOption = new InputOption(
143
            '--root-dir',
144
            '',
145
            InputOption::VALUE_OPTIONAL,
146
            'Force magento root dir. No auto detection'
147
        );
148
        $inputDefinition->addOption($rootDirOption);
149
150
        /**
151
         * Skip config
152
         */
153
        $skipExternalConfig = new InputOption(
154
            '--skip-config',
155
            '',
156
            InputOption::VALUE_NONE,
157
            'Do not load any custom config.'
158
        );
159
        $inputDefinition->addOption($skipExternalConfig);
160
161
        /**
162
         * Skip root check
163
         */
164
        $skipExternalConfig = new InputOption(
165
            '--skip-root-check',
166
            '',
167
            InputOption::VALUE_NONE,
168
            'Do not check if n98-magerun runs as root'
169
        );
170
        $inputDefinition->addOption($skipExternalConfig);
171
172
        /**
173
         * Skip core commands
174
         */
175
        $skipMagento2CoreCommands = new InputOption(
176
            '--skip-core-commands',
177
            '',
178
            InputOption::VALUE_OPTIONAL,
179
            'Do not include Magento 2 core commands'
180
        );
181
        $inputDefinition->addOption($skipMagento2CoreCommands);
182
183
        return $inputDefinition;
184
    }
185
186
    /**
187
     * Sets whether to automatically exit after a command execution or not.
188
     *
189
     * Implemented on this level to allow early exit on configuration exceptions
190
     *
191
     * @see run()
192
     *
193
     * @param bool $boolean Whether to automatically exit after a command execution or not
194
     */
195
    public function setAutoExit($boolean)
196
    {
197
        $this->autoExit = (bool) $boolean;
198
        parent::setAutoExit($boolean);
199
    }
200
201
    /**
202
     * Search for magento root folder
203
     *
204
     * @param InputInterface $input [optional]
205
     * @param OutputInterface $output [optional]
206
     * @return void
207
     */
208
    public function detectMagento(InputInterface $input = null, OutputInterface $output = null)
209
    {
210
        if ($this->detectionResult) {
211
            return;
212
        }
213
214
        $this->detectionResult = $result = $this->getDetectionResult($input, $output);
215
216
        if ($result->isDetected()) {
217
            $magentoMajorVersion = $result->getMajorVersion();
218
            if ($magentoMajorVersion !== $this->magerunMajorVersion) {
219
                $this->_initMagento1();
220
            }
221
        }
222
    }
223
224
    /**
225
     * Add own helpers to helperset.
226
     *
227
     * @return void
228
     */
229
    protected function registerHelpers()
230
    {
231
        $helperSet = $this->getHelperSet();
232
        $config = $this->config->getConfig();
233
234
        // Twig
235
        $twigBaseDirs = array(
236
            __DIR__ . '/../../../res/twig',
237
        );
238
        if (isset($config['twig']['baseDirs']) && is_array($config['twig']['baseDirs'])) {
239
            $twigBaseDirs = array_merge(array_reverse($config['twig']['baseDirs']), $twigBaseDirs);
240
        }
241
        $helperSet->set(new TwigHelper($twigBaseDirs), 'twig');
242
243
        foreach ($config['helpers'] as $helperName => $helperClass) {
244
            if (class_exists($helperClass)) {
245
                $helperSet->set(new $helperClass(), $helperName);
246
            }
247
        }
248
    }
249
250
    /**
251
     * Try to bootstrap magento 2 and load cli application
252
     *
253
     * @param OutputInterface $output
254
     */
255
    protected function registerMagentoCoreCommands(OutputInterface $output)
256
    {
257
        $magentoRootFolder = $this->getMagentoRootFolder();
258
        if (!$magentoRootFolder) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $magentoRootFolder of type string|null is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
259
            return;
260
        }
261
262
        // Magento was found -> register core cli commands
263
        $this->requireOnce($magentoRootFolder . '/app/bootstrap.php');
264
265
        $coreCliApplication = new \Magento\Framework\Console\Cli();
266
        $coreCliApplicationCommands = $coreCliApplication->all();
267
268
        foreach ($coreCliApplicationCommands as $coreCliApplicationCommand) {
269
            if (OutputInterface::VERBOSITY_DEBUG <= $output->getVerbosity()) {
270
                $output->writeln(
271
                    sprintf(
272
                        '<debug>Add core command </debug> <info>%s</info> -> <comment>%s</comment>',
273
                        $coreCliApplicationCommand->getName(),
274
                        get_class($coreCliApplicationCommand)
275
                    )
276
                );
277
            }
278
            $this->add($coreCliApplicationCommand);
279
        }
280
    }
281
282
    /**
283
     * Override standard command registration. We want alias support.
284
     *
285
     * @param Command $command
286
     *
287
     * @return Command
0 ignored issues
show
Documentation introduced by
Should the return type not be Command|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
288
     */
289
    public function add(Command $command)
290
    {
291
        if ($this->config) {
292
            $this->config->registerConfigCommandAlias($command);
293
        }
294
295
        return parent::add($command);
296
    }
297
298
    /**
299
     * @param bool $mode
300
     */
301
    public function setPharMode($mode)
302
    {
303
        $this->_isPharMode = $mode;
304
    }
305
306
    /**
307
     * @return bool
308
     */
309
    public function isPharMode()
310
    {
311
        return $this->_isPharMode;
312
    }
313
314
    /**
315
     * @TODO Move logic into "EventSubscriber"
316
     *
317
     * @param OutputInterface $output
318
     * @return null|false
319
     */
320
    public function checkVarDir(OutputInterface $output)
321
    {
322
        $tempVarDir = sys_get_temp_dir() . '/magento/var';
323
        if (!OutputInterface::VERBOSITY_NORMAL <= $output->getVerbosity() && !is_dir($tempVarDir)) {
324
            return;
325
        }
326
327
        $this->detectMagento(null, $output);
328
        /* If magento is not installed yet, don't check */
329
        if ($this->detectionResult->getRootFolder() === null
330
            || !file_exists($this->getMagentoRootFolder() . '/app/etc/env.php')
331
        ) {
332
            return;
333
        }
334
335
        try {
336
            $this->initMagento();
337
        } catch (Exception $e) {
338
            $message = 'Cannot initialize Magento. Please check your configuration. '
339
                . 'Some n98-magerun command will not work. Got message: '
340
                . $e->getMessage();
341
            if (OutputInterface::VERBOSITY_VERY_VERBOSE <= $output->getVerbosity()) {
342
                $message .= "\n" . $e->getTraceAsString();
343
            }
344
            $output->writeln($message);
345
346
            return;
347
        }
348
349
        $directoryList = $this->_objectManager->get('\Magento\Framework\App\Filesystem\DirectoryList');
350
        $currentVarDir = $directoryList->getPath('var');
351
352
        if ($currentVarDir === $tempVarDir) {
353
            $output->writeln(array(
354
                sprintf('<warning>Fallback folder %s is used in n98-magerun</warning>', $tempVarDir),
355
                '',
356
                'n98-magerun2 is using the fallback folder. If there is another folder configured for Magento, this ' .
357
                'can cause serious problems.',
358
                'Please refer to https://github.com/netz98/n98-magerun/wiki/File-system-permissions ' .
359
                'for more information.',
360
                '',
361
            ));
362
        } else {
363
            $output->writeln(array(
364
                sprintf('<warning>Folder %s found, but not used in n98-magerun</warning>', $tempVarDir),
365
                '',
366
                "This might cause serious problems. n98-magerun2 is using the configured var-folder " .
367
                "<comment>$currentVarDir</comment>",
368
                'Please refer to https://github.com/netz98/n98-magerun/wiki/File-system-permissions ' .
369
                'for more information.',
370
                '',
371
            ));
372
373
            return false;
374
        }
375
    }
376
377
    /**
378
     * Loads and initializes the Magento application
379
     *
380
     * @param bool $soft
381
     *
382
     * @return bool false if magento root folder is not set, true otherwise
383
     */
384
    public function initMagento($soft = false)
385
    {
386
        if ($this->getMagentoRootFolder(true) === null) {
387
            return false;
388
        }
389
390
        $isMagento2 = $this->detectionResult->getMajorVersion() === self::MAGENTO_MAJOR_VERSION_2;
391
        if ($isMagento2) {
392
            $this->_initMagento2();
393
        } else {
394
            $this->_initMagento1($soft);
395
        }
396
397
        return true;
398
    }
399
400
    /**
401
     * @return string
402
     */
403
    public function getHelp()
404
    {
405
        return self::$logo . parent::getHelp();
406
    }
407
408
    public function getLongVersion()
409
    {
410
        return parent::getLongVersion() . ' by <info>netz98 GmbH</info>';
411
    }
412
413
    /**
414
     * @return boolean
415
     */
416
    public function isMagentoEnterprise()
417
    {
418
        return $this->detectionResult->isEnterpriseEdition();
419
    }
420
421
    /**
422
     * @param bool $preventException [optional] on uninitialized magento root folder (returns null then, caution!)
423
     * @return string
0 ignored issues
show
Documentation introduced by
Should the return type not be string|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
424
     */
425
    public function getMagentoRootFolder($preventException = false)
426
    {
427
        if (null !== $this->magentoRootFolderInjected) {
428
            return $this->magentoRootFolderInjected;
429
        }
430
431
        if ($preventException) {
432
            return $this->detectionResult ? $this->detectionResult->getRootFolder() : null;
433
        }
434
435
        if (!$this->detectionResult) {
436
            throw new BadMethodCallException('Magento-root-folder is not yet detected (nor set)');
437
        }
438
439
        return $this->detectionResult->getRootFolder();
440
    }
441
442
    /**
443
     * @param string $magentoRootFolder
444
     */
445
    public function setMagentoRootFolder($magentoRootFolder)
446
    {
447
        $this->magentoRootFolderInjected = $magentoRootFolder;
448
    }
449
450
    /**
451
     * @return int
0 ignored issues
show
Documentation introduced by
Should the return type not be integer|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
452
     */
453
    public function getMagentoMajorVersion()
454
    {
455
        return $this->detectionResult ? $this->detectionResult->getMajorVersion() : null;
456
    }
457
458
    /**
459
     * @return ClassLoader
460
     */
461
    public function getAutoloader()
462
    {
463
        return $this->autoloader;
464
    }
465
466
    /**
467
     * @param ClassLoader $autoloader
468
     */
469
    public function setAutoloader(ClassLoader $autoloader)
470
    {
471
        $this->autoloader = $autoloader;
472
    }
473
474
    /**
475
     * @return array
476
     */
477
    public function getConfig()
478
    {
479
        // TODO(TK) getter for config / getter for config array
480
        return $this->config->getConfig();
481
    }
482
483
    /**
484
     * @param array $config
485
     */
486
    public function setConfig($config)
487
    {
488
        $this->config->setConfig($config);
489
    }
490
491
    /**
492
     * @deprecated 1.3.0
493
     * @return boolean
494
     */
495
    public function isMagerunStopFileFound()
496
    {
497
        trigger_error('Deprecated method "isMagerunStopFileFound" called.', E_USER_DEPRECATED);
498
499
        return $this->detectionResult->isMagerunStopFileFound();
500
    }
501
502
    /**
503
     * Runs the current application with possible command aliases
504
     *
505
     * @param InputInterface $input An Input instance
506
     * @param OutputInterface $output An Output instance
507
     *
508
     * @return integer 0 if everything went fine, or an error code
509
     */
510
    public function doRun(InputInterface $input, OutputInterface $output)
511
    {
512
        $event = new Application\Console\Event($this, $input, $output);
513
        $this->dispatcher->dispatch(Events::RUN_BEFORE, $event);
514
515
        /**
516
         * only for compatibility to old versions.
517
         */
518
        $event = new ConsoleEvent(new Command('dummy'), $input, $output);
519
        $this->dispatcher->dispatch('console.run.before', $event);
520
521
        $input = $this->config->checkConfigCommandAlias($input);
522
        if ($output instanceof ConsoleOutput) {
523
            $this->checkVarDir($output->getErrorOutput());
524
        }
525
526
        return parent::doRun($input, $output);
527
    }
528
529
    /**
530
     * @param InputInterface $input [optional]
531
     * @param OutputInterface $output [optional]
0 ignored issues
show
Documentation introduced by
Should the type for parameter $output not be null|OutputInterface?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
532
     *
533
     * @return int
0 ignored issues
show
Documentation introduced by
Should the return type not be null|integer?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
534
     */
535
    public function run(InputInterface $input = null, OutputInterface $output = null)
536
    {
537
        if (null === $input) {
538
            $input = new ArgvInput();
539
        }
540
541
        if (null === $output) {
542
            $output = new ConsoleOutput();
543
        }
544
        $this->_addOutputStyles($output);
545
        if ($output instanceof ConsoleOutput) {
546
            $this->_addOutputStyles($output->getErrorOutput());
547
        }
548
549
        $this->configureIO($input, $output);
550
551
        try {
552
            $this->init(array(), $input, $output);
553
        } catch (Exception $e) {
554
            $output = new ConsoleOutput();
555
            $this->renderException($e, $output->getErrorOutput());
556
            $exitCode = max(1, min(255, (int) $e->getCode()));
557
            if ($this->autoExit) {
558
                die($exitCode);
1 ignored issue
show
Coding Style Compatibility introduced by
The method run() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
559
            }
560
561
            return $exitCode;
562
        }
563
564
        $return = parent::run($input, $output);
565
566
        // Fix for no return values -> used in interactive shell to prevent error output
567
        if ($return === null) {
568
            return 0;
569
        }
570
571
        return $return;
572
    }
573
574
    /**
575
     * @param array $initConfig [optional]
576
     * @param InputInterface $input [optional]
577
     * @param OutputInterface $output [optional]
0 ignored issues
show
Documentation introduced by
Should the type for parameter $output not be null|OutputInterface?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
578
     *
579
     * @return void
580
     */
581
    public function init(array $initConfig = array(), InputInterface $input = null, OutputInterface $output = null)
582
    {
583
        if ($this->_isInitialized) {
584
            return;
585
        }
586
587
        // Suppress DateTime warnings
588
        date_default_timezone_set(@date_default_timezone_get());
589
590
        // Initialize EventDispatcher early
591
        $this->dispatcher = new EventDispatcher();
592
        $this->setDispatcher($this->dispatcher);
593
594
        $input = $input ?: new ArgvInput();
595
        $output = $output ?: new ConsoleOutput();
596
597
        if (null !== $this->config) {
598
            throw new UnexpectedValueException(sprintf('Config already initialized'));
599
        }
600
601
        $loadExternalConfig = !$this->_checkSkipConfigOption($input);
602
603
        $this->config = $config = new Config($initConfig, $this->isPharMode(), $output);
604
        if ($this->configurationLoaderInjected) {
605
            $config->setLoader($this->configurationLoaderInjected);
606
        }
607
        $config->loadPartialConfig($loadExternalConfig);
608
        $this->detectMagento($input, $output);
609
610
        $configLoader = $config->getLoader();
611
        $configLoader->loadStageTwo(
612
            $this->getMagentoRootFolder(true),
613
            $loadExternalConfig,
614
            $this->detectionResult->getMagerunStopFileFolder()
615
        );
616
        $config->load();
617
618
        if ($autoloader = $this->autoloader) {
619
            /**
620
             * Include commands shipped by Magento 2 core
621
             */
622
            if (!$this->_checkSkipMagento2CoreCommandsOption($input)) {
623
                $this->registerMagentoCoreCommands($output);
624
            }
625
            $config->registerCustomAutoloaders($autoloader);
626
            $this->registerEventSubscribers();
627
            $config->registerCustomCommands($this);
628
        }
629
630
        $this->registerHelpers();
631
632
        $this->_isInitialized = true;
633
    }
634
635
    /**
636
     * @param array $initConfig [optional]
637
     * @param InputInterface $input [optional]
638
     * @param OutputInterface $output [optional]
0 ignored issues
show
Documentation introduced by
Should the type for parameter $output not be null|OutputInterface?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
639
     */
640
    public function reinit($initConfig = array(), InputInterface $input = null, OutputInterface $output = null)
641
    {
642
        $this->_isInitialized = false;
643
        $this->detectionResult = null;
644
        $this->config = null;
645
        $this->init($initConfig, $input, $output);
646
    }
647
648
    /**
649
     * @return void
650
     */
651
    protected function registerEventSubscribers()
652
    {
653
        $config = $this->config->getConfig();
654
        $subscriberClasses = $config['event']['subscriber'];
655
        foreach ($subscriberClasses as $subscriberClass) {
656
            $subscriber = new $subscriberClass();
657
            $this->dispatcher->addSubscriber($subscriber);
658
        }
659
    }
660
661
    /**
662
     * @param InputInterface $input
663
     * @return bool
664
     */
665
    protected function _checkSkipConfigOption(InputInterface $input)
666
    {
667
        return $input->hasParameterOption('--skip-config');
668
    }
669
670
    /**
671
     * @return bool
672
     */
673
    protected function _checkSkipMagento2CoreCommandsOption(InputInterface $input)
674
    {
675
        return $input->hasParameterOption('--skip-core-commands') || getenv('MAGERUN_SKIP_CORE_COMMANDS');
676
    }
677
678
    /**
679
     * @param InputInterface $input
680
     * @return string
0 ignored issues
show
Documentation introduced by
Should the return type not be string|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
681
     */
682
    protected function _checkRootDirOption(InputInterface $input)
683
    {
684
        $rootDir = $input->getParameterOption('--root-dir');
685
        if (is_string($rootDir)) {
686
            $this->setRootDir($rootDir);
687
        }
688
    }
689
690
    /**
691
     * Set root dir (chdir()) of magento directory
692
     *
693
     * @param string $path to Magento directory
694
     */
695
    private function setRootDir($path)
696
    {
697
        if (isset($path[0]) && '~' === $path[0]) {
698
            $path = OperatingSystem::getHomeDir() . substr($path, 1);
699
        }
700
701
        $folder = realpath($path);
702
        $this->_directRootDir = true;
703
        if (is_dir($folder)) {
704
            chdir($folder);
705
        }
706
    }
707
708
    /**
709
     * use require-once inside a function with it's own variable scope w/o any other variables
710
     * and $this unbound.
711
     *
712
     * @param string $path
713
     */
714
    private function requireOnce($path)
715
    {
716
        $requireOnce = function () {
717
            require_once func_get_arg(0);
718
        };
719
        if (50400 <= PHP_VERSION_ID) {
720
            $requireOnce->bindTo(null);
721
        }
722
723
        $requireOnce($path);
724
    }
725
726
    /**
727
     * @param bool $soft
728
     *
729
     * @return void
730
     */
731
    protected function _initMagento1($soft = false)
0 ignored issues
show
Unused Code introduced by
The parameter $soft 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...
732
    {
733
        $this->outputMagerunCompatibilityNotice('1');
734
    }
735
736
    /**
737
     * @return void
738
     */
739
    protected function _initMagento2()
0 ignored issues
show
Coding Style introduced by
_initMagento2 uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
740
    {
741
        $this->requireOnce($this->getMagentoRootFolder() . '/app/bootstrap.php');
742
743
        $params = $_SERVER;
744
        $params[\Magento\Store\Model\StoreManager::PARAM_RUN_CODE] = 'admin';
745
        $params[\Magento\Store\Model\Store::CUSTOM_ENTRY_POINT_PARAM] = true;
746
        $params['entryPoint'] = basename(__FILE__);
747
748
        $bootstrap = \Magento\Framework\App\Bootstrap::create(BP, $params);
749
        /** @var \Magento\Framework\App\Cron $app */
750
        $app = $bootstrap->createApplication('N98\Magento\Framework\App\Magerun', []);
751
        /* @var $app \N98\Magento\Framework\App\Magerun */
752
        $app->launch();
753
754
        $this->_objectManager = $app->getObjectManager();
0 ignored issues
show
Documentation Bug introduced by
It seems like $app->getObjectManager() of type object<Magento\Framework\ObjectManagerInterface> is incompatible with the declared type object<Magento\Framework...tManager\ObjectManager> of property $_objectManager.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
755
    }
756
757
    /**
758
     * Show a hint that this is Magento incompatible with Magerun and how to obtain the correct Magerun for it
759
     *
760
     * @param string $version of Magento, "1" or "2", that is incompatible
761
     */
762
    private function outputMagerunCompatibilityNotice($version)
763
    {
764
        $file = $version === '2' ? $version : '';
765
        $magentoHint = <<<MAGENTOHINT
766
You are running a Magento $version.x instance. This version of n98-magerun is not compatible
767
with Magento $version.x. Please use n98-magerun$file (version $version) for this shop.
768
769
A current version of the software can be downloaded from the website:
770
771
<info>Download with curl
772
------------------</info>
773
774
    <comment>curl -O https://files.magerun.net/n98-magerun$file.phar</comment>
775
776
<info>Download with wget
777
------------------</info>
778
779
    <comment>wget https://files.magerun.net/n98-magerun$file.phar</comment>
780
781
MAGENTOHINT;
782
783
        $output = new ConsoleOutput();
784
785
        /** @var $formatter FormatterHelper */
786
        $formatter = $this->getHelperSet()->get('formatter');
787
788
        $output->writeln(array(
789
            '',
790
            $formatter->formatBlock('Compatibility Notice', 'bg=blue;fg=white', true),
791
            '',
792
            $magentoHint,
793
        ));
794
795
        throw new RuntimeException('This version of n98-magerun is not compatible with Magento ' . $version);
796
    }
797
798
    /**
799
     * @return EventDispatcher
800
     */
801
    public function getDispatcher()
802
    {
803
        return $this->dispatcher;
804
    }
805
806
    /**
807
     * @param ConfigurationLoader $configurationLoader
808
     */
809
    public function setConfigurationLoader(ConfigurationLoader $configurationLoader)
810
    {
811
        if ($this->config) {
812
            $this->config->setLoader($configurationLoader);
813
        } else {
814
            /* inject loader to be used later when config is created in */
815
            /* @see \N98\Magento\Application::init() */
0 ignored issues
show
Unused Code Comprehensibility introduced by
38% 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...
816
            $this->configurationLoaderInjected = $configurationLoader;
817
        }
818
    }
819
820
    /**
821
     * @param OutputInterface $output
822
     */
823
    protected function _addOutputStyles(OutputInterface $output)
824
    {
825
        $output->getFormatter()->setStyle('debug', new OutputFormatterStyle('magenta', 'white'));
826
        $output->getFormatter()->setStyle('warning', new OutputFormatterStyle('red', 'yellow', array('bold')));
827
    }
828
829
    /**
830
     * @return ObjectManager
831
     */
832
    public function getObjectManager()
833
    {
834
        return $this->_objectManager;
835
    }
836
837
    /**
838
     * @param InputInterface $input [optional]
839
     * @param OutputInterface $output [optional]
0 ignored issues
show
Documentation introduced by
Should the type for parameter $output not be null|OutputInterface?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
840
     * @return DetectionResult
841
     */
842
    private function getDetectionResult(InputInterface $input = null, OutputInterface $output = null)
843
    {
844
        $input = $input ?: new ArgvInput();
845
        $output = $output ?: new ConsoleOutput();
846
847
        $folder = $this->getMagentoRootFolder(true);
848
        if ($folder === null) {
849
            $this->_checkRootDirOption($input);
850
            $folder = OperatingSystem::getCwd();
851
        }
852
        if ($this->_directRootDir) {
853
            $subFolders = array($folder);
854
        } else {
855
            $subFolders = $this->config->getDetectSubFolders();
856
        }
857
858
        $this->getHelperSet()->set(new MagentoHelper($input, $output), 'magento');
859
        /* @var $magentoHelper MagentoHelper */
860
        $magentoHelper = $this->getHelperSet()->get('magento');
861
862
        $detection = new Application\DetectionResult($magentoHelper, $folder, $subFolders);
863
864
        return $detection;
865
    }
866
}
867