Completed
Push — master ( 9752f3...c8a0ff )
by Christian
02:37
created

Application::preloadClassesBeforeMagentoCore()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 6
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 0
1
<?php
2
3
namespace N98\Magento;
4
5
use BadMethodCallException;
6
use Composer\Autoload\ClassLoader;
7
use Exception;
8
use Magento\Framework\ObjectManagerInterface;
9
use N98\Magento\Application\ApplicationAwareInterface;
10
use N98\Magento\Application\Config;
11
use N98\Magento\Application\ConfigurationLoader;
12
use N98\Magento\Application\Console\Events;
13
use N98\Magento\Application\DetectionResult;
14
use N98\Magento\Application\Magento1Initializer;
15
use N98\Magento\Application\Magento2Initializer;
16
use N98\Magento\Application\MagentoDetector;
17
use N98\Util\Console\Helper\TwigHelper;
18
use Symfony\Component\Console\Application as BaseApplication;
19
use Symfony\Component\Console\Command\Command;
20
use Symfony\Component\Console\Event\ConsoleEvent;
21
use Symfony\Component\Console\Formatter\OutputFormatterStyle;
22
use Symfony\Component\Console\Input\ArgvInput;
23
use Symfony\Component\Console\Input\InputDefinition;
24
use Symfony\Component\Console\Input\InputInterface;
25
use Symfony\Component\Console\Input\InputOption;
26
use Symfony\Component\Console\Output\ConsoleOutput;
27
use Symfony\Component\Console\Output\OutputInterface;
28
use Symfony\Component\EventDispatcher\EventDispatcher;
29
use UnexpectedValueException;
30
31
/**
32
 * Class Application
33
 * @package N98\Magento
34
 */
35
class Application extends BaseApplication
36
{
37
    /**
38
     * @var string
39
     */
40
    const APP_NAME = 'n98-magerun2';
41
42
    /**
43
     * @var string
44
     */
45
    const APP_VERSION = '4.0.4';
46
47
    /**
48
     * @var int
49
     */
50
    const MAGENTO_MAJOR_VERSION_1 = 1;
51
    const MAGENTO_MAJOR_VERSION_2 = 2;
52
53
    /**
54
     * @var string
55
     */
56
    private static $logo = "
57
     ___ ___                                       ___
58
 _ _/ _ ( _ )___ _ __  __ _ __ _ ___ _ _ _  _ _ _ |_  )
59
| ' \\_, / _ \\___| '  \\/ _` / _` / -_) '_| || | ' \\ / /
60
|_||_/_/\\___/   |_|_|_\\__,_\\__, \\___|_|  \\_,_|_||_/___|
61
                           |___/
62
";
63
    /**
64
     * @var ClassLoader
65
     */
66
    protected $autoloader;
67
68
    /**
69
     * @var Config
70
     */
71
    protected $config;
72
73
    /**
74
     * @var bool
75
     */
76
    protected $_isPharMode = false;
77
78
    /**
79
     * @var bool
80
     */
81
    protected $_isInitialized = false;
82
83
    /**
84
     * @var EventDispatcher
85
     */
86
    protected $dispatcher;
87
88
    /**
89
     * @var ObjectManagerInterface
90
     */
91
    protected $_objectManager;
92
93
    /**
94
     * @see \N98\Magento\Application::setConfigurationLoader()
95
     * @var ConfigurationLoader
96
     */
97
    private $configurationLoaderInjected;
98
99
    /**
100
     * @var string [optional] root folder not detected, but set via public setter
101
     * @see setMagentoRootFolder()
102
     */
103
    private $magentoRootFolderInjected;
104
105
    /**
106
     * @var int Magento Major Version to operate on by this Magerun application
107
     */
108
    private $magerunMajorVersion = self::MAGENTO_MAJOR_VERSION_2;
109
110
    /**
111
     * @var DetectionResult of the Magento application (e.g. v1/v2, Enterprise/Community, root-path)
112
     */
113
    private $detectionResult;
