Completed
Push — develop ( 72e16a...79cb00 )
by Tom
03:52
created

IncrementalCommand   D

Complexity

Total Complexity 62

Size/Duplication

Total Lines 636
Duplicated Lines 9.12 %

Coupling/Cohesion

Components 1
Dependencies 3

Importance

Changes 0
Metric Value
wmc 62
lcom 1
cbo 3
dl 58
loc 636
rs 4.8598
c 0
b 0
f 0

30 Methods

Rating   Name   Duplication   Size   Complexity  
A configure() 0 11 1
A execute() 0 19 3
A _loadSecondConfig() 0 6 1
A _getAllSetupResourceObjects() 0 19 4
A _getResource() 0 4 1
A _getAvaiableDbFilesFromResource() 16 16 2
A _getAvaiableDataFilesFromResource() 14 14 2
A _callProtectedMethodFromObject() 0 8 1
A _setProtectedPropertyFromObjectToValue() 7 7 1
A _getProtectedPropertyFromObject() 7 8 1
A _getDbVersionFromName() 0 4 1
A _getDbDataVersionFromName() 0 4 1
A _getConfiguredVersionFromResourceObject() 0 6 1
B _getAllSetupResourceObjectThatNeedUpdates() 0 20 5
A _log() 0 4 1
A _setOutput() 0 4 1
A _setInput() 0 4 1
B _outputUpdateInformation() 0 45 4
A _outputFileArray() 0 12 3
D _runNamedSetupResource() 0 65 11
B _processExceptionDuringUpdate() 0 41 2
A _checkCacheSettings() 0 15 2
A _runStructureOrDataScripts() 0 18 1
A _getTestedVersions() 0 4 1
A _restoreEventContext() 0 5 1
A _stashEventContext() 0 7 1
A _init() 0 19 3
A _analyzeSetupResourceClasses() 0 16 1
A _listDetailedUpdateInformation() 0 13 1
B _runAllStructureUpdates() 14 28 3

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like IncrementalCommand often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use IncrementalCommand, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace N98\Magento\Command\System\Setup;
4
5
use Exception;
6
use N98\Magento\Command\AbstractMagentoCommand;
7
use ReflectionClass;
8
use RuntimeException;
9
use Symfony\Component\Console\Helper\DialogHelper;
10
use Symfony\Component\Console\Input\InputInterface;
11
use Symfony\Component\Console\Input\InputOption;
12
use Symfony\Component\Console\Output\OutputInterface;
13
14
/**
15
 * Class IncrementalCommand
16
 *
17
 * @package N98\Magento\Command\System\Setup
18
 * @codeCoverageIgnore
19
 */
