Completed
Pull Request — develop (#182)
by Tom
04:37
created

Application::getDefaultInputDefinition()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 50
Code Lines 27

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 1 Features 1
Metric Value
c 3
b 1
f 1
dl 0
loc 50
rs 9.3333
cc 1
eloc 27
nc 1
nop 0
1
<?php
2
3
namespace N98\Magento;
4
5
use Composer\Autoload\ClassLoader;
6
use Magento\Framework\ObjectManager\ObjectManager;
7
use Magento\Mtf\EntryPoint\EntryPoint;
8
use N98\Magento\Application\Config;
9
use N98\Magento\Application\ConfigurationLoader;
10
use N98\Magento\Application\Console\Events;
11
use N98\Util\Console\Helper\MagentoHelper;
12
use N98\Util\Console\Helper\TwigHelper;
13
use N98\Util\OperatingSystem;
14
use Symfony\Component\Console\Application as BaseApplication;
15
use Symfony\Component\Console\Command\Command;
16
use Symfony\Component\Console\Event\ConsoleEvent;
17
use Symfony\Component\Console\Formatter\OutputFormatterStyle;
18
use Symfony\Component\Console\Input\ArgvInput;
19
use Symfony\Component\Console\Input\InputDefinition;
20
use Symfony\Component\Console\Input\InputInterface;
21
use Symfony\Component\Console\Input\InputOption;
22
use Symfony\Component\Console\Output\ConsoleOutput;
23
use Symfony\Component\Console\Output\NullOutput;
24
use Symfony\Component\Console\Output\OutputInterface;
25
use Symfony\Component\EventDispatcher\EventDispatcher;
26
use UnexpectedValueException;
27
28
class Application extends BaseApplication
29
{
30
    /**
31
     * @var string
32
     */
33
    const APP_NAME = 'n98-magerun2';
34
35
    /**
36
     * @var string
37
     */
38
    const APP_VERSION = '1.1.5';
39
40
    /**
41
     * @var int
42
     */
43
    const MAGENTO_MAJOR_VERSION_1 = 1;
44
45
    /**
46
     * @var int
47
     */
48
    const MAGENTO_MAJOR_VERSION_2 = 2;
49
50
    /**
51
     * @var string
52
     */
53
    private static $logo = "
54
          ____  ____                                                   ___ 
55
   ____  / __ \\( __ )      ____ ___  ____ _____ ____  _______  ______ |__ \\
56
  / __ \\/ /_/ / __  |_____/ __ `__ \\/ __ `/ __ `/ _ \\/ ___/ / / / __ \\__/ /
57
 / / / /\\__, / /_/ /_____/ / / / / / /_/ / /_/ /  __/ /  / /_/ / / / / __/
58
/_/ /_//____/\\____/     /_/ /_/ /_/\\__,_/\\__, /\\___/_/   \\__,_/_/ /_/____/
59
                                        /____/                             
60
";
61
    /**
62
     * @var ClassLoader
63
     */
64
    protected $autoloader;
65
66
    /**
67
     * @var Config
68
     */
69
    protected $config;
70
71
    /**
72
     * @var string
73
     */
74
    protected $_magentoRootFolder = null;
75
76
    /**
77
     * @var bool
78
     */
79
    protected $_magentoEnterprise = false;
80
81
    /**
82
     * @var int
83
     */
84
    protected $_magentoMajorVersion = self::MAGENTO_MAJOR_VERSION_2;
85
86
    /**
87
     * @var EntryPoint
88
     */
89
    protected $_magento2EntryPoint = null;
90
91
    /**
92
     * @var bool
93
     */
94
    protected $_isPharMode = false;
95
96
    /**
97
     * @var bool
98
     */
99
    protected $_magerunStopFileFound = false;
100
101
    /**
102
     * @var string
103
     */
104
    protected $_magerunStopFileFolder = null;
105
106
    /**
107
     * @var bool
108
     */
109
    protected $_isInitialized = false;
110
111
    /**
112
     * @var EventDispatcher
113
     */
114
    protected $dispatcher;
115
116
    /**
117
     * If root dir is set by root-dir option this flag is true
118
     *
119
     * @var bool
120
     */
121
    protected $_directRootDir = false;
122
123
    /**
124
     * @var bool
125
     */
126
    protected $_magentoDetected = false;
127
128
    /**
129
     * @var ObjectManager
130
     */
131
    protected $_objectManager = null;
132
133
    /**
134
     * @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...
135
     */
136
    public function __construct($autoloader = null)
137
    {
138
        $this->autoloader = $autoloader;
139
        parent::__construct(self::APP_NAME, self::APP_VERSION);
140
    }
141
142
    /**
143
     * @return InputDefinition
144
     */
145
    protected function getDefaultInputDefinition()
146
    {
147
        $inputDefinition = parent::getDefaultInputDefinition();
148
149
        /**
150
         * Root dir
151
         */
152
        $rootDirOption = new InputOption(
153
            '--root-dir',
154
            '',
155
            InputOption::VALUE_OPTIONAL,
156
            'Force magento root dir. No auto detection'
157
        );
158
        $inputDefinition->addOption($rootDirOption);
159
160
        /**
161
         * Skip config
162
         */
163
        $skipExternalConfig = new InputOption(
164
            '--skip-config',
165
            '',
166
            InputOption::VALUE_NONE,
167
            'Do not load any custom config.'
168
        );
169
        $inputDefinition->addOption($skipExternalConfig);
170
171
        /**
172
         * Skip root check
173
         */
174
        $skipExternalConfig = new InputOption(
175
            '--skip-root-check',
176
            '',
177
            InputOption::VALUE_NONE,
178
            'Do not check if n98-magerun runs as root'
179
        );
180
        $inputDefinition->addOption($skipExternalConfig);
181
182
        /**
183
         * Skip core commands
184
         */
185
        $skipMagento2CoreCommands = new InputOption(
186
            '--skip-core-commands',
187
            '',
188
            InputOption::VALUE_OPTIONAL,
189
            'Do not include Magento 2 core commands'
190
        );
191
        $inputDefinition->addOption($skipMagento2CoreCommands);
192
193
        return $inputDefinition;
194
    }
195
196
    /**
197
     * Search for magento root folder
198
     *
199
     * @param InputInterface $input [optional]
1 ignored issue
show
Documentation introduced by
Should the type for parameter $input not be null|InputInterface?

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...
200
     * @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...
201
     * @return void
202
     */
203
    public function detectMagento(InputInterface $input = null, OutputInterface $output = null)
204
    {
205
        // do not detect magento twice
206
        if ($this->_magentoDetected) {
207
            return;
208
        }
209
210
        if ($this->getMagentoRootFolder() === null) {
211
            $this->_checkRootDirOption();
212
            $folder = OperatingSystem::getCwd();
213
        } else {
214
            $folder = $this->getMagentoRootFolder();
215
        }
216
217
        $this->getHelperSet()->set(new MagentoHelper($input, $output), 'magento');
218
        $magentoHelper = $this->getHelperSet()->get('magento');
219
        /* @var $magentoHelper MagentoHelper */
220
        if (!$this->_directRootDir) {
221
            $subFolders = $this->config->getDetectSubFolders();
222
        } else {
223
            $subFolders = array();
224
        }
225
226
        $this->_magentoDetected = $magentoHelper->detect($folder, $subFolders);
227
        $this->_magentoRootFolder = $magentoHelper->getRootFolder();
228
        $this->_magentoEnterprise = $magentoHelper->isEnterpriseEdition();
229
        $this->_magentoMajorVersion = $magentoHelper->getMajorVersion();
230
        $this->_magerunStopFileFound = $magentoHelper->isMagerunStopFileFound();
231
        $this->_magerunStopFileFolder = $magentoHelper->getMagerunStopFileFolder();
232
    }
233
234
    /**
235
     * Add own helpers to helperset.
236
     *
237
     * @return void
238
     */
239
    protected function registerHelpers()
240
    {
241
        $helperSet = $this->getHelperSet();
242
        $config = $this->config->getConfig();
243
244
        // Twig
245
        $twigBaseDirs = array(
246
            __DIR__ . '/../../../res/twig'
247
        );
248
        if (isset($config['twig']['baseDirs']) && is_array($config['twig']['baseDirs'])) {
249
            $twigBaseDirs = array_merge(array_reverse($config['twig']['baseDirs']), $twigBaseDirs);
250
        }
251
        $helperSet->set(new TwigHelper($twigBaseDirs), 'twig');
252
253
        foreach ($config['helpers'] as $helperName => $helperClass) {
254
            if (class_exists($helperClass)) {
255
                $helperSet->set(new $helperClass(), $helperName);
256
            }
257
        }
258
    }
259
260
    /**
261
     * Try to bootstrap magento 2 and load cli application
262
     *
263
     * @param OutputInterface $output
264
     */
265
    protected function registerMagentoCoreCommands(OutputInterface $output)
266
    {
267
        if ($this->getMagentoRootFolder()) {
268
            // Magento was found -> register core cli commands
269
            require_once $this->getMagentoRootFolder() . '/app/bootstrap.php';
270
271
            $coreCliApplication = new \Magento\Framework\Console\Cli();
272
            $coreCliApplicationCommands = $coreCliApplication->all();
273
274
            foreach ($coreCliApplicationCommands as $coreCliApplicationCommand) {
275
                $this->add($coreCliApplicationCommand);
276
277
                if (OutputInterface::VERBOSITY_DEBUG <= $output->getVerbosity()) {
278
                    $output->writeln(
279
                        '<debug>Added core command </debug><comment>'
280
                        . get_class($coreCliApplicationCommand) . '</comment>'
281
                    );
282
                }
283
            }
284
        }
285
    }
286
287
    /**
288
     * Override standard command registration. We want alias support.
289
     *
290
     * @param \Symfony\Component\Console\Command\Command $command
291
     * @return \Symfony\Component\Console\Command\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...
292
     */
293
    public function add(Command $command)
294
    {
295
        if ($this->config) {
296
            $this->config->registerConfigCommandAlias($command);
297
        }
298
299
        return parent::add($command);
300
    }
301
302
    /**
303
     * @param bool $mode
304
     */
305
    public function setPharMode($mode)
306
    {
307
        $this->_isPharMode = $mode;
308
    }
309
310
    /**
311
     * @return bool
312
     */
313
    public function isPharMode()
314
    {
315
        return $this->_isPharMode;
316
    }
317
318
    /**
319
     * @TODO Move logic into "EventSubscriber"
320
     *
321
     * @param OutputInterface $output
322
     * @return bool
0 ignored issues
show
Documentation introduced by
Should the return type not be null|false?

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...
323
     */
324
    public function checkVarDir(OutputInterface $output)
325
    {
326
        $tempVarDir = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'magento' . DIRECTORY_SEPARATOR . 'var';
327
        if (!OutputInterface::VERBOSITY_NORMAL <= $output->getVerbosity() && !is_dir($tempVarDir)) {
328
            return;
329
        }
330
331
        $this->detectMagento(null, $output);
332
        /* If magento is not installed yet, don't check */
333
        if ($this->_magentoRootFolder === null
334
            || !file_exists($this->_magentoRootFolder . '/app/etc/local.xml')
335
        ) {
336
            return;
337
        }
338
339
        try {
340
            $this->initMagento();
341
        } catch (\Exception $e) {
342
            $message = 'Cannot initialize Magento. Please check your configuration. '
343
                . 'Some n98-magerun command will not work. Got message: ';
344
            if (OutputInterface::VERBOSITY_VERY_VERBOSE <= $output->getVerbosity()) {
345
                $message .= $e->getTraceAsString();
346
            } else {
347
                $message .= $e->getMessage();
348
            }
349
            $output->writeln($message);
350
351
            return;
352
        }
353
354
        $configOptions = new \Mage_Core_Model_Config_Options();
355
        $currentVarDir = $configOptions->getVarDir();
356
357
        if ($currentVarDir == $tempVarDir) {
358
            $output->writeln(
359
                sprintf('<warning>Fallback folder %s is used in n98-magerun</warning>', $tempVarDir)
360
            );
361
            $output->writeln('');
362
            $output->writeln(
363
                'n98-magerun is using the fallback folder. If there is another folder configured for Magento, '
364
                . 'this can cause serious problems.'
365
            );
366
            $output->writeln(
367
                'Please refer to https://github.com/netz98/n98-magerun/wiki/File-system-permissions '
368
                . 'for more information.'
369
            );
370
            $output->writeln('');
371
        } else {
372
            $output->writeln(sprintf(
373
                '<warning>Folder %s found, but not used in n98-magerun</warning>',
374
                $tempVarDir
375
            ));
376
            $output->writeln('');
377
            $output->writeln(
378
                sprintf(
379
                    'This might cause serious problems. n98-magerun is using the configured var-folder '
380
                    . '<comment>%s</comment>',
381
                    $currentVarDir
382
                )
383
            );
384
            $output->writeln(
385
                'Please refer to https://github.com/netz98/n98-magerun/wiki/File-system-permissions '
386
                . 'for more information.'
387
            );
388
            $output->writeln('');
389
390
            return false;
391
        }
392
    }
393
394
    /**
395
     * Loads and initializes the Magento application
396
     *
397
     * @return bool false if magento root folder is not set, true otherwise
398
     */
399
    public function initMagento()
400
    {
401
        if ($this->getMagentoRootFolder() !== null) {
402
            if ($this->_magentoMajorVersion == self::MAGENTO_MAJOR_VERSION_2) {
403
                $this->_initMagento2();
404
            } else {
405
                $this->_initMagento1();
406
            }
407
408
            return true;
409
        }
410
411
        return false;
412
    }
413
414
    /**
415
     * @return string
416
     */
417
    public function getHelp()
418
    {
419
        return self::$logo . parent::getHelp();
420
    }
421
422
    public function getLongVersion()
423
    {
424
        return parent::getLongVersion() . ' by <info>netz98 new media GmbH</info>';
425
    }
426
427
    /**
428
     * @return boolean
429
     */
430
    public function isMagentoEnterprise()
431
    {
432
        return $this->_magentoEnterprise;
433
    }
434
435
    /**
436
     * @return string
437
     */
438
    public function getMagentoRootFolder()
439
    {
440
        return $this->_magentoRootFolder;
441
    }
442
443
    /**
444
     * @param string $magentoRootFolder
445
     */
446
    public function setMagentoRootFolder($magentoRootFolder)
447
    {
448
        $this->_magentoRootFolder = $magentoRootFolder;
449
    }
450
451
    /**
452
     * @return int
453
     */
454
    public function getMagentoMajorVersion()
455
    {
456
        return $this->_magentoMajorVersion;
457
    }
458
459
    /**
460
     * @return ClassLoader
461
     */
462
    public function getAutoloader()
463
    {
464
        return $this->autoloader;
465
    }
466
467
    /**
468
     * @param ClassLoader $autoloader
469
     */
470
    public function setAutoloader(ClassLoader $autoloader)
471
    {
472
        $this->autoloader = $autoloader;
473
    }
474
475
    /**
476
     * @return array
477
     */
478
    public function getConfig()
479
    {
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
     * @return boolean
493
     */
494
    public function isMagerunStopFileFound()
495
    {
496
        return $this->_magerunStopFileFound;
497
    }
498
499
    /**
500
     * Runs the current application with possible command aliases
501
     *
502
     * @param InputInterface $input An Input instance
503
     * @param OutputInterface $output An Output instance
504
     *
505
     * @return integer 0 if everything went fine, or an error code
506
     */
507
    public function doRun(InputInterface $input, OutputInterface $output)
508
    {
509
        $event = new Application\Console\Event($this, $input, $output);
510
        $this->dispatcher->dispatch(Events::RUN_BEFORE, $event);
511
512
        /**
513
         * only for compatibility to old versions.
514
         */
515
        $event = new ConsoleEvent(new Command('dummy'), $input, $output);
516
        $this->dispatcher->dispatch('console.run.before', $event);
517
518
        $input = $this->config->checkConfigCommandAlias($input);
519
        if ($output instanceof ConsoleOutput) {
520
            $this->checkVarDir($output->getErrorOutput());
521
        }
522
523
        return parent::doRun($input, $output);
524
    }
525
526
    /**
527
     * @param InputInterface $input [optional]
1 ignored issue
show
Documentation introduced by
Should the type for parameter $input not be null|InputInterface?

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...
528
     * @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...
529
     *
530
     * @return int
531
     */
532
    public function run(InputInterface $input = null, OutputInterface $output = null)
533
    {
534
        if (null === $input) {
535
            $input = new ArgvInput();
536
        }
537
538
        if (null === $output) {
539
            $output = new ConsoleOutput();
540
        }
541
        $this->_addOutputStyles($output);
542
        if ($output instanceof ConsoleOutput) {
543
            $this->_addOutputStyles($output->getErrorOutput());
544
        }
545
546
        $this->configureIO($input, $output);
547
548
        try {
549
            $this->init(array(), $input, $output);
550
        } catch (\Exception $e) {
551
            $output = new ConsoleOutput();
552
            $this->renderException($e, $output);
553
        }
554
555
        $return = parent::run($input, $output);
556
557
        // Fix for no return values -> used in interactive shell to prevent error output
558
        if ($return === null) {
559
            return 0;
560
        }
561
562
        return $return;
563
    }
564
565
    /**
566
     * @param array $initConfig
567
     * @param InputInterface $input
1 ignored issue
show
Documentation introduced by
Should the type for parameter $input not be null|InputInterface?

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...
568
     * @param OutputInterface $output
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...
569
     *
570
     * @return void
571
     */
572
    public function init(array $initConfig = array(), InputInterface $input = null, OutputInterface $output = null)
573
    {
574
        if ($this->_isInitialized) {
575
            return;
576
        }
577
578
        // Suppress DateTime warnings
579
        date_default_timezone_set(@date_default_timezone_get());
580
581
        // Initialize EventDispatcher early
582
        $this->dispatcher = new EventDispatcher();
583
        $this->setDispatcher($this->dispatcher);
584
585
        if (null === $input) {
586
            $input = new ArgvInput();
587
        }
588
589
        if (null === $output) {
590
            $output = new ConsoleOutput();
591
        }
592
593
        if (null !== $this->config) {
594
            throw new UnexpectedValueException(sprintf('Config already initialized'));
595
        }
596
597
        $loadExternalConfig = !$this->_checkSkipConfigOption();
598
599
        $this->config = $config = new Config($initConfig, $this->isPharMode(), $output);
600
        $configLoader = $config->getLoader();
601
        $config->loadPartialConfig($loadExternalConfig);
602
        $this->detectMagento($input, $output);
603
        $configLoader->loadStageTwo($this->_magentoRootFolder, $loadExternalConfig, $this->_magerunStopFileFolder);
604
        $config->load();
605
606
        if ($autoloader = $this->autoloader) {
607
608
            /**
609
             * Include commands shipped by Magento 2 core
610
             */
611
            if (!$this->_checkSkipMagento2CoreCommandsOption()) {
612
                $this->registerMagentoCoreCommands($output);
613
            }
614
615
            $this->config->registerCustomAutoloaders($autoloader);
616
            $this->registerEventSubscribers();
617
            $config->registerCustomCommands($this);
618
        }
619
620
        $this->registerHelpers();
621
622
        $this->_isInitialized = true;
623
    }
624
625
    /**
626
     * @param array $initConfig [optional]
627
     * @param InputInterface $input [optional]
1 ignored issue
show
Documentation introduced by
Should the type for parameter $input not be null|InputInterface?

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...
628
     * @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...
629
     */
630
    public function reinit($initConfig = array(), InputInterface $input = null, OutputInterface $output = null)
631
    {
632
        $this->_isInitialized = false;
633
        $this->config = null;
634
        $this->init($initConfig, $input, $output);
635
    }
636
637
    /**
638
     * @return void
639
     */
640
    protected function registerEventSubscribers()
641
    {
642
        foreach ($this->config->getConfig()['event']['subscriber'] as $subscriberClass) {
643
            $subscriber = new $subscriberClass();
644
            $this->dispatcher->addSubscriber($subscriber);
645
        }
646
    }
647
648
    /**
649
     * @return bool
650
     */
651
    protected function _checkSkipConfigOption()
652
    {
653
        $skipConfigOption = getopt('', array('skip-config'));
654
655
        return count($skipConfigOption) > 0;
656
    }
657
658
    /**
659
     * @return bool
660
     */
661
    protected function _checkSkipMagento2CoreCommandsOption()
662
    {
663
        $skipConfigOption = getopt('', array('skip-core-commands'));
664
665
        getenv('MAGERUN_SKIP_CORE_COMMANDS') && $skipConfigOption[] = 1;
666
667
        return count($skipConfigOption) > 0;
668
    }
669
670
    /**
671
     * @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...
672
     */
673
    protected function _checkRootDirOption()
674
    {
675
        $specialGlobalOptions = getopt('', array('root-dir:'));
676
677
        if (count($specialGlobalOptions) > 0) {
678
            if (isset($specialGlobalOptions['root-dir'][0])
679
                && $specialGlobalOptions['root-dir'][0] == '~'
680
            ) {
681
                $specialGlobalOptions['root-dir'] = OperatingSystem::getHomeDir() .
682
                    substr($specialGlobalOptions['root-dir'], 1);
683
            }
684
            $folder = realpath($specialGlobalOptions['root-dir']);
685
            $this->_directRootDir = true;
686
            if (is_dir($folder)) {
687
                chdir($folder);
688
689
                return;
690
            }
691
        }
692
    }
693
694
    protected function _initMagento1()
695
    {
696
        $magento1Hint = <<<'MAGENTO1HINT'
697
You are running a Magento 1.x instance. This version of n98-magerun is not compatible
698
with Magento 1.x. Please use n98-magerun (version 1) for this shop.
699
700
A current version of the software can be downloaded on github.
701
702
<info>Download with curl
703
------------------</info>
704
705
    <comment>curl -O https://files.magerun.net/n98-magerun.phar</comment>
706
707
<info>Download with wget
708
------------------</info>
709
710
    <comment>wget https://files.magerun.net/n98-magerun.phar</comment>
711
712
MAGENTO1HINT;
713
714
        $output = new ConsoleOutput();
715
716
        $output->writeln(array(
717
            '',
718
            $this->getHelperSet()->get('formatter')->formatBlock('Compatibility Notice', 'bg=blue;fg=white', true),
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Symfony\Component\Console\Helper\HelperInterface as the method formatBlock() does only exist in the following implementations of said interface: Symfony\Component\Console\Helper\FormatterHelper.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
719
            ''
720
        ));
721
722
        $output->writeln($magento1Hint);
723
        exit;
0 ignored issues
show
Coding Style Compatibility introduced by
The method _initMagento1() 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...
724
    }
725
726
    /**
727
     * @return void
728
     */
729
    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...
730
    {
731
        require_once $this->getMagentoRootFolder() . '/app/bootstrap.php';
732
733
        $params = $_SERVER;
734
        $params[\Magento\Store\Model\StoreManager::PARAM_RUN_CODE] = 'admin';
735
        $params[\Magento\Store\Model\Store::CUSTOM_ENTRY_POINT_PARAM] = true;
736
        $params['entryPoint'] = basename(__FILE__);
737
738
        $bootstrap = \Magento\Framework\App\Bootstrap::create(BP, $params);
739
        /** @var \Magento\Framework\App\Cron $app */
740
        $app = $bootstrap->createApplication('N98\Magento\Framework\App\Magerun', []);
741
        /* @var $app \N98\Magento\Framework\App\Magerun */
742
        $app->launch();
743
744
        $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...
745
    }
746
747
    /**
748
     * @return EventDispatcher
749
     */
750
    public function getDispatcher()
751
    {
752
        return $this->dispatcher;
753
    }
754
755
    /**
756
     * @param ConfigurationLoader $configurationLoader
757
     */
758
    public function setConfigurationLoader(ConfigurationLoader $configurationLoader)
759
    {
760
        $this->config->setConfigurationLoader($configurationLoader);
761
    }
762
763
    /**
764
     * @param OutputInterface $output
765
     */
766
    protected function _addOutputStyles(OutputInterface $output)
767
    {
768
        $output->getFormatter()->setStyle('debug', new OutputFormatterStyle('magenta', 'white'));
769
        $output->getFormatter()->setStyle('warning', new OutputFormatterStyle('red', 'yellow', array('bold')));
770
    }
771
772
    /**
773
     * @return ObjectManager
774
     */
775
    public function getObjectManager()
776
    {
777
        return $this->_objectManager;
778
    }
779
}
780