114
115
    /**
116
     * @var boolean
117
     */
118
    private $autoExit = true;
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
119
120
    /**
121
     * @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...
122
     */
123
    public function __construct($autoloader = null)
124
    {
125
        $this->autoloader = $autoloader;
126
        parent::__construct(self::APP_NAME, self::APP_VERSION);
127
128
        $this->preloadClassesBeforeMagentoCore();
129
    }
130
131
    /**
132
     * Sets whether to automatically exit after a command execution or not.
133
     *
134
     * Implemented on this level to allow early exit on configuration exceptions
135
     *
136
     * @see run()
137
     *
138
     * @param bool $boolean Whether to automatically exit after a command execution or not
139
     */
140
    public function setAutoExit($boolean)
141
    {
142
        $this->autoExit = (bool) $boolean;
143
        parent::setAutoExit($boolean);
144
    }
145
146
    /**
147
     * @param bool $mode
148
     */
149
    public function setPharMode($mode)
150
    {
151
        $this->_isPharMode = $mode;
152
    }
153
154
    /**
155
     * @return string
156
     */
157
    public function getHelp()
158
    {
159
        return self::$logo . parent::getHelp();
160
    }
161
162
    public function getLongVersion()
163
    {
164
        return parent::getLongVersion() . ' by <info>netz98 GmbH</info>';
165
    }
166
167
    /**
168
     * @return boolean
169
     */
170
    public function isMagentoEnterprise()
171
    {
172
        return $this->detectionResult->isEnterpriseEdition();
173
    }
174
175
    /**
176
     * @param string $magentoRootFolder
177
     */
178
    public function setMagentoRootFolder($magentoRootFolder)
179
    {
180
        $this->magentoRootFolderInjected = $magentoRootFolder;
181
    }
182
183
    /**
184
     * @return int|null
185
     */
186
    public function getMagentoMajorVersion()
187
    {
188
        return $this->detectionResult ? $this->detectionResult->getMajorVersion() : null;
189
    }
190
191
    /**
192
     * @return array
193
     */
194
    public function getConfig()
195
    {
196
        // TODO(TK) getter for config / getter for config array
197
        return $this->config->getConfig();
198
    }
199
200
    /**
201
     * @param array $config
202
     */
203
    public function setConfig($config)
204
    {
205
        $this->config->setConfig($config);
206
    }
207
208
    /**
209
     * Runs the current application with possible command aliases
210
     *
211
     * @param InputInterface $input An Input instance
212
     * @param OutputInterface $output An Output instance
213
     *
214
     * @return int 0 if everything went fine, or an error code
215
     * @throws \Magento\Framework\Exception\FileSystemException
216
     * @throws \Exception
217
     * @throws \Throwable
218
     */
219
    public function doRun(InputInterface $input, OutputInterface $output)
220
    {
221
        $input = $this->config->checkConfigCommandAlias($input);
222
223
        $event = new ConsoleEvent(new \N98\Magento\Command\DummyCommand(), $input, $output);
224
        $this->dispatcher->dispatch($event, Events::RUN_BEFORE);
225
226
        return parent::doRun($input, $output);
227
    }
228
229
    /**
230
     * Loads and initializes the Magento application
231
     *
232
     * @param bool $soft
233
     *
234
     * @return bool false if magento root folder is not set, true otherwise
235
     * @throws \Exception
236
     */
237
    public function initMagento($soft = false)
0 ignored issues
show
Unused Code introduced by
The parameter $soft is not used and could be removed.

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

Loading history...
238
    {
239
        if ($this->getMagentoRootFolder(true) === null) {
240
            return false;
241
        }
242
243
        $isMagento2 = $this->detectionResult->getMajorVersion() === self::MAGENTO_MAJOR_VERSION_2;
244
        if ($isMagento2) {
245
            $magento2Initializer = new Magento2Initializer($this->getAutoloader());
246
            $app = $magento2Initializer->init($this->getMagentoRootFolder());
247
            $this->_objectManager = $app->getObjectManager();
248
        } else {
249
            $magento1Initializer = new Magento1Initializer($this->getHelperSet());
250
            $magento1Initializer->init();
251
        }
252
253
        return true;
254
    }