20
class IncrementalCommand extends AbstractMagentoCommand
21
{
22
    const TYPE_MIGRATION_STRUCTURE = 'structure';
23
    const TYPE_MIGRATION_DATA = 'data';
24
25
    /**
26
     * @var OutputInterface
27
     */
28
    protected $_output;
29
30
    /**
31
     * @var InputInterface
32
     */
33
    protected $_input;
34
35
    /**
36
     * Holds our copy of the global config.
37
     *
38
     * Loaded to avoid grabbing the cached version, and so
39
     * we still have all our original information when we
40
     * destroy the real configuration
41
     *
42
     * @var mixed $_secondConfig
43
     */
44
    protected $_secondConfig;
45
46
    protected $_eventStash;
47
48
    /**
49
     * @var array
50
     */
51
    protected $_config;
52
53
    protected function configure()
54
    {
55
        $this
56
            ->setName('sys:setup:incremental')
57
            ->setDescription('List new setup scripts to run, then runs one script')
58
            ->addOption('stop-on-error', null, InputOption::VALUE_NONE, 'Stops execution of script on error')
59
            ->setHelp(
60
                'Examines an un-cached configuration tree and determines which ' .
61
                'structure and data setup resource scripts need to run, and then runs them.'
62
            );
63
    }
64
65
    /**
66
     * @param InputInterface $input
67
     * @param OutputInterface $output
68
     *
69
     * @return int|null|void
70
     */
71
    protected function execute(InputInterface $input, OutputInterface $output)
72
    {
73
        $this->_config = $this->getCommandConfig();
74
75
        //sets output so we can access it from all methods
76
        $this->_setOutput($output);
77
        $this->_setInput($input);
78
        if (false === $this->_init()) {
79
            return;
80
        }
81
        $needsUpdate = $this->_analyzeSetupResourceClasses();
82
83
        if (count($needsUpdate) == 0) {
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
84
            // return;
85
        }
86
        $this->_listDetailedUpdateInformation($needsUpdate);
87
        $this->_runAllStructureUpdates($needsUpdate);
88
        $output->writeln('We have run all the setup resource scripts.');
89
    }
90
91
    protected function _loadSecondConfig()
92
    {
93
        $config = new \Mage_Core_Model_Config;
94
        $config->loadBase(); //get app/etc
95
        $this->_secondConfig = \Mage::getConfig()->loadModulesConfiguration('config.xml', $config);
96
    }
97
98
    /**
99
     * @return array
100
     */
101
    protected function _getAllSetupResourceObjects()
102
    {
103
        $config = $this->_secondConfig;
104
        $resources = $config->getNode('global/resources')->children();
105
        $setupResources = array();
106
        foreach ($resources as $name => $resource) {
107
            if (!$resource->setup) {
108
                continue;
109
            }
110
            $className = 'Mage_Core_Model_Resource_Setup';
111
            if (isset($resource->setup->class)) {
112
                $className = $resource->setup->getClassName();
113
            }
114
115
            $setupResources[$name] = new $className($name);
116
        }
117
118
        return $setupResources;
119
    }
120
121
    /**
122
     * @return \Mage_Core_Model_Resource
123
     */
124
    protected function _getResource()
125
    {
126
        return \Mage::getResourceSingleton('core/resource');
127
    }
128
129
    /**
130
     * @param \Mage_Core_Model_Resource_Setup $setupResource
131
     * @param array $args
132
     *
133
     * @return array|mixed
134
     */
135 View Code Duplication
    protected function _getAvaiableDbFilesFromResource($setupResource, $args = array())
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...
136
    {
137
        $result = $this->_callProtectedMethodFromObject('_getAvailableDbFiles', $setupResource, $args);
138
139
        //an install runs the install script first, then any upgrades
140
        if ($args[0] == \Mage_Core_Model_Resource_Setup::TYPE_DB_INSTALL) {
141
            $args[0] = \Mage_Core_Model_Resource_Setup::TYPE_DB_UPGRADE;
142
            $args[1] = $result[0]['toVersion'];
143
            $result = array_merge(
144
                $result,
145
                $this->_callProtectedMethodFromObject('_getAvailableDbFiles', $setupResource, $args)
146
            );
147
        }
148
149
        return $result;
150
    }
151
152
    /**
153
     * @param \Mage_Core_Model_Resource_Setup $setupResource
154
     * @param array $args
155
     *
156
     * @return array|mixed
157
     */
158 View Code Duplication
    protected function _getAvaiableDataFilesFromResource($setupResource, $args = array())
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...
159
    {
160
        $result = $this->_callProtectedMethodFromObject('_getAvailableDataFiles', $setupResource, $args);
161
        if ($args[0] == \Mage_Core_Model_Resource_Setup::TYPE_DATA_INSTALL) {
162
            $args[0] = \Mage_Core_Model_Resource_Setup::TYPE_DATA_UPGRADE;
163
            $args[1] = $result[0]['toVersion'];
164
            $result = array_merge(
165
                $result,
166
                $this->_callProtectedMethodFromObject('_getAvailableDbFiles', $setupResource, $args)
167
            );
168
        }
169
170
        return $result;
171
    }
172
173
    /**
174
     * @param string $method
175
     * @param object $object
176
     * @param array $args
177
     *
178
     * @return mixed
179
     */
180
    protected function _callProtectedMethodFromObject($method, $object, $args = array())
181
    {
182
        $r = new ReflectionClass($object);
183
        $m = $r->getMethod($method);
184
        $m->setAccessible(true);
185
186
        return $m->invokeArgs($object, $args);
187
    }
188
189
    /**
190
     * @param string $property
191
     * @param object $object
192
     * @param mixed $value
193
     */
194 View Code Duplication
    protected function _setProtectedPropertyFromObjectToValue($property, $object, $value)
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...
195
    {
196
        $r = new ReflectionClass($object);
197
        $p = $r->getProperty($property);
198
        $p->setAccessible(true);
199
        $p->setValue($object, $value);
200
    }
201
202
    /**
203
     * @param string $property
204
     * @param object $object
205
     *
206
     * @return mixed
207
     */
208 View Code Duplication
    protected function _getProtectedPropertyFromObject($property, $object)
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...
209
    {
210
        $r = new ReflectionClass($object);
211
        $p = $r->getProperty($property);
212
        $p->setAccessible(true);
213
214
        return $p->getValue($object);
215
    }
216
217
    /**
218
     * @param string $name
219
     *
220
     * @return string
221
     */
222
    protected function _getDbVersionFromName($name)
223
    {
224
        return $this->_getResource()->getDbVersion($name);
225
    }
226
227
    /**
228
     * @param string $name
229
     *
230
     * @return string
231
     */
232
    protected function _getDbDataVersionFromName($name)
233
    {
234
        return $this->_getResource()->getDataVersion($name);
235
    }
236
237
    /**
238
     * @param Object $object
239
     *
240
     * @return mixed
241
     */
242
    protected function _getConfiguredVersionFromResourceObject($object)
243
    {
244
        $moduleConfig = $this->_getProtectedPropertyFromObject('_moduleConfig', $object);
245
246
        return $moduleConfig->version;
247
    }
248
249
    /**
250
     * @param bool|array $setupResources
251
     *
252
     * @return array
253
     */
254
    protected function _getAllSetupResourceObjectThatNeedUpdates($setupResources = false)
255
    {
256
        $setupResources = $setupResources ? $setupResources : $this->_getAllSetupResourceObjects();
257
        $needsUpdate = array();
258
        foreach ($setupResources as $name => $setupResource) {
0 ignored issues
show
Bug introduced by
The expression $setupResources of type boolean|array is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
259
            $db_ver = $this->_getDbVersionFromName($name);
260
            $db_data_ver = $this->_getDbDataVersionFromName($name);
261
            $config_ver = $this->_getConfiguredVersionFromResourceObject($setupResource);
262
263
            if (
264
                (string) $config_ver == (string) $db_ver && //structure
265
                (string) $config_ver == (string) $db_data_ver //data
266
            ) {
267
                continue;
268
            }
269
            $needsUpdate[$name] = $setupResource;
270
        }
271
272
        return $needsUpdate;
273
    }
274
275
    /**
276
     * @param string $message
277
     */
278
    protected function _log($message)
279
    {
280
        $this->_output->writeln($message);
281
    }
282
283
    /**
284
     * @param OutputInterface $output
285
     */
286
    protected function _setOutput(OutputInterface $output)
287
    {
288
        $this->_output = $output;
289
    }
290
291
    /**
292
     * @param InputInterface $input
293
     */
294
    protected function _setInput(InputInterface $input)
295
    {
296
        $this->_input = $input;
297
    }
298
299
    /**
300
     * @param array $needsUpdate
301
     */
302
    protected function _outputUpdateInformation(array $needsUpdate)
303
    {
304
        $output = $this->_output;
305
        foreach ($needsUpdate as $name => $setupResource) {
306
            $dbVersion = $this->_getDbVersionFromName($name);
307
            $dbDataVersion = $this->_getDbDataVersionFromName($name);
308
            $configVersion = $this->_getConfiguredVersionFromResourceObject($setupResource);
309
310
            $moduleConfig = $this->_getProtectedPropertyFromObject('_moduleConfig', $setupResource);
311
            $output->writeln(
312
                array(
313
                    '+--------------------------------------------------+',
314
                    'Resource Name:             ' . $name,
315
                    'For Module:                ' . $moduleConfig->getName(),
316
                    'Class:                     ' . get_class($setupResource),
317
                    'Current Structure Version: ' . $dbVersion,
318
                    'Current Data Version:      ' . $dbDataVersion,
319
                    'Configured Version:        ' . $configVersion,
320
                )
321
            );
322
323
            $args = array(
324
                '',
325
                (string) $dbVersion,
326
                (string) $configVersion,
327
            );
328
329
            $args[0] = $dbVersion
330
                ? \Mage_Core_Model_Resource_Setup::TYPE_DB_UPGRADE
331
                : \Mage_Core_Model_Resource_Setup::TYPE_DB_INSTALL;
332
            $output->writeln('Structure Files to Run: ');
333
            $filesStructure = $this->_getAvaiableDbFilesFromResource($setupResource, $args);
334
            $this->_outputFileArray($filesStructure, $output);
0 ignored issues
show
Unused Code introduced by
The call to IncrementalCommand::_outputFileArray() has too many arguments starting with $output.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
335
            $output->writeln("");
336
337
            $args[0] = $dbVersion
338
                ? \Mage_Core_Model_Resource_Setup::TYPE_DATA_UPGRADE
339
                : \Mage_Core_Model_Resource_Setup::TYPE_DATA_INSTALL;
340
            $output->writeln('Data Files to Run: ');
341
            $filesData = $this->_getAvaiableDataFilesFromResource($setupResource, $args);
342
            $this->_outputFileArray($filesData, $output);
0 ignored issues
show
Unused Code introduced by
The call to IncrementalCommand::_outputFileArray() has too many arguments starting with $output.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
343
            $output->writeln('+--------------------------------------------------+');
344
            $output->writeln('');
345
        }
346
    }
347
348
    /**
349
     * @param array $files
350
     */
351
    protected function _outputFileArray($files)
352
    {
353
        $output = $this->_output;
354
        if (count($files) == 0) {
355
            $output->writeln('No files found');
356
357
            return;
358
        }
359
        foreach ($files as $file) {
360
            $output->writeln(str_replace(\Mage::getBaseDir() . '/', '', $file['fileName']));
361
        }
362
    }
363
364
    /**
365
     * Runs a single named setup resource
366
     *
367
     * This method nukes the global/resources node in the global config
368
     * and then repopulates it with **only** the $name resource. Then it
369
     * calls the standard Magento `applyAllUpdates` method.
370
     *
371
     * The benefit of this approach is we don't need to recreate the entire
372
     * setup resource running logic ourselves.  Yay for code reuse
373
     *
374
     * The downside is we should probably exit quickly, as anything else that
375
     * uses the global/resources node is going to behave weird.
376
     *
377
     * @todo     Repopulate global config after running?  Non trivial since setNode escapes strings
378
     *
379
     * @param string $name
380
     * @param array $needsUpdate
381
     * @param string $type
382
     *
383
     * @throws RuntimeException
384
     * @internal param $string
385
     */
386
    protected function _runNamedSetupResource($name, array $needsUpdate, $type)
387
    {
388
        $output = $this->_output;
389
        if (!in_array($type, array(self::TYPE_MIGRATION_STRUCTURE, self::TYPE_MIGRATION_DATA))) {
390
            throw new RuntimeException('Invalid Type [' . $type . ']: structure, data is valid');
391
        }
392
393
        if (!array_key_Exists($name, $needsUpdate)) {
394
            $output->writeln('<error>No updates to run for ' . $name . ', skipping </error>');
395
396
            return;
397
        }
398
399
        //remove all other setup resources from configuration
400
        //(in memory, do not persist this to cache)
401
        $realConfig = \Mage::getConfig();
402
        $resources = $realConfig->getNode('global/resources');
403
        foreach ($resources->children() as $resource) {
404
            if (!$resource->setup) {
405
                continue;
406
            }
407
            unset($resource->setup);
408
        }
409
        //recreate our specific node in <global><resources></resource></global>
410
        //allows for theoretical multiple runs
411
        $setupResourceConfig = $this->_secondConfig->getNode('global/resources/' . $name);
412
        $moduleName = $setupResourceConfig->setup->module;
413
        $className = $setupResourceConfig->setup->class;
414
415
        $specificResource = $realConfig->getNode('global/resources/' . $name);
416
        $setup = $specificResource->addChild('setup');
417
        if ($moduleName) {
418
            $setup->addChild('module', $moduleName);
419
        } else {
420
            $output->writeln(
421
                '<error>No module node configured for ' . $name . ', possible configuration error </error>'
422
            );
423
        }
424
425
        if ($className) {
426
            $setup->addChild('class', $className);
427
        }
428
429
        //and finally, RUN THE UPDATES
430
        try {
431
            ob_start();
432
            if ($type == self::TYPE_MIGRATION_STRUCTURE) {
433
                $this->_stashEventContext();
434
                \Mage_Core_Model_Resource_Setup::applyAllUpdates();
435
                $this->_restoreEventContext();
436
            } else {
437
                if ($type == self::TYPE_MIGRATION_DATA) {
438
                    \Mage_Core_Model_Resource_Setup::applyAllDataUpdates();
439
                }
440
            }
441
            $exceptionOutput = ob_get_clean();
442
            $this->_output->writeln($exceptionOutput);
443
        } catch (Exception $e) {
444
            $exceptionOutput = ob_get_clean();
445
            $this->_processExceptionDuringUpdate($e, $name, $exceptionOutput);
446
            if ($this->_input->getOption('stop-on-error')) {
447
                throw new RuntimeException('Setup stopped with errors');
448
            }
449
        }
450
    }
451
452
    /**
453
     * @param Exception $e
454
     * @param string $name
455
     * @param string $magentoExceptionOutput
456
     */
457
    protected function _processExceptionDuringUpdate(
458
        Exception $e,
459
        $name,
460
        $magentoExceptionOutput
461
    ) {
462
        $output = $this->_output;
463
        $output->writeln(array(
464
            "<error>Magento encountered an error while running the following setup resource.</error>",
465
            "",
466
            "    $name ",
467
            "",
468
            "<error>The Good News:</error> You know the error happened, and the database",
469
            "information below will  help you fix this error!",
470
            "",
471
            "<error>The Bad News:</error> Because Magento/MySQL can't run setup resources",
472
            "transactionally your database is now in an half upgraded, invalid",
473
            "state. Even if you fix the error, new errors may occur due to",
474
            "this half upgraded, invalid state.",
475
            '',
476
            "What to Do: ",
477
            "1. Figure out why the error happened, and manually fix your",
478
            "   database and/or system so it won't happen again.",
479
            "2. Restore your database from backup.",
480
            "3. Re-run the scripts.",
481
            "",
482
            "Exception Message:",
483
            $e->getMessage(),
484
            "",
485
        ));
486
487
        if ($magentoExceptionOutput) {
488
            /* @var  $dialog DialogHelper */
489
            $dialog = $this->getHelper('dialog');
490
            $dialog->ask(
491
                $output,
492
                '<question>Press Enter to view raw Magento error text:</question> '
493
            );
494
            $output->writeln("Magento Exception Error Text:");
495
            echo $magentoExceptionOutput, "\n"; //echoing (vs. writeln) to avoid seg fault
496
        }
497
    }
498
499
    /**
500
     * @return bool
501
     */
502
    protected function _checkCacheSettings()
503
    {
504
        $output = $this->_output;
505
        $allTypes = \Mage::app()->useCache();
506
        if ($allTypes['config'] !== '1') {
507
            $output->writeln('<error>ERROR: Config Cache is Disabled</error>');
508
            $output->writeln('This command will not run with the configuration cache disabled.');
509
            $output->writeln('Please change your Magento settings at System -> Cache Management');
510
            $output->writeln('');
511
512
            return false;
513
        }
514
515
        return true;
516
    }
517
518
    /**
519
     * @param string $toUpdate
520
     * @param array $needsUpdate
521
     * @param string $type
522
     */
523
    protected function _runStructureOrDataScripts($toUpdate, array $needsUpdate, $type)
524
    {
525
        $output = $this->_output;
526
        $output->writeln('The next ' . $type . ' update to run is <info>' . $toUpdate . '</info>');
527
        /* @var  $dialog DialogHelper */
528
        $dialog = $this->getHelper('dialog');
529
        $dialog->ask(
530
            $output,
531
            '<question>Press Enter to Run this update: </question>'
532
        );
533
534
        $start = microtime(true);
535
        $this->_runNamedSetupResource($toUpdate, $needsUpdate, $type);
536
        $time_ran = microtime(true) - $start;
537
        $output->writeln('');
538
        $output->writeln(ucwords($type) . ' update <info>' . $toUpdate . '</info> complete.');
539
        $output->writeln('Ran in ' . floor($time_ran * 1000) . 'ms');
540
    }
541
542
    /**
543
     * @return array
544
     */
545
    protected function _getTestedVersions()
546
    {
547
        return $this->_config['tested-versions'];
548
    }
549
550
    protected function _restoreEventContext()
551
    {
552
        $app = \Mage::app();
553
        $this->_setProtectedPropertyFromObjectToValue('_events', $app, $this->_eventStash);
554
    }
555
556
    protected function _stashEventContext()
557
    {
558
        $app = \Mage::app();
559
        $events = $this->_getProtectedPropertyFromObject('_events', $app);
560
        $this->_eventStash = $events;
561
        $this->_setProtectedPropertyFromObjectToValue('_events', $app, array());
562
    }
563
564
    /**
565
     * @return bool
566
     */
567
    protected function _init()
568
    {
569
        //bootstrap magento
570
        $this->detectMagento($this->_output);
571
        if (!$this->initMagento()) {
572
            return false;
573
        }
574
575
        //don't run if cache is off.  If cache is off that means
576
        //setup resource will run automagically
577
        if (!$this->_checkCacheSettings()) {
578
            return false;
579
        }
580
581
        //load a second, not cached, config.xml tree
582
        $this->_loadSecondConfig();
583
584
        return true;
585
    }
586
587
    /**
588
     * @return array
589
     */
590
    protected function _analyzeSetupResourceClasses()
591
    {
592
        $output = $this->_output;
593
        $this->writeSection($output, 'Analyzing Setup Resource Classes');
594
        $setupResources = $this->_getAllSetupResourceObjects();
595
        $needsUpdate = $this->_getAllSetupResourceObjectThatNeedUpdates($setupResources);
596
597
        $output->writeln(
598
            'Found <info>' . count($setupResources) . '</info> configured setup resource(s)</info>'
599
        );
600
        $output->writeln(
601
            'Found <info>' . count($needsUpdate) . '</info> setup resource(s) which need an update</info>'
602
        );
603
604
        return $needsUpdate;
605
    }
606
607
    /**
608
     * @param array $needsUpdate
609
     */
610
    protected function _listDetailedUpdateInformation(array $needsUpdate)
611
    {
612
        $output = $this->_output;
613
        /* @var  $dialog DialogHelper */
614
        $dialog = $this->getHelper('dialog');
615
        $dialog->ask(
616
            $output,
617
            '<question>Press Enter to View Update Information: </question>'
618
        );
619
620
        $this->writeSection($output, 'Detailed Update Information');
621
        $this->_outputUpdateInformation($needsUpdate, $output);
0 ignored issues
show
Unused Code introduced by
The call to IncrementalCommand::_outputUpdateInformation() has too many arguments starting with $output.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
622
    }
623
624
    /**
625
     * @param array $needsUpdate
626
     */
627
    protected function _runAllStructureUpdates(array $needsUpdate)
628
    {
629
        $output = $this->_output;
630
        $this->writeSection($output, "Run Structure Updates");
631
        $output->writeln('All structure updates run before data updates.');
632
        $output->writeln('');
633
634
        $c = 1;
635
        $total = count($needsUpdate);
636 View Code Duplication
        foreach ($needsUpdate as $key => $value) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
637
            $toUpdate = $key;
638
            $this->_runStructureOrDataScripts($toUpdate, $needsUpdate, self::TYPE_MIGRATION_STRUCTURE);
639
            $output->writeln("($c of $total)");
640
            $output->writeln('');
641
            $c++;
642
        }
643
644
        $this->writeSection($output, "Run Data Updates");
645
        $c = 1;
646
        $total = count($needsUpdate);
647 View Code Duplication
        foreach ($needsUpdate as $key => $value) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
648
            $toUpdate = $key;
649
            $this->_runStructureOrDataScripts($toUpdate, $needsUpdate, self::TYPE_MIGRATION_DATA);
650
            $output->writeln("($c of $total)");
651
            $output->writeln('');
652
            $c++;
653
        }
654
    }
655
}
656