Completed
Push — master ( abd676...8fc697 )
by Tom
05:37
created

Application::getAutoloader()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 4
rs 10
cc 1
eloc 2
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\OutputInterface;
24
use Symfony\Component\EventDispatcher\EventDispatcher;
25
use UnexpectedValueException;
26
27
class Application extends BaseApplication
28
{
29
    /**
30
     * @var string
31
     */
32
    const APP_NAME = 'n98-magerun2';
33
34
    /**
35
     * @var string
36
     */
37
    const APP_VERSION = '1.1.12';
38
39
    /**
40
     * @var int
41
     */
42
    const MAGENTO_MAJOR_VERSION_1 = 1;
43
44
    /**
45
     * @var int
46
     */
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
    /**
61
     * @var ClassLoader
62
     */
63
    protected $autoloader;
64
65
    /**
66
     * @var Config
67
     */
68
    protected $config;
69
70
    /**
71
     * @var string
72
     */
73
    protected $_magentoRootFolder = null;
74
75
    /**
76
     * @var bool
77
     */
78
    protected $_magentoEnterprise = false;
79
80
    /**
81
     * @var int
82
     */
83
    protected $_magentoMajorVersion = self::MAGENTO_MAJOR_VERSION_2;
84
85
    /**
86
     * @var EntryPoint
87
     */
88
    protected $_magento2EntryPoint = null;
89
90
    /**
91
     * @var bool
92
     */
93
    protected $_isPharMode = false;
94
95
    /**
96
     * @var bool
97
     */
98
    protected $_magerunStopFileFound = false;
99
100
    /**
101
     * @var string
102
     */
103
    protected $_magerunStopFileFolder = null;
104
105
    /**
106
     * @var bool
107
     */
108
    protected $_isInitialized = false;
109
110
    /**
111
     * @var EventDispatcher
112
     */
113
    protected $dispatcher;
114
115
    /**
116
     * If root dir is set by root-dir option this flag is true
117
     *
118
     * @var bool
119
     */
120
    protected $_directRootDir = false;
121
122
    /**
123
     * @var bool
124
     */
125
    protected $_magentoDetected = false;
126
127
    /**
128
     * @var ObjectManager
129
     */
130
    protected $_objectManager = null;
131
132
    /**
133
     * @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...
134
     */
135
    public function __construct($autoloader = null)
136
    {
137
        $this->autoloader = $autoloader;
138
        parent::__construct(self::APP_NAME, self::APP_VERSION);
139
    }
140
141
    /**
142
     * @return InputDefinition
143
     */
144
    protected function getDefaultInputDefinition()
145
    {
146
        $inputDefinition = parent::getDefaultInputDefinition();
147
148
        /**
149
         * Root dir
150
         */
151
        $rootDirOption = new InputOption(
152
            '--root-dir',
153
            '',
154
            InputOption::VALUE_OPTIONAL,
155
            'Force magento root dir. No auto detection'
156
        );
157
        $inputDefinition->addOption($rootDirOption);
158
159
        /**
160
         * Skip config
161
         */
162
        $skipExternalConfig = new InputOption(
163
            '--skip-config',
164
            '',
165
            InputOption::VALUE_NONE,
166
            'Do not load any custom config.'
167
        );
168
        $inputDefinition->addOption($skipExternalConfig);
169
170
        /**
171
         * Skip root check
172
         */
173
        $skipExternalConfig = new InputOption(
174
            '--skip-root-check',
175
            '',
176
            InputOption::VALUE_NONE,
177
            'Do not check if n98-magerun runs as root'
178
        );
179
        $inputDefinition->addOption($skipExternalConfig);
180
181
        /**
182
         * Skip core commands
183
         */
184
        $skipMagento2CoreCommands = new InputOption(
185
            '--skip-core-commands',
186
            '',
187
            InputOption::VALUE_OPTIONAL,
188
            'Do not include Magento 2 core commands'
189
        );
190
        $inputDefinition->addOption($skipMagento2CoreCommands);
191
192
        return $inputDefinition;
193
    }
194
195
    /**
196
     * Search for magento root folder
197
     *
198
     * @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...
199
     * @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...
200
     * @return void
201
     */
202
    public function detectMagento(InputInterface $input = null, OutputInterface $output = null)
203
    {
204
        // do not detect magento twice
205
        if ($this->_magentoDetected) {
206
            return;
207
        }
208
209
        if ($this->getMagentoRootFolder() === null) {
210
            $this->_checkRootDirOption();
211
            $folder = OperatingSystem::getCwd();
212
        } else {
213
            $folder = $this->getMagentoRootFolder();
214
        }
215
216
        $this->getHelperSet()->set(new MagentoHelper($input, $output), 'magento');
217
        $magentoHelper = $this->getHelperSet()->get('magento');
218
        /* @var $magentoHelper MagentoHelper */
219
        if (!$this->_directRootDir) {
220
            $subFolders = $this->config->getDetectSubFolders();
221
        } else {
222
            $subFolders = array();
223
        }
224
225
        $this->_magentoDetected = $magentoHelper->detect($folder, $subFolders);
226
        $this->_magentoRootFolder = $magentoHelper->getRootFolder();
227
        $this->_magentoEnterprise = $magentoHelper->isEnterpriseEdition();
228
        $this->_magentoMajorVersion = $magentoHelper->getMajorVersion();
229
        $this->_magerunStopFileFound = $magentoHelper->isMagerunStopFileFound();
230
        $this->_magerunStopFileFolder = $magentoHelper->getMagerunStopFileFolder();
231
    }
232
233
    /**
234
     * Add own helpers to helperset.
235
     *
236
     * @return void
237
     */
238
    protected function registerHelpers()
239
    {
240
        $helperSet = $this->getHelperSet();
241
        $config = $this->config->getConfig();
242
243
        // Twig
244
        $twigBaseDirs = array(
245
            __DIR__ . '/../../../res/twig'
246
        );
247
        if (isset($config['twig']['baseDirs']) && is_array($config['twig']['baseDirs'])) {
248
            $twigBaseDirs = array_merge(array_reverse($config['twig']['baseDirs']), $twigBaseDirs);
249
        }
250
        $helperSet->set(new TwigHelper($twigBaseDirs), 'twig');
251
252
        foreach ($config['helpers'] as $helperName => $helperClass) {
253
            if (class_exists($helperClass)) {
254
                $helperSet->set(new $helperClass(), $helperName);
255
            }
256
        }
257
    }
258
259
    /**
260
     * Try to bootstrap magento 2 and load cli application
261
     *
262
     * @param OutputInterface $output
263
     */
264
    protected function registerMagentoCoreCommands(OutputInterface $output)
265
    {
266
        if ($this->getMagentoRootFolder()) {
267
            // Magento was found -> register core cli commands
268
            require_once $this->getMagentoRootFolder() . '/app/bootstrap.php';
269
270
            $coreCliApplication = new \Magento\Framework\Console\Cli();
271
            $coreCliApplicationCommands = $coreCliApplication->all();
272
273
            foreach ($coreCliApplicationCommands as $coreCliApplicationCommand) {
274
                if (OutputInterface::VERBOSITY_DEBUG <= $output->getVerbosity()) {
275
                    $output->writeln(
276
                        sprintf(
277
                            '<debug>Add core command </debug> <info>%s</info> -> <comment>%s</comment>',
278
                            $coreCliApplicationCommand->getName(),
279
                            get_class($coreCliApplicationCommand)
280
                        )
281
                    );
282
                }
283
                $this->add($coreCliApplicationCommand);
284
            }
285
        }
286
    }
287
288
    /**
289
     * Override standard command registration. We want alias support.
290
     *
291
     * @param \Symfony\Component\Console\Command\Command $command
292
     * @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...
293
     */
294
    public function add(Command $command)
295
    {
296
        if ($this->config) {
297
            $this->config->registerConfigCommandAlias($command);
298
        }
299
300
        return parent::add($command);
301
    }
302
303
    /**
304
     * @param bool $mode
305
     */
306
    public function setPharMode($mode)
307
    {
308
        $this->_isPharMode = $mode;
309
    }
310
311
    /**
312
     * @return bool
313
     */
314
    public function isPharMode()
315
    {
316
        return $this->_isPharMode;
317
    }
318
319
    /**
320
     * @TODO Move logic into "EventSubscriber"
321
     *
322
     * @param OutputInterface $output
323
     * @return null|false
324
     */
325
    public function checkVarDir(OutputInterface $output)
326
    {
327
        $tempVarDir = sys_get_temp_dir() . '/magento/var';
328
        if (!OutputInterface::VERBOSITY_NORMAL <= $output->getVerbosity() && !is_dir($tempVarDir)) {
329
            return;
330
        }
331
332
        $this->detectMagento(null, $output);
333
        /* If magento is not installed yet, don't check */
334
        if ($this->_magentoRootFolder === null
335
            || !file_exists($this->_magentoRootFolder . '/app/etc/local.xml')
336
        ) {
337
            return;
338
        }
339
340
        try {
341
            $this->initMagento();
342
        } catch (\Exception $e) {
343
            $message = 'Cannot initialize Magento. Please check your configuration. '
344
                . 'Some n98-magerun command will not work. Got message: ';
345
            if (OutputInterface::VERBOSITY_VERY_VERBOSE <= $output->getVerbosity()) {
346
                $message .= $e->getTraceAsString();
347
            } else {
348
                $message .= $e->getMessage();
349
            }
350
            $output->writeln($message);
351
352
            return;
353
        }
354
355
        $configOptions = new \Mage_Core_Model_Config_Options();
356
        $currentVarDir = $configOptions->getVarDir();
357
358
        if ($currentVarDir == $tempVarDir) {
359
            $output->writeln(
360
                sprintf('<warning>Fallback folder %s is used in n98-magerun</warning>', $tempVarDir)
361
            );
362
            $output->writeln('');
363
            $output->writeln(
364
                'n98-magerun is using the fallback folder. If there is another folder configured for Magento, '
365
                . 'this can cause serious problems.'
366
            );
367
            $output->writeln(
368
                'Please refer to https://github.com/netz98/n98-magerun/wiki/File-system-permissions '
369
                . 'for more information.'
370
            );
371
            $output->writeln('');
372
        } else {
373
            $output->writeln(sprintf(
374
                '<warning>Folder %s found, but not used in n98-magerun</warning>',
375
                $tempVarDir
376
            ));
377
            $output->writeln('');
378
            $output->writeln(
379
                sprintf(
380
                    'This might cause serious problems. n98-magerun is using the configured var-folder '
381
                    . '<comment>%s</comment>',
382
                    $currentVarDir
383
                )
384
            );
385
            $output->writeln(
386
                'Please refer to https://github.com/netz98/n98-magerun/wiki/File-system-permissions '
387
                . 'for more information.'
388
            );
389
            $output->writeln('');
390
391
            return false;
392
        }
393
    }
394
395
    /**
396
     * Loads and initializes the Magento application
397
     *
398
     * @return bool false if magento root folder is not set, true otherwise
399
     */
400
    public function initMagento()
401
    {
402
        if ($this->getMagentoRootFolder() !== null) {
403
            if ($this->_magentoMajorVersion == self::MAGENTO_MAJOR_VERSION_2) {
404
                $this->_initMagento2();
405
            } else {
406
                $this->_initMagento1();
407
            }
408
409
            return true;
410
        }
411
412
        return false;
413
    }
414
415
    /**
416
     * @return string
417
     */
418
    public function getHelp()
419
    {
420
        return self::$logo . parent::getHelp();
421
    }
422
423
    public function getLongVersion()
424
    {
425
        return parent::getLongVersion() . ' by <info>netz98 new media GmbH</info>';
426
    }
427
428
    /**
429
     * @return boolean
430
     */
431
    public function isMagentoEnterprise()
432
    {
433
        return $this->_magentoEnterprise;
434
    }
435
436
    /**
437
     * @return string
438
     */
439
    public function getMagentoRootFolder()
440
    {
441
        return $this->_magentoRootFolder;
442
    }
443
444
    /**
445
     * @param string $magentoRootFolder
446
     */
447
    public function setMagentoRootFolder($magentoRootFolder)
448
    {
449
        $this->_magentoRootFolder = $magentoRootFolder;
450
    }
451
452
    /**
453
     * @return int
454
     */
455
    public function getMagentoMajorVersion()
456
    {
457
        return $this->_magentoMajorVersion;
458
    }
459
460
    /**
461
     * @return ClassLoader
462
     */
463
    public function getAutoloader()
464
    {
465
        return $this->autoloader;
466
    }
467
468
    /**
469
     * @param ClassLoader $autoloader
470
     */
471
    public function setAutoloader(ClassLoader $autoloader)
472
    {
473
        $this->autoloader = $autoloader;
474
    }
475
476
    /**
477
     * @return array
478
     */
479
    public function getConfig()
480
    {
481
        return $this->config->getConfig();
482
    }
483
484
    /**
485
     * @param array $config
486
     */
487
    public function setConfig($config)
488
    {
489
        $this->config->setConfig($config);
490
    }
491
492
    /**
493
     * @return boolean
494
     */
495
    public function isMagerunStopFileFound()
496
    {
497
        return $this->_magerunStopFileFound;
498
    }
499
500
    /**
501
     * Runs the current application with possible command aliases
502
     *
503
     * @param InputInterface $input An Input instance
504
     * @param OutputInterface $output An Output instance
505
     *
506
     * @return integer 0 if everything went fine, or an error code
507
     */
508
    public function doRun(InputInterface $input, OutputInterface $output)
509
    {
510
        $event = new Application\Console\Event($this, $input, $output);
511
        $this->dispatcher->dispatch(Events::RUN_BEFORE, $event);
512
513
        /**
514
         * only for compatibility to old versions.
515
         */
516
        $event = new ConsoleEvent(new Command('dummy'), $input, $output);
517
        $this->dispatcher->dispatch('console.run.before', $event);
518
519
        $input = $this->config->checkConfigCommandAlias($input);
520
        if ($output instanceof ConsoleOutput) {
521
            $this->checkVarDir($output->getErrorOutput());
522
        }
523
524
        return parent::doRun($input, $output);
525
    }
526
527
    /**
528
     * @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...
529
     * @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...
530
     *
531
     * @return int
532
     */
533
    public function run(InputInterface $input = null, OutputInterface $output = null)
534
    {
535
        if (null === $input) {
536
            $input = new ArgvInput();
537
        }
538
539
        if (null === $output) {
540
            $output = new ConsoleOutput();
541
        }
542
        $this->_addOutputStyles($output);
543
        if ($output instanceof ConsoleOutput) {
544
            $this->_addOutputStyles($output->getErrorOutput());
545
        }
546
547
        $this->configureIO($input, $output);
548
549
        try {
550
            $this->init(array(), $input, $output);
551
        } catch (\Exception $e) {
552
            $output = new ConsoleOutput();
553
            $this->renderException($e, $output);
554
        }
555
556
        $return = parent::run($input, $output);
557
558
        // Fix for no return values -> used in interactive shell to prevent error output
559
        if ($return === null) {
560
            return 0;
561
        }
562
563
        return $return;
564
    }
565
566
    /**
567
     * @param array $initConfig
568
     * @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...
569
     * @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...
570
     *
571
     * @return void
572
     */
573
    public function init(array $initConfig = array(), InputInterface $input = null, OutputInterface $output = null)
574
    {
575
        if ($this->_isInitialized) {
576
            return;
577
        }
578
579
        // Suppress DateTime warnings
580
        date_default_timezone_set(@date_default_timezone_get());
581
582
        // Initialize EventDispatcher early
583
        $this->dispatcher = new EventDispatcher();
584
        $this->setDispatcher($this->dispatcher);
585
586
        if (null === $input) {
587
            $input = new ArgvInput();
588
        }
589
590
        if (null === $output) {
591
            $output = new ConsoleOutput();
592
        }
593
594
        if (null !== $this->config) {
595
            throw new UnexpectedValueException(sprintf('Config already initialized'));
596
        }
597
598
        $loadExternalConfig = !$this->_checkSkipConfigOption();
599
600
        $this->config = $config = new Config($initConfig, $this->isPharMode(), $output);
601
        $configLoader = $config->getLoader();
602
        $config->loadPartialConfig($loadExternalConfig);
603
        $this->detectMagento($input, $output);
604
        $configLoader->loadStageTwo($this->_magentoRootFolder, $loadExternalConfig, $this->_magerunStopFileFolder);
605
        $config->load();
606
607
        if ($autoloader = $this->autoloader) {
608
609
            /**
610
             * Include commands shipped by Magento 2 core
611
             */
612
            if (!$this->_checkSkipMagento2CoreCommandsOption()) {
613
                $this->registerMagentoCoreCommands($output);
614
            }
615
616
            $this->config->registerCustomAutoloaders($autoloader);
617
            $this->registerEventSubscribers();
618
            $config->registerCustomCommands($this);
619
        }
620
621
        $this->registerHelpers();
622
623
        $this->_isInitialized = true;
624
    }
625
626
    /**
627
     * @param array $initConfig [optional]
628
     * @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...
629
     * @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...
630
     */
631
    public function reinit($initConfig = array(), InputInterface $input = null, OutputInterface $output = null)
632
    {
633
        $this->_isInitialized = false;
634
        $this->config = null;
635
        $this->init($initConfig, $input, $output);
636
    }
637
638
    /**
639
     * @return void
640
     */
641
    protected function registerEventSubscribers()
642
    {
643
        foreach ($this->config->getConfig()['event']['subscriber'] as $subscriberClass) {
644
            $subscriber = new $subscriberClass();
645
            $this->dispatcher->addSubscriber($subscriber);
646
        }
647
    }
648
649
    /**
650
     * @return bool
651
     */
652
    protected function _checkSkipConfigOption()
653
    {
654
        $skipConfigOption = getopt('', array('skip-config'));
655
656
        return count($skipConfigOption) > 0;
657
    }
658
659
    /**
660
     * @return bool
661
     */
662
    protected function _checkSkipMagento2CoreCommandsOption()
663
    {
664
        $skipConfigOption = getopt('', array('skip-core-commands'));
665
666
        getenv('MAGERUN_SKIP_CORE_COMMANDS') && $skipConfigOption[] = 1;
667
668
        return count($skipConfigOption) > 0;
669
    }
670
671
    /**
672
     * @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...
673
     */
674
    protected function _checkRootDirOption()
675
    {
676
        $specialGlobalOptions = getopt('', array('root-dir:'));
677
678
        if (count($specialGlobalOptions) > 0) {
679
            if (isset($specialGlobalOptions['root-dir'][0])
680
                && $specialGlobalOptions['root-dir'][0] == '~'
681
            ) {
682
                $specialGlobalOptions['root-dir'] = OperatingSystem::getHomeDir() .
683
                    substr($specialGlobalOptions['root-dir'], 1);
684
            }
685
            $folder = realpath($specialGlobalOptions['root-dir']);
686
            $this->_directRootDir = true;
687
            if (is_dir($folder)) {
688
                chdir($folder);
689
690
                return;
691
            }
692
        }
693
    }
694
695
    protected function _initMagento1()
696
    {
697
        $magento1Hint = <<<'MAGENTO1HINT'
698
You are running a Magento 1.x instance. This version of n98-magerun is not compatible
699
with Magento 1.x. Please use n98-magerun (version 1) for this shop.
700
701
A current version of the software can be downloaded on github.
702
703
<info>Download with curl
704
------------------</info>
705
706
    <comment>curl -O https://files.magerun.net/n98-magerun.phar</comment>
707
708
<info>Download with wget
709
------------------</info>
710
711
    <comment>wget https://files.magerun.net/n98-magerun.phar</comment>
712
713
MAGENTO1HINT;
714
715
        $output = new ConsoleOutput();
716
717
        $output->writeln(array(
718
            '',
719
            $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...
720
            ''
721
        ));
722
723
        $output->writeln($magento1Hint);
724
        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...
725
    }
726
727
    /**
728
     * @return void
729
     */
730
    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...
731
    {
732
        require_once $this->getMagentoRootFolder() . '/app/bootstrap.php';
733
734
        $params = $_SERVER;
735
        $params[\Magento\Store\Model\StoreManager::PARAM_RUN_CODE] = 'admin';
736
        $params[\Magento\Store\Model\Store::CUSTOM_ENTRY_POINT_PARAM] = true;
737
        $params['entryPoint'] = basename(__FILE__);
738
739
        $bootstrap = \Magento\Framework\App\Bootstrap::create(BP, $params);
740
        /** @var \Magento\Framework\App\Cron $app */
741
        $app = $bootstrap->createApplication('N98\Magento\Framework\App\Magerun', []);
742
        /* @var $app \N98\Magento\Framework\App\Magerun */
743
        $app->launch();
744
745
        $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...
746
    }
747
748
    /**
749
     * @return EventDispatcher
750
     */
751
    public function getDispatcher()
752
    {
753
        return $this->dispatcher;
754
    }
755
756
    /**
757
     * @param ConfigurationLoader $configurationLoader
758
     */
759
    public function setConfigurationLoader(ConfigurationLoader $configurationLoader)
760
    {
761
        $this->config->setConfigurationLoader($configurationLoader);
762
    }
763
764
    /**
765
     * @param OutputInterface $output
766
     */
767
    protected function _addOutputStyles(OutputInterface $output)
768
    {
769
        $output->getFormatter()->setStyle('debug', new OutputFormatterStyle('magenta', 'white'));
770
        $output->getFormatter()->setStyle('warning', new OutputFormatterStyle('red', 'yellow', array('bold')));
771
    }
772
773
    /**
774
     * @return ObjectManager
775
     */
776
    public function getObjectManager()
777
    {
778
        return $this->_objectManager;
779
    }
780
}
781