255
256
    /**
257
     * @param bool $preventException [optional] on uninitialized magento root folder (returns null then, caution!)
258
     * @return string|null
259
     */
260
    public function getMagentoRootFolder($preventException = false)
261
    {
262
        if (null !== $this->magentoRootFolderInjected) {
263
            return $this->magentoRootFolderInjected;
264
        }
265
266
        if ($preventException) {
267
            return $this->detectionResult ? $this->detectionResult->getRootFolder() : null;
268
        }
269
270
        if (!$this->detectionResult) {
271
            throw new BadMethodCallException('Magento-root-folder is not yet detected (nor set)');
272
        }
273
274
        return $this->detectionResult->getRootFolder();
275
    }
276
277
    /**
278
     * @return ClassLoader
279
     */
280
    public function getAutoloader()
281
    {
282
        return $this->autoloader;
283
    }
284
285
    /**
286
     * @param ClassLoader $autoloader
287
     */
288
    public function setAutoloader(ClassLoader $autoloader)
289
    {
290
        $this->autoloader = $autoloader;
291
    }
292
293
    /**
294
     * @param InputInterface $input [optional]
295
     * @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...
296
     *
297
     * @return int
0 ignored issues
show
Documentation introduced by
Should the return type not be null|integer?

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

Loading history...
298
     * @throws \Exception
299
     */
300
    public function run(InputInterface $input = null, OutputInterface $output = null)
301
    {
302
        if (null === $input) {
303
            $input = new ArgvInput();
304
        }
305
306
        if (null === $output) {
307
            $output = new ConsoleOutput();
308
        }
309
        $this->_addOutputStyles($output);
310
        if ($output instanceof ConsoleOutput) {
311
            $this->_addOutputStyles($output->getErrorOutput());
312
        }
313
314
        $this->configureIO($input, $output);
315
316
        try {
317
            $this->init([], $input, $output);
318
        } catch (Exception $e) {
319
            $output = new ConsoleOutput();
320
            $this->renderThrowable($e, $output->getErrorOutput());
321
            $exitCode = max(1, min(255, (int) $e->getCode()));
322
            if ($this->autoExit) {
323
                die($exitCode);
324
            }
325
326
            return $exitCode;
327
        }
328
329
        $return = parent::run($input, $output);
330
331
        // Fix for no return values -> used in interactive shell to prevent error output
332
        if ($return === null) {
333
            return 0;
334
        }
335
336
        return $return;
337
    }
338
339
    /**
340
     * @param OutputInterface $output
341
     */
342
    protected function _addOutputStyles(OutputInterface $output)
343
    {
344
        $output->getFormatter()->setStyle('debug', new OutputFormatterStyle('magenta', 'white'));
345
        $output->getFormatter()->setStyle('warning', new OutputFormatterStyle('red', 'yellow', ['bold']));
346
    }
347
348
    /**
349
     * @param array $initConfig [optional]
350
     * @param InputInterface $input [optional]
351
     * @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...
352
     *
353
     * @return void
354
     * @throws \Exception
355
     */
356
    public function init(array $initConfig = [], InputInterface $input = null, OutputInterface $output = null)
