Completed
Pull Request — master (#177)
by
unknown
04:33
created

src/N98/Magento/Application.php (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

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\Console\Events;
10
use N98\Magento\Application\ConfigurationLoader;
11
use N98\Util\Console\Helper\TwigHelper;
12
use N98\Util\Console\Helper\MagentoHelper;
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\InputInterface;
20
use Symfony\Component\Console\Input\InputOption;
21
use Symfony\Component\Console\Output\ConsoleOutput;
22
use Symfony\Component\Console\Output\NullOutput;
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.4';
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
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 \Symfony\Component\Console\Input\InputDefinition|void
143
     */
144
    protected function getDefaultInputDefinition()
145
    {
146
        $inputDefinition = parent::getDefaultInputDefinition();
147
        $rootDirOption   = new InputOption(
148
            '--root-dir',
149
            '',
150
            InputOption::VALUE_OPTIONAL,
151
            'Force magento root dir. No auto detection'
152
        );
153
        $inputDefinition->addOption($rootDirOption);
154
155
        $skipExternalConfig = new InputOption(
156
            '--skip-config',
157
            '',
158
            InputOption::VALUE_OPTIONAL,
159
            'Do not load any custom config.'
160
        );
161
        $inputDefinition->addOption($skipExternalConfig);
162
163
        $skipExternalConfig = new InputOption(
164
            '--skip-root-check',
165
            '',
166
            InputOption::VALUE_OPTIONAL,
167
            'Do not check if n98-magerun runs as root'
168
        );
169
        $inputDefinition->addOption($skipExternalConfig);
170
171
        $skipMagento2CoreCommands = new InputOption(
172
            '--skip-core-commands',
173
            '',
174
            InputOption::VALUE_OPTIONAL,
175
            'Do not include Magento 2 core commands'
176
        );
177
        $inputDefinition->addOption($skipMagento2CoreCommands);
178
179
        return $inputDefinition;
180
    }
181
182
    /**
183
     * Search for magento root folder
184
     *
185
     * @param InputInterface  $input  [optional]
186
     * @param OutputInterface $output [optional]
187
     */
188
    public function detectMagento(InputInterface $input = null, OutputInterface $output = null)
189
    {
190
        // do not detect magento twice
191
        if ($this->_magentoDetected) {
192
            return;
193
        }
194
195
        if ($this->getMagentoRootFolder() === null) {
196
            $this->_checkRootDirOption();
197
            if (function_exists('exec')) {
198
                if (OperatingSystem::isWindows()) {
199
                    $folder = exec('@echo %cd%'); // @TODO not currently tested!!!
200
                } else {
201
                    $folder = exec('pwd');
202
                }
203
            } else {
204
                $folder = getcwd();
205
            }
206
        } else {
207
            $folder = $this->getMagentoRootFolder();
208
        }
209
210
        $this->getHelperSet()->set(new MagentoHelper($input, $output), 'magento');
211
        $magentoHelper = $this->getHelperSet()->get('magento');
212
        /* @var $magentoHelper MagentoHelper */
213
        if (!$this->_directRootDir) {
214
            $subFolders = $this->config->getDetectSubFolders();
215
        } else {
216
            $subFolders = array();
217
        }
218
219
        $this->_magentoDetected = $magentoHelper->detect($folder, $subFolders);
220
        $this->_magentoRootFolder = $magentoHelper->getRootFolder();
221
        $this->_magentoEnterprise = $magentoHelper->isEnterpriseEdition();
222
        $this->_magentoMajorVersion = $magentoHelper->getMajorVersion();
223
        $this->_magerunStopFileFound = $magentoHelper->isMagerunStopFileFound();
224
        $this->_magerunStopFileFolder = $magentoHelper->getMagerunStopFileFolder();
225
    }
226
227
    /**
228
     * Add own helpers to helperset.
229
     *
230
     * @return void
231
     */
232
    protected function registerHelpers()
233
    {
234
        $helperSet = $this->getHelperSet();
235
        $config = $this->config->getConfig();
236
237
        // Twig
238
        $twigBaseDirs = array(
239
            __DIR__ . '/../../../res/twig'
240
        );
241
        if (isset($config['twig']['baseDirs']) && is_array($config['twig']['baseDirs'])) {
242
            $twigBaseDirs = array_merge(array_reverse($config['twig']['baseDirs']), $twigBaseDirs);
243
        }
244
        $helperSet->set(new TwigHelper($twigBaseDirs), 'twig');
245
246
        foreach ($config['helpers'] as $helperName => $helperClass) {
247
            if (class_exists($helperClass)) {
248
                $helperSet->set(new $helperClass(), $helperName);
249
            }
250
        }
251
    }
252
253
    /**
254
     * Try to bootstrap magento 2 and load cli application
255
     *
256
     * @param OutputInterface $output
257
     */
258
    protected function registerMagentoCoreCommands(OutputInterface $output)
259
    {
260
        if ($this->getMagentoRootFolder()) {
261
            // Magento was found -> register core cli commands
262
            require_once $this->getMagentoRootFolder() . '/app/bootstrap.php';
263
264
            $coreCliApplication = new \Magento\Framework\Console\Cli();
265
            $coreCliApplicationCommands = $coreCliApplication->all();
266
267
            foreach ($coreCliApplicationCommands as $coreCliApplicationCommand) {
268
                $this->add($coreCliApplicationCommand);
269
270
                if (OutputInterface::VERBOSITY_DEBUG <= $output->getVerbosity()) {
271
                    $output->writeln(
272
                        '<debug>Added core command </debug><comment>'
273
                        . get_class($coreCliApplicationCommand) . '</comment>'
274
                    );
275
                }
276
            }
277
        }
278
    }
279
280
    /**
281
     * Override standard command registration. We want alias support.
282
     *
283
     * @param \Symfony\Component\Console\Command\Command $command
284
     * @return \Symfony\Component\Console\Command\Command
285
     */
286
    public function add(Command $command)
287
    {
288
        if ($this->config) {
289
            $this->config->registerConfigCommandAlias($command);
290
        }
291
292
        return parent::add($command);
293
    }
294
295
    /**
296
     * @param bool $mode
297
     */
298
    public function setPharMode($mode)
299
    {
300
        $this->_isPharMode = $mode;
301
    }
302
303
    /**
304
     * @return bool
305
     */
306
    public function isPharMode()
307
    {
308
        return $this->_isPharMode;
309
    }
310
311
    /**
312
     * @TODO Move logic into "EventSubscriber"
313
     *
314
     * @param OutputInterface $output
315
     * @return bool
316
     */
317
    public function checkVarDir(OutputInterface $output)
318
    {
319
        if (OutputInterface::VERBOSITY_NORMAL <= $output->getVerbosity()) {
320
            $tempVarDir = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'magento' . DIRECTORY_SEPARATOR . 'var';
321
322
            if (is_dir($tempVarDir)) {
323
                $this->detectMagento(null, $output);
324
                /* If magento is not installed yet, don't check */
325
                if ($this->_magentoRootFolder === null
326
                    || !file_exists($this->_magentoRootFolder . '/app/etc/local.xml')
327
                ) {
328
                    return;
329
                }
330
331
                try {
332
                    $this->initMagento();
333
                } catch (\Exception $e) {
334
                    $message = 'Cannot initialize Magento. Please check your configuration. '
335
                        . 'Some n98-magerun command will not work. Got message: ';
336
                    if (OutputInterface::VERBOSITY_VERY_VERBOSE <= $output->getVerbosity()) {
337
                        $message .= $e->getTraceAsString();
338
                    } else {
339
                        $message .= $e->getMessage();
340
                    }
341
                    $output->writeln($message);
342
343
                    return;
344
                }
345
346
                $configOptions = new \Mage_Core_Model_Config_Options();
347
                $currentVarDir = $configOptions->getVarDir();
348
349
                if ($currentVarDir == $tempVarDir) {
350
                    $output->writeln(sprintf('<warning>Fallback folder %s is used in n98-magerun</warning>',
351
                        $tempVarDir));
352
                    $output->writeln('');
353
                    $output->writeln(
354
                        'n98-magerun is using the fallback folder. If there is another folder configured for Magento, '
355
                        . 'this can cause serious problems.'
356
                    );
357
                    $output->writeln(
358
                        'Please refer to https://github.com/netz98/n98-magerun/wiki/File-system-permissions '
359
                        . 'for more information.'
360
                    );
361
                    $output->writeln('');
362
                } else {
363
                    $output->writeln(sprintf('<warning>Folder %s found, but not used in n98-magerun</warning>',
364
                        $tempVarDir));
365
                    $output->writeln('');
366
                    $output->writeln(
367
                        sprintf(
368
                            'This might cause serious problems. n98-magerun is using the configured var-folder '
369
                            . '<comment>%s</comment>', $currentVarDir
370
                        )
371
                    );
372
                    $output->writeln(
373
                        'Please refer to https://github.com/netz98/n98-magerun/wiki/File-system-permissions '
374
                        . 'for more information.'
375
                    );
376
                    $output->writeln('');
377
378
                    return false;
379
                }
380
            }
381
        }
382
    }
383
384
    public function initMagento()
385
    {
386
        if ($this->getMagentoRootFolder() !== null) {
387
            if ($this->_magentoMajorVersion == self::MAGENTO_MAJOR_VERSION_2) {
388
                $this->_initMagento2();
389
            } else {
390
                $this->_initMagento1();
391
            }
392
393
            return true;
394
        }
395
396
        return false;
397
    }
398
399
    /**
400
     * @return string
401
     */
402
    public function getHelp()
403
    {
404
        return self::$logo . parent::getHelp();
405
    }
406
407
    public function getLongVersion()
408
    {
409
        return parent::getLongVersion() . ' by <info>netz98 new media GmbH</info>';
410
    }
411
412
    /**
413
     * @return boolean
414
     */
415
    public function isMagentoEnterprise()
416
    {
417
        return $this->_magentoEnterprise;
418
    }
419
420
    /**
421
     * @return string
422
     */
423
    public function getMagentoRootFolder()
424
    {
425
        return $this->_magentoRootFolder;
426
    }
427
428
    /**
429
     * @param string $magentoRootFolder
430
     */
431
    public function setMagentoRootFolder($magentoRootFolder)
432
    {
433
        $this->_magentoRootFolder = $magentoRootFolder;
434
    }
435
436
    /**
437
     * @return int
438
     */
439
    public function getMagentoMajorVersion()
440
    {
441
        return $this->_magentoMajorVersion;
442
    }
443
444
    /**
445
     * @return ClassLoader
446
     */
447
    public function getAutoloader()
448
    {
449
        return $this->autoloader;
450
    }
451
452
    /**
453
     * @param ClassLoader $autoloader
454
     */
455
    public function setAutoloader(ClassLoader $autoloader)
456
    {
457
        $this->autoloader = $autoloader;
458
    }
459
460
    /**
461
     * @return array
462
     */
463
    public function getConfig()
464
    {
465
        return $this->config->getConfig();
466
    }
467
468
    /**
469
     * @param array $config
470
     */
471
    public function setConfig($config)
472
    {
473
        $this->config->setConfig($config);
474
    }
475
476
    /**
477
     * @return boolean
478
     */
479
    public function isMagerunStopFileFound()
480
    {
481
        return $this->_magerunStopFileFound;
482
    }
483
484
    /**
485
     * Runs the current application with possible command aliases
486
     *
487
     * @param InputInterface  $input  An Input instance
488
     * @param OutputInterface $output An Output instance
489
     *
490
     * @return integer 0 if everything went fine, or an error code
491
     */
492
    public function doRun(InputInterface $input, OutputInterface $output)
493
    {
494
        $event = new Application\Console\Event($this, $input, $output);
495
        $this->dispatcher->dispatch(Events::RUN_BEFORE, $event);
496
497
        /**
498
         * only for compatibility to old versions.
499
         */
500
        $event = new ConsoleEvent(new Command('dummy'), $input, $output);
501
        $this->dispatcher->dispatch('console.run.before', $event);
502
503
        $input = $this->config->checkConfigCommandAlias($input);
504
        if ($output instanceof ConsoleOutput) {
505
            $this->checkVarDir($output->getErrorOutput());
506
        }
507
508
        if (OutputInterface::VERBOSITY_DEBUG <= $output->getVerbosity()) {
509
            $output->writeln('DEBUG');
510
        }
511
512
        return parent::doRun($input, $output);
513
    }
514
515
    /**
516
     * @param InputInterface  $input  [optional]
517
     * @param OutputInterface $output [optional]
518
     *
519
     * @return int
520
     */
521
    public function run(InputInterface $input = null, OutputInterface $output = null)
522
    {
523
        if (null === $input) {
524
            $input = new ArgvInput();
525
        }
526
527
        if (null === $output) {
528
            $output = new ConsoleOutput();
529
        }
530
        $this->_addOutputStyles($output);
531
        if ($output instanceof ConsoleOutput) {
532
            $this->_addOutputStyles($output->getErrorOutput());
533
        }
534
535
        $this->configureIO($input, $output);
536
537
        try {
538
            $this->init(array(), $input, $output);
539
        } catch (\Exception $e) {
540
            $output = new ConsoleOutput();
541
            $this->renderException($e, $output);
542
        }
543
544
        $return = parent::run($input, $output);
545
546
        // Fix for no return values -> used in interactive shell to prevent error output
547
        if ($return === null) {
548
            return 0;
549
        }
550
551
        return $return;
552
    }
553
554
    /**
555
     * @param array           $initConfig
556
     * @param InputInterface  $input
557
     * @param OutputInterface $output
558
     *
559
     * @return void
560
     */
561
    public function init($initConfig = array(), InputInterface $input = null, OutputInterface $output = null)
562
    {
563
        if (!$this->_isInitialized) {
564
            // Suppress DateTime warnings
565
            date_default_timezone_set(@date_default_timezone_get());
566
567
            $loadExternalConfig = !$this->_checkSkipConfigOption();
568
569
            if ($output === null) {
570
                $output = new NullOutput();
571
            }
572
573
            if (null !== $this->config) {
574
                throw new UnexpectedValueException(sprintf('Config already initialized'));
575
            }
576
577
            $this->config = $config = new Config($initConfig, $this->isPharMode(), $output);
578
            $configLoader = $config->getLoader();
579
            $config->loadPartialConfig($loadExternalConfig);
580
            $this->detectMagento($input, $output);
581
            $configLoader->loadStageTwo($this->_magentoRootFolder, $loadExternalConfig, $this->_magerunStopFileFolder);
582
            $config->load();
583
584
            $this->dispatcher = new EventDispatcher();
585
            $this->setDispatcher($this->dispatcher);
586
587
            if ($autoloader = $this->autoloader) {
588
589
                /**
590
                 * Include commands shipped by Magento 2 core
591
                 */
592
                if (!$this->_checkSkipMagento2CoreCommandsOption()) {
593
                    $this->registerMagentoCoreCommands($output);
594
                }
595
596
                $this->config->registerCustomAutoloaders($autoloader);
597
                $this->registerEventSubscribers();
598
                $config->registerCustomCommands($this);
599
            }
600
            $this->registerHelpers();
601
602
603
            $this->_isInitialized = true;
604
        }
605
    }
606
607
    /**
608
     * @param array           $initConfig [optional]
609
     * @param InputInterface  $input      [optional]
610
     * @param OutputInterface $output     [optional]
611
     */
612
    public function reinit($initConfig = array(), InputInterface $input = null, OutputInterface $output = null)
613
    {
614
        $this->_isInitialized = false;
615
        $this->config = null;
616
        $this->init($initConfig, $input, $output);
617
    }
618
619
    /**
620
     * @return void
621
     */
622
    protected function registerEventSubscribers()
623
    {
624
        foreach ($this->config->getConfig()['event']['subscriber'] as $subscriberClass) {
625
            $subscriber = new $subscriberClass();
626
            $this->dispatcher->addSubscriber($subscriber);
627
        }
628
    }
629
630
    /**
631
     * @return bool
632
     */
633
    protected function _checkSkipConfigOption()
634
    {
635
        $skipConfigOption = getopt('', array('skip-config'));
636
637
        return count($skipConfigOption) > 0;
638
    }
639
640
    /**
641
     * @return bool
642
     */
643
    protected function _checkSkipMagento2CoreCommandsOption()
644
    {
645
        $skipConfigOption = getopt('', array('skip-core-commands'));
646
647
        getenv('MAGERUN_SKIP_CORE_COMMANDS') && $skipConfigOption[] = 1;
648
649
        return count($skipConfigOption) > 0;
650
    }
651
652
    /**
653
     * @return string
654
     */
655
    protected function _checkRootDirOption()
656
    {
657
        $specialGlobalOptions = getopt('', array('root-dir:'));
658
659
        if (count($specialGlobalOptions) > 0) {
660
            if (isset($specialGlobalOptions['root-dir'][0])
661
                && $specialGlobalOptions['root-dir'][0] == '~'
662
            ) {
663
                $specialGlobalOptions['root-dir'] = OperatingSystem::getHomeDir() . substr($specialGlobalOptions['root-dir'],
0 ignored issues
show
This line exceeds maximum limit of 120 characters; contains 125 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
664
                        1);
665
            }
666
            $folder = realpath($specialGlobalOptions['root-dir']);
667
            $this->_directRootDir = true;
668
            if (is_dir($folder)) {
669
                chdir($folder);
670
671
                return;
672
            }
673
        }
674
    }
675
676
    protected function _initMagento1()
677
    {
678
        $magento1Hint = <<<'MAGENTO1HINT'
679
You are running a Magento 1.x instance. This version of n98-magerun is not compatible
680
with Magento 1.x. Please use n98-magerun (version 1) for this shop.
681
682
A current version of the software can be downloaded on github.
683
684
<info>Download with curl
685
------------------</info>
686
687
    <comment>curl -O https://files.magerun.net/n98-magerun.phar</comment>
688
689
<info>Download with wget
690
------------------</info>
691
692
    <comment>wget https://files.magerun.net/n98-magerun.phar</comment>
693
694
MAGENTO1HINT;
695
696
        $output = new ConsoleOutput();
697
698
        $output->writeln(array(
699
            '',
700
            $this->getHelperSet()->get('formatter')->formatBlock('Compatibility Notice', 'bg=blue;fg=white', true),
701
            ''
702
        ));
703
704
        $output->writeln($magento1Hint);
705
        exit;
706
    }
707
708
    /**
709
     * @return void
710
     */
711
    protected function _initMagento2()
712
    {
713
        require_once $this->getMagentoRootFolder() . '/app/bootstrap.php';
714
715
        $params = $_SERVER;
716
        $params[\Magento\Store\Model\StoreManager::PARAM_RUN_CODE] = 'admin';
717
        $params[\Magento\Store\Model\Store::CUSTOM_ENTRY_POINT_PARAM] = true;
718
        $params['entryPoint'] = basename(__FILE__);
719
720
        $bootstrap = \Magento\Framework\App\Bootstrap::create(BP, $params);
721
        /** @var \Magento\Framework\App\Cron $app */
722
        $app = $bootstrap->createApplication('N98\Magento\Framework\App\Magerun', []);
723
        /* @var $app \N98\Magento\Framework\App\Magerun */
724
        $app->launch();
725
726
        $this->_objectManager = $app->getObjectManager();
727
    }
728
729
    /**
730
     * @return EventDispatcher
731
     */
732
    public function getDispatcher()
733
    {
734
        return $this->dispatcher;
735
    }
736
737
    /**
738
     * @param ConfigurationLoader $configurationLoader
739
     */
740
    public function setConfigurationLoader(ConfigurationLoader $configurationLoader)
741
    {
742
        $this->config->setConfigurationLoader($configurationLoader);
743
    }
744
745
    /**
746
     * @param OutputInterface $output
747
     */
748
    protected function _addOutputStyles(OutputInterface $output)
749
    {
750
        $output->getFormatter()->setStyle('debug', new OutputFormatterStyle('magenta', 'white'));
751
        $output->getFormatter()->setStyle('warning', new OutputFormatterStyle('red', 'yellow', array('bold')));
752
    }
753
754
    /**
755
     * @return ObjectManager
756
     */
757
    public function getObjectManager()
758
    {
759
        return $this->_objectManager;
760
    }
761
}
762