Completed
Push — master ( ad0611...abd676 )
by Tom
09:08 queued 04:30
created

AbstractMagentoCommand::getCommandConfig()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 12
Code Lines 7

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 12
rs 9.4285
cc 3
eloc 7
nc 4
nop 1
1
<?php
2
3
namespace N98\Magento\Command;
4
5
use Composer\Package\PackageInterface;
6
use Magento\Framework\ObjectManager\ObjectManager;
7
use N98\Magento\Command\SubCommand\ConfigBag;
8
use N98\Magento\Command\SubCommand\SubCommandFactory;
9
use Symfony\Component\Console\Command\Command;
10
use Symfony\Component\Console\Input\InputInterface;
11
use Symfony\Component\Console\Output\OutputInterface;
12
use Composer\Package\Loader\ArrayLoader as PackageLoader;
13
use Composer\Factory as ComposerFactory;
14
use Composer\IO\ConsoleIO;
15
use N98\Util\Console\Helper\MagentoHelper;
16
17
/**
18
 * Class AbstractMagentoCommand
19
 *
20
 * @package N98\Magento\Command
21
 *
22
 * @method \N98\Magento\Application getApplication() getApplication()
23
 */
24
abstract class AbstractMagentoCommand extends Command
25
{
26
    /**
27
     * @var int
28
     */
29
    const MAGENTO_MAJOR_VERSION_2 = 2;
30
31
    /**
32
     * @var string
33
     */
34
    protected $_magentoRootFolder = null;
35
36
    /**
37
     * @var int
38
     */
39
    protected $_magentoMajorVersion = self::MAGENTO_MAJOR_VERSION_2;
40
41
    /**
42
     * @var bool
43
     */
44
    protected $_magentoEnterprise = false;
45
46
    /**
47
     * @var array
48
     */
49
    protected $_deprecatedAlias = array();
50
51
    /**
52
     * @var array
53
     */
54
    protected $_websiteCodeMap = array();
55
56
    /**
57
     * @var ObjectManager
58
     */
59
    protected $_objectManager = null;
60
61
    /**
62
     * Initializes the command just after the input has been validated.
63
     *
64
     * This is mainly useful when a lot of commands extends one main command
65
     * where some things need to be initialized based on the input arguments and options.
66
     *
67
     * @param InputInterface  $input  An InputInterface instance
68
     * @param OutputInterface $output An OutputInterface instance
69
     */
70
    protected function initialize(InputInterface $input, OutputInterface $output)
71
    {
72
        $this->checkDeprecatedAliases($input, $output);
73
    }
74
75
    /**
76
     * @return ObjectManager
77
     */
78
    protected function getObjectManager()
79
    {
80
        return $this->getApplication()->getObjectManager();
81
    }
82
83
    /**
84
     * @param array $codeArgument
85
     * @param bool  $status
86
     * @return bool
0 ignored issues
show
Documentation introduced by
Should the return type not be boolean|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...
87
     */
88
    protected function saveCacheStatus($codeArgument, $status)
89
    {
90
        $cacheTypes = $this->_getCacheModel()->getTypes();
0 ignored issues
show
Bug introduced by
The method _getCacheModel() does not seem to exist on object<N98\Magento\Comma...AbstractMagentoCommand>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
91
        $enable = \Mage::app()->useCache();
92
        foreach ($cacheTypes as $cacheCode => $cacheModel) {
93
            if (empty($codeArgument) || in_array($cacheCode, $codeArgument)) {
94
                $enable[$cacheCode] = $status ? 1 : 0;
95
            }
96
        }
97
98
        \Mage::app()->saveUseCache($enable);
99
    }
100
101
    private function _initWebsites()
102
    {
103
        $this->_websiteCodeMap = array();
104
        /** @var \Mage_Core_Model_Website[] $websites */
105
        $websites = \Mage::app()->getWebsites(false);
106
        foreach ($websites as $website) {
107
            $this->_websiteCodeMap[$website->getId()] = $website->getCode();
108
        }
109
    }
110
111
    /**
112
     * @param int $websiteId
113
     * @return string
114
     */
115
    protected function _getWebsiteCodeById($websiteId)
116
    {
117
        if (empty($this->_websiteCodeMap)) {
118
            $this->_initWebsites();
119
        }
120
121
        if (isset($this->_websiteCodeMap[$websiteId])) {
122
            return $this->_websiteCodeMap[$websiteId];
123
        }
124
125
        return '';
126
    }
127
128
    /**
129
     * @param string $websiteCode
130
     * @return int
131
     */
132
    protected function _getWebsiteIdByCode($websiteCode)
133
    {
134
        if (empty($this->_websiteCodeMap)) {
135
            $this->_initWebsites();
136
        }
137
        $websiteMap = array_flip($this->_websiteCodeMap);
138
139
        return $websiteMap[$websiteCode];
140
    }
141
142
    /**
143
     * @param string|null $commandClass
144
     * @return array
145
     */
146
    protected function getCommandConfig($commandClass = null)
147
    {
148
        if ($commandClass == null) {
0 ignored issues
show
Bug introduced by
It seems like you are loosely comparing $commandClass of type string|null against null; this is ambiguous if the string can be empty. Consider using a strict comparison === instead.
Loading history...
149
            $commandClass = get_class($this);
150
        }
151
        $configArray = $this->getApplication()->getConfig();
152
        if (isset($configArray['commands'][$commandClass])) {
153
            return $configArray['commands'][$commandClass];
154
        }
155
156
        return null;
157
    }
158
159
    /**
160
     * @param \Symfony\Component\Console\Output\OutputInterface $output
161
     * @param string $text
162
     * @param string $style
163
     */
164
    protected function writeSection(OutputInterface $output, $text, $style = 'bg=blue;fg=white')
165
    {
166
        $output->writeln(array(
167
            '',
168
            $this->getHelperSet()->get('formatter')->formatBlock($text, $style, true),
169
            '',
170
        ));
171
    }
172
173
    /**
174
     * Bootstrap magento shop
175
     *
176
     * @return bool
177
     */
178
    protected function initMagento()
179
    {
180
        $init = $this->getApplication()->initMagento();
181
        if ($init) {
182
            $this->_magentoRootFolder = $this->getApplication()->getMagentoRootFolder();
183
        }
184
185
        return $init;
186
    }
187
188
    /**
189
     * Search for magento root folder
190
     *
191
     * @param OutputInterface $output
192
     * @param bool $silent print debug messages
193
     * @throws \RuntimeException
194
     */
195
    public function detectMagento(OutputInterface $output, $silent = true)
196
    {
197
        $this->getApplication()->detectMagento();
198
199
        $this->_magentoEnterprise = $this->getApplication()->isMagentoEnterprise();
200
        $this->_magentoRootFolder = $this->getApplication()->getMagentoRootFolder();
201
        $this->_magentoMajorVersion = $this->getApplication()->getMagentoMajorVersion();
202
203
        if (!$silent) {
204
            $editionString = ($this->_magentoEnterprise ? ' (Enterprise Edition) ' : '');
205
            $output->writeln(
206
                '<info>Found Magento '. $editionString . 'in folder "' . $this->_magentoRootFolder . '"</info>'
207
            );
208
        }
209
210
        if (!empty($this->_magentoRootFolder)) {
211
            return;
212
        }
213
214
        throw new \RuntimeException('Magento folder could not be detected');
215
    }
216
217
    /**
218
     * Die if not Enterprise
219
     */
220
    protected function requireEnterprise(OutputInterface $output)
221
    {
222
        if (!$this->_magentoEnterprise) {
223
            $output->writeln('<error>Enterprise Edition is required but was not detected</error>');
224
            exit;
0 ignored issues
show
Coding Style Compatibility introduced by
The method requireEnterprise() 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...
225
        }
226
    }
227
228
    /**
229
     * @return \Mage_Core_Helper_Data
230
     */
231
    protected function getCoreHelper()
232
    {
233
        if ($this->_magentoMajorVersion == self::MAGENTO_MAJOR_VERSION_2) {
234
            return \Mage::helper('Mage_Core_Helper_Data');
235
        }
236
        return \Mage::helper('core');
237
    }
238
239
    /**
240
     * @param InputInterface $input
241
     * @param OutputInterface $output
242
     * @return \Composer\Downloader\DownloadManager
243
     */
244
    public function getComposerDownloadManager($input, $output)
245
    {
246
        return $this->getComposer($input, $output)->getDownloadManager();
247
    }
248
249
    /**
250
     * @param array|PackageInterface $config
251
     * @return \Composer\Package\CompletePackage
252
     */
253
    public function createComposerPackageByConfig($config)
254
    {
255
        $packageLoader = new PackageLoader();
256
        return $packageLoader->load($config);
0 ignored issues
show
Bug introduced by
It seems like $config defined by parameter $config on line 253 can also be of type object<Composer\Package\PackageInterface>; however, Composer\Package\Loader\ArrayLoader::load() does only seem to accept array, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
257
    }
258
259
    /**
260
     * @param InputInterface $input
261
     * @param OutputInterface $output
262
     * @param array|PackageInterface $config
263
     * @param string $targetFolder
264
     * @param bool $preferSource
265
     * @return \Composer\Package\CompletePackage
266
     */
267
    public function downloadByComposerConfig(
268
        InputInterface $input,
269
        OutputInterface $output,
270
        $config,
271
        $targetFolder,
272
        $preferSource = true
273
    ) {
274
        $dm = $this->getComposerDownloadManager($input, $output);
275
        if (! $config instanceof PackageInterface) {
276
            $package = $this->createComposerPackageByConfig($config);
277
        } else {
278
            $package = $config;
279
        }
280
281
        $helper = new \N98\Util\Console\Helper\MagentoHelper();
282
        $helper->detect($targetFolder);
283
        if ($this->isSourceTypeRepository($package->getSourceType()) && $helper->getRootFolder() == $targetFolder) {
284
            $package->setInstallationSource('source');
285
            $this->checkRepository($package, $targetFolder);
286
            $dm->update($package, $package, $targetFolder);
287
        } else {
288
            $dm->download($package, $targetFolder, $preferSource);
289
        }
290
291
        return $package;
292
    }
293
294
    /**
295
     * brings locally cached repository up to date if it is missing the requested tag
296
     *
297
     * @param $package
298
     * @param $targetFolder
299
     */
300
    protected function checkRepository($package, $targetFolder)
301
    {
302
        if ($package->getSourceType() == 'git') {
303
            $command = sprintf(
304
                'cd %s && git rev-parse refs/tags/%s',
305
                escapeshellarg($targetFolder),
306
                escapeshellarg($package->getSourceReference())
307
            );
308
            $existingTags = shell_exec($command);
309
            if (!$existingTags) {
310
                $command = sprintf('cd %s && git fetch', escapeshellarg($targetFolder));
311
                shell_exec($command);
312
            }
313
        } elseif ($package->getSourceType() == 'hg') {
314
            $command = sprintf(
315
                'cd %s && hg log --template "{tags}" -r %s',
316
                escapeshellarg($targetFolder),
317
                escapeshellarg($package->getSourceReference())
318
            );
319
            $existingTag =  shell_exec($command);
320
            if ($existingTag === $package->getSourceReference()) {
321
                $command = sprintf('cd %s && hg pull', escapeshellarg($targetFolder));
322
                shell_exec($command);
323
            }
324
        }
325
    }
326
327
    /**
328
     * @param string $type
329
     *
330
     * @return bool
331
     */
332
    public function isSourceTypeRepository($type)
333
    {
334
        return in_array($type, array('git', 'hg'));
335
    }
336
337
    /**
338
     * obtain composer
339
     *
340
     * @param InputInterface  $input
341
     * @param OutputInterface $output
342
     *
343
     * @return \Composer\Composer
344
     */
345
    public function getComposer(InputInterface $input, OutputInterface $output)
346
    {
347
        $io = new ConsoleIO($input, $output, $this->getHelperSet());
0 ignored issues
show
Bug introduced by
It seems like $this->getHelperSet() can be null; however, __construct() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
348
        $config = array(
349
            'config' => array(
350
                'secure-http' => false,
351
            ),
352
        );
353
354
        return ComposerFactory::create($io, $config);
355
    }
356
357
    /**
358
     * @param string $alias
359
     * @param string $message
360
     * @return AbstractMagentoCommand
361
     */
362
    protected function addDeprecatedAlias($alias, $message)
363
    {
364
        $this->_deprecatedAlias[$alias] = $message;
365
366
        return $this;
367
    }
368
369
    /**
370
     * @param InputInterface $input
371
     * @param OutputInterface $output
372
     */
373
    protected function checkDeprecatedAliases(InputInterface $input, OutputInterface $output)
374
    {
375
        if (isset($this->_deprecatedAlias[$input->getArgument('command')])) {
376
            $output->writeln(
377
                '<error>Deprecated:</error> <comment>' . $this->_deprecatedAlias[$input->getArgument('command')] .
378
                '</comment>'
379
            );
380
        }
381
    }
382
383
    /**
384
     * @param string $value
385
     * @return bool
386
     */
387
    protected function _parseBoolOption($value)
388
    {
389
        return in_array(strtolower($value), array('y', 'yes', 1, 'true'));
390
    }
391
392
    /**
393
     * @param string $value
394
     * @return bool
395
     */
396
    public function parseBoolOption($value)
397
    {
398
        return $this->_parseBoolOption($value);
399
    }
400
401
    /**
402
     * @param string $value
403
     * @return string
404
     */
405
    public function formatActive($value)
406
    {
407
        if (in_array($value, array(1, 'true'))) {
408
            return 'active';
409
        }
410
411
        return 'inactive';
412
    }
413
414
    /**
415
     * @param InputInterface  $input
416
     * @param OutputInterface $output
417
     *
418
     * @return int
419
     */
420
    public function run(InputInterface $input, OutputInterface $output)
421
    {
422
        $this->getHelperSet()->setCommand($this);
423
424
        $this->injectObjects($output);
425
426
        return parent::run($input, $output);
427
    }
428
429
    /**
430
     * @param OutputInterface $output
431
     */
432
    public function injectObjects(OutputInterface $output)
433
    {
434
        /* @var $injectionHelper InjectionHelper */
435
        if (method_exists($this, 'inject')) {
436
            $this->detectMagento($output);
437
            $this->initMagento();
438
            $injectionHelper = $this->getHelper('injection');
439
            $injectionHelper->methodInjection(
440
                $this,
441
                'inject',
442
                $this->getObjectManager()
443
            );
444
        }
445
    }
446
447
    /**
448
     * @param InputInterface  $input
449
     * @param OutputInterface $output
450
     * @param string $baseNamespace If this is set we can use relative class names.
451
     *
452
     * @return SubCommandFactory
453
     */
454
    protected function createSubCommandFactory(
455
        InputInterface $input,
456
        OutputInterface $output,
457
        $baseNamespace = ''
458
    ) {
459
        $configBag = new ConfigBag();
460
461
        $commandConfig = $this->getCommandConfig();
462
        if (empty($commandConfig)) {
463
            $commandConfig = array();
464
        }
465
466
        return new SubCommandFactory(
467
            $this,
468
            $baseNamespace,
469
            $input,
470
            $output,
471
            $commandConfig,
472
            $configBag
473
        );
474
    }
475
}
476