357
    {
358
        if ($this->_isInitialized) {
359
            return;
360
        }
361
362
        // Suppress DateTime warnings
363
        date_default_timezone_set(@date_default_timezone_get());
364
365
        // Initialize EventDispatcher early
366
        $this->dispatcher = new EventDispatcher();
367
        $this->setDispatcher($this->dispatcher);
368
369
        $input = $input ?: new ArgvInput();
370
        $output = $output ?: new ConsoleOutput();
371
372
        if (null !== $this->config) {
373
            throw new UnexpectedValueException(sprintf('Config already initialized'));
374
        }
375
376
        $loadExternalConfig = !$this->_checkSkipConfigOption($input);
377
378
        $this->config = new Config($initConfig, $this->isPharMode(), $output);
379
        if ($this->configurationLoaderInjected) {
380
            $this->config->setLoader($this->configurationLoaderInjected);
381
        }
382
        $this->config->loadPartialConfig($loadExternalConfig);
383
        $this->detectMagento($input, $output);
384
385
        $configLoader = $this->config->getLoader();
386
        $configLoader->loadStageTwo(
387
            $this->getMagentoRootFolder(true),
388
            $loadExternalConfig,
389
            $this->detectionResult->getMagerunStopFileFolder()
390
        );
391
        $this->config->load();
392
393
        if ($autoloader = $this->autoloader) {
394
            /**
395
             * Include commands shipped by Magento 2 core
396
             */
397
            if (!$this->_checkSkipMagento2CoreCommandsOption($input)) {
398
                $this->registerMagentoCoreCommands($output);
399
            }
400
            $this->config->registerCustomAutoloaders($autoloader);
401
            $this->registerEventSubscribers($input, $output);
402
            $this->config->registerCustomCommands($this);
403
        }
404
405
        $this->registerHelpers();
406
407
        $this->_isInitialized = true;
408
    }
409
410
    /**
411
     * @param InputInterface $input
412
     * @return bool
413
     */
414
    protected function _checkSkipConfigOption(InputInterface $input)
415
    {
416
        return $input->hasParameterOption('--skip-config');
417
    }
418
419
    /**
420
     * @return bool
421
     */
422
    public function isPharMode()
423
    {
424
        return $this->_isPharMode;
425
    }
426
427
    /**
428
     * Search for magento root folder
429
     *
430
     * @param InputInterface $input [optional]
431
     * @param OutputInterface $output [optional]
432
     * @return void
433
     * @throws \Exception
434
     */
435
    public function detectMagento(InputInterface $input = null, OutputInterface $output = null)
436
    {
437
        if ($this->detectionResult) {
438
            return;
439
        }
440
441
        $magentoRootDirectory = $this->getMagentoRootFolder(true);
442
443
        $detector = new MagentoDetector();
444
        $this->detectionResult = $detector->detect(
445
            $input,
0 ignored issues
show
Bug introduced by
It seems like $input defined by parameter $input on line 435 can be null; however, N98\Magento\Application\MagentoDetector::detect() does not accept null, maybe add an additional type check?

It seems like you allow that null is being passed for a parameter, however the function which is called does not seem to accept null.

We recommend to add an additional type check (or disallow null for the parameter):

function notNullable(stdClass $x) { }

// Unsafe
function withoutCheck(stdClass $x = null) {
    notNullable($x);
}

// Safe - Alternative 1: Adding Additional Type-Check
function withCheck(stdClass $x = null) {
    if ($x instanceof stdClass) {
        notNullable($x);
    }
}

// Safe - Alternative 2: Changing Parameter
function withNonNullableParam(stdClass $x) {
    notNullable($x);
}
Loading history...
446
            $output,
0 ignored issues
show
Bug introduced by
It seems like $output defined by parameter $output on line 435 can be null; however, N98\Magento\Application\MagentoDetector::detect() does not accept null, maybe add an additional type check?

It seems like you allow that null is being passed for a parameter, however the function which is called does not seem to accept null.

We recommend to add an additional type check (or disallow null for the parameter):

function notNullable(stdClass $x) { }

// Unsafe
function withoutCheck(stdClass $x = null) {
    notNullable($x);
}

// Safe - Alternative 1: Adding Additional Type-Check
function withCheck(stdClass $x = null) {
    if ($x instanceof stdClass) {
        notNullable($x);
    }
}

// Safe - Alternative 2: Changing Parameter
function withNonNullableParam(stdClass $x) {
    notNullable($x);
}
Loading history...
447
            $this->config,
448
            $this->getHelperSet(),
449
            $magentoRootDirectory
450
        );
451
452
        if ($this->detectionResult->isDetected()) {
453
            $magentoMajorVersion = $this->detectionResult->getMajorVersion();
454
            if ($magentoMajorVersion !== $this->magerunMajorVersion) {
455
                $magento1Initialiter = new Magento1Initializer($this->getHelperSet());
456
                $magento1Initialiter->init();
457
            }
458
        }
459
    }
460
461
    /**
462
     * @return bool
463
     */
464
    protected function _checkSkipMagento2CoreCommandsOption(InputInterface $input)
465
    {
466
        return $input->hasParameterOption('--skip-core-commands') || getenv('MAGERUN_SKIP_CORE_COMMANDS');
467
    }
468
469
    /**
470
     * Try to bootstrap magento 2 and load cli application
471
     *
472
     * @param OutputInterface $output
473
     */
474
    protected function registerMagentoCoreCommands(OutputInterface $output)
475
    {
476
        $magentoRootFolder = $this->getMagentoRootFolder();
477
        if (0 === strlen($magentoRootFolder)) {
478
            return;
479
        }
480
481
        // Magento was found -> register core cli commands
482
        try {
483
            $this->requireOnce($magentoRootFolder . '/app/bootstrap.php');
484
485
            // Magento 2.3.1 removes phar stream wrapper.
486
            if (!in_array('phar', \stream_get_wrappers(), true)) {
487
                \stream_wrapper_restore('phar');
488
            }
489
        } catch (\Exception $ex) {
490
            $this->renderThrowable($ex, $output);
491
            $output->writeln(
492
                '<info>Use --skip-core-commands to not require the Magento app/bootstrap.php which caused ' .
493
                'the exception.</info>'
494
            );
495
496
            return;
497
        }
498
499
        $coreCliApplication = new \Magento\Framework\Console\Cli();
500
        $coreCliApplicationCommands = $coreCliApplication->all();
501
502
        foreach ($coreCliApplicationCommands as $coreCliApplicationCommand) {
503
            if (OutputInterface::VERBOSITY_DEBUG <= $output->getVerbosity()) {
504
                $output->writeln(
505
                    sprintf(
506
                        '<debug>Add core command </debug> <info>%s</info> -> <comment>%s</comment>',
507
                        $coreCliApplicationCommand->getName(),
508
                        get_class($coreCliApplicationCommand)
509
                    )
510
                );
511
            }
512
            $this->add($coreCliApplicationCommand);
513
        }
514
    }
515
516
    /**
517
     * use require-once inside a function with it's own variable scope w/o any other variables
518
     * and $this unbound.
519
     *
520
     * @param string $path
521
     */
522 View Code Duplication
    private function requireOnce($path)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
523
    {
524
        $requireOnce = function () {
525
            require_once func_get_arg(0);
526
        };
527
        if (50400 <= PHP_VERSION_ID) {
528
            $requireOnce->bindTo(null);
529
        }
530
531
        $requireOnce($path);
532
    }
533
534
    /**
535
     * Override standard command registration. We want alias support.
536
     *
537
     * @param Command $command
538
     *
539
     * @return Command
0 ignored issues
show
Documentation introduced by
Should the return type not be Command|null?

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

Loading history...
540
     */
541
    public function add(Command $command)
542
    {
543
        if ($this->config) {
544
            $this->config->registerConfigCommandAlias($command);
545
        }
546
547
        return parent::add($command);
548
    }
549
550
    /**
551
     * @return void
552
     */
553
    protected function registerEventSubscribers(InputInterface $input, OutputInterface $output)
554
    {
555
        $config = $this->config->getConfig();
556
557
        if (!isset($config['event']['subscriber'])) {
558
            return;
559
        }
560
561
        $subscriberClasses = $config['event']['subscriber'];
562
        foreach ($subscriberClasses as $subscriberClass) {
563
            $subscriber = new $subscriberClass($this, $input, $output);
564
565
            if ($subscriber instanceof ApplicationAwareInterface) {
566
                $subscriber->setApplication($this);
567
            }
568
569
            $this->dispatcher->addSubscriber($subscriber);
570
        }
571
    }
572
573
    /**
574
     * Add own helpers to helperset.
575
     *
576
     * @return void
577
     */
578
    protected function registerHelpers()
579
    {
580
        $helperSet = $this->getHelperSet();
581
        $config = $this->config->getConfig();
582
583
        if (empty($config)) {
584
            return;
585
        }
586
587
        // Twig
588
        $twigBaseDirs = [
589
            __DIR__ . '/../../../res/twig',
590
        ];
591
        if (isset($config['twig']['baseDirs']) && is_array($config['twig']['baseDirs'])) {
592
            $twigBaseDirs = array_merge(array_reverse($config['twig']['baseDirs']), $twigBaseDirs);
593
        }
594
        $helperSet->set(new TwigHelper($twigBaseDirs), 'twig');
595
596
        foreach ($config['helpers'] as $helperName => $helperClass) {
597
            if (class_exists($helperClass)) {
598
                $helperSet->set(new $helperClass(), $helperName);
599
            }
600
        }
601
    }
602
603
    /**
604
     * @param array $initConfig [optional]
605
     * @param InputInterface $input [optional]
606
     * @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...
607
     * @throws \Exception
608
     */
609
    public function reinit($initConfig = [], InputInterface $input = null, OutputInterface $output = null)
610
    {
611
        $this->_isInitialized = false;
612
        $this->detectionResult = null;
613
        $this->config = null;
614
        $this->init($initConfig, $input, $output);
615
    }
616
617
    /**
618
     * @param ConfigurationLoader $configurationLoader
619
     */
620
    public function setConfigurationLoader(ConfigurationLoader $configurationLoader)
621
    {
622
        if ($this->config) {
623
            $this->config->setLoader($configurationLoader);
624
        } else {
625
            /* inject loader to be used later when config is created in */
626
            /* @see \N98\Magento\Application::init() */
627
            $this->configurationLoaderInjected = $configurationLoader;
628
        }
629
    }
630
631
    /**
632
     * @return ObjectManagerInterface
633
     */
634
    public function getObjectManager()
635
    {
636
        return $this->_objectManager;
637
    }
638
639
    /**
640
     * @return InputDefinition
641
     */
642
    protected function getDefaultInputDefinition()
643
    {
644
        $inputDefinition = parent::getDefaultInputDefinition();
645
646
        /**
647
         * Root dir
648
         */
649
        $rootDirOption = new InputOption(
650
            '--root-dir',
651
            '',
652
            InputOption::VALUE_OPTIONAL,
653
            'Force magento root dir. No auto detection'
654
        );
655
        $inputDefinition->addOption($rootDirOption);
656
657
        /**
658
         * Skip config
659
         */
660
        $skipExternalConfig = new InputOption(
661
            '--skip-config',
662
            '',
663
            InputOption::VALUE_NONE,
664
            'Do not load any custom config.'
665
        );
666
        $inputDefinition->addOption($skipExternalConfig);
667
668
        /**
669
         * Skip root check
670
         */
671
        $skipExternalConfig = new InputOption(
672
            '--skip-root-check',
673
            '',
674
            InputOption::VALUE_NONE,
675
            'Do not check if n98-magerun runs as root'
676
        );
677
        $inputDefinition->addOption($skipExternalConfig);
678
679
        /**
680
         * Skip core commands
681
         */
682
        $skipMagento2CoreCommands = new InputOption(
683
            '--skip-core-commands',
684
            '',
685
            InputOption::VALUE_OPTIONAL,
686
            'Do not include Magento 2 core commands'
687
        );
688
        $inputDefinition->addOption($skipMagento2CoreCommands);
689
690
        return $inputDefinition;
691
    }
692
693
    /**
694
     * Force to load some classes before the Magento core loads the classes
695
     * in a different version
696
     */
697
    private function preloadClassesBeforeMagentoCore()
698
    {
699
        if ($this->autoloader instanceof ClassLoader) {
700
            $this->autoloader->loadClass('Symfony\Component\Console\Question\Question');
701
        }
702
    }
703
}
704