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 classes like Application 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 Application, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
31 | class Application extends BaseApplication |
||
32 | { |
||
33 | /** |
||
34 | * @var string |
||
35 | */ |
||
36 | const APP_NAME = 'n98-magerun'; |
||
37 | |||
38 | /** |
||
39 | * @var string |
||
40 | */ |
||
41 | const APP_VERSION = '1.97.23'; |
||
42 | |||
43 | /** |
||
44 | * @var int |
||
45 | */ |
||
46 | const MAGENTO_MAJOR_VERSION_1 = 1; |
||
47 | |||
48 | /** |
||
49 | * @var int |
||
50 | */ |
||
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 array |
||
70 | */ |
||
71 | protected $config = array(); |
||
72 | |||
73 | /** |
||
74 | * @var ConfigurationLoader |
||
75 | */ |
||
76 | protected $configurationLoader = null; |
||
77 | |||
78 | /** |
||
79 | * @var array |
||
80 | */ |
||
81 | protected $partialConfig = array(); |
||
82 | |||
83 | /** |
||
84 | * @var string |
||
85 | */ |
||
86 | protected $_magentoRootFolder = null; |
||
87 | |||
88 | /** |
||
89 | * @var bool |
||
90 | */ |
||
91 | protected $_magentoEnterprise = false; |
||
92 | |||
93 | /** |
||
94 | * @var int |
||
95 | */ |
||
96 | protected $_magentoMajorVersion = self::MAGENTO_MAJOR_VERSION_1; |
||
97 | |||
98 | /** |
||
99 | * @var EntryPoint |
||
100 | */ |
||
101 | protected $_magento2EntryPoint = null; |
||
102 | |||
103 | /** |
||
104 | * @var bool |
||
105 | */ |
||
106 | protected $_isPharMode = false; |
||
107 | |||
108 | /** |
||
109 | * @var bool |
||
110 | */ |
||
111 | protected $_magerunStopFileFound = false; |
||
112 | |||
113 | /** |
||
114 | * @var string |
||
115 | */ |
||
116 | protected $_magerunStopFileFolder = null; |
||
117 | |||
118 | /** |
||
119 | * @var bool |
||
120 | */ |
||
121 | protected $_isInitialized = false; |
||
122 | |||
123 | /** |
||
124 | * @var EventDispatcher |
||
125 | */ |
||
126 | protected $dispatcher; |
||
127 | |||
128 | /** |
||
129 | * If root dir is set by root-dir option this flag is true |
||
130 | * |
||
131 | * @var bool |
||
132 | */ |
||
133 | protected $_directRootDir = false; |
||
134 | |||
135 | /** |
||
136 | * @var bool |
||
137 | */ |
||
138 | protected $_magentoDetected = false; |
||
139 | |||
140 | /** |
||
141 | * @param ClassLoader $autoloader |
||
142 | */ |
||
143 | public function __construct($autoloader = null) |
||
144 | { |
||
145 | $this->autoloader = $autoloader; |
||
146 | parent::__construct(self::APP_NAME, self::APP_VERSION); |
||
147 | } |
||
148 | |||
149 | /** |
||
150 | * @return InputDefinition |
||
151 | */ |
||
152 | protected function getDefaultInputDefinition() |
||
153 | { |
||
154 | $inputDefinition = parent::getDefaultInputDefinition(); |
||
155 | |||
156 | /** |
||
157 | * Root dir |
||
158 | */ |
||
159 | $rootDirOption = new InputOption( |
||
160 | '--root-dir', |
||
161 | '', |
||
162 | InputOption::VALUE_OPTIONAL, |
||
163 | 'Force magento root dir. No auto detection' |
||
164 | ); |
||
165 | $inputDefinition->addOption($rootDirOption); |
||
166 | |||
167 | /** |
||
168 | * Skip config |
||
169 | */ |
||
170 | $skipExternalConfig = new InputOption( |
||
171 | '--skip-config', |
||
172 | '', |
||
173 | InputOption::VALUE_NONE, |
||
174 | 'Do not load any custom config.' |
||
175 | ); |
||
176 | $inputDefinition->addOption($skipExternalConfig); |
||
177 | |||
178 | /** |
||
179 | * Skip root check |
||
180 | */ |
||
181 | $skipExternalConfig = new InputOption( |
||
182 | '--skip-root-check', |
||
183 | '', |
||
184 | InputOption::VALUE_NONE, |
||
185 | 'Do not check if n98-magerun runs as root' |
||
186 | ); |
||
187 | $inputDefinition->addOption($skipExternalConfig); |
||
188 | |||
189 | return $inputDefinition; |
||
190 | } |
||
191 | |||
192 | /** |
||
193 | * Get names of sub-folders to be scanned during Magento detection |
||
194 | * |
||
195 | * @return array |
||
196 | */ |
||
197 | public function getDetectSubFolders() |
||
205 | |||
206 | /** |
||
207 | * Search for magento root folder |
||
208 | * |
||
209 | * @param InputInterface $input [optional] |
||
210 | * @param OutputInterface $output [optional] |
||
211 | * @return void |
||
212 | */ |
||
213 | public function detectMagento(InputInterface $input = null, OutputInterface $output = null) |
||
214 | { |
||
215 | // do not detect magento twice |
||
216 | if ($this->_magentoDetected) { |
||
217 | return; |
||
218 | } |
||
219 | |||
220 | if (null === $input) { |
||
221 | $input = new ArgvInput(); |
||
222 | } |
||
223 | |||
224 | if (null === $output) { |
||
225 | $output = new ConsoleOutput(); |
||
226 | } |
||
227 | |||
228 | if ($this->getMagentoRootFolder() === null) { |
||
229 | $this->_checkRootDirOption($input); |
||
230 | $folder = OperatingSystem::getCwd(); |
||
231 | } else { |
||
232 | $folder = $this->getMagentoRootFolder(); |
||
233 | } |
||
234 | |||
235 | $this->getHelperSet()->set(new MagentoHelper($input, $output), 'magento'); |
||
236 | $magentoHelper = $this->getHelperSet()->get('magento'); |
||
237 | /* @var $magentoHelper MagentoHelper */ |
||
238 | if (!$this->_directRootDir) { |
||
239 | $subFolders = $this->getDetectSubFolders(); |
||
240 | } else { |
||
241 | $subFolders = array(); |
||
242 | } |
||
243 | |||
244 | $this->_magentoDetected = $magentoHelper->detect($folder, $subFolders); |
||
245 | $this->_magentoRootFolder = $magentoHelper->getRootFolder(); |
||
246 | $this->_magentoEnterprise = $magentoHelper->isEnterpriseEdition(); |
||
247 | $this->_magentoMajorVersion = $magentoHelper->getMajorVersion(); |
||
248 | $this->_magerunStopFileFound = $magentoHelper->isMagerunStopFileFound(); |
||
249 | $this->_magerunStopFileFolder = $magentoHelper->getMagerunStopFileFolder(); |
||
250 | } |
||
251 | |||
252 | /** |
||
253 | * Add own helpers to helperset. |
||
254 | * |
||
255 | * @return void |
||
256 | */ |
||
257 | protected function registerHelpers() |
||
258 | { |
||
259 | $helperSet = $this->getHelperSet(); |
||
260 | |||
261 | // Twig |
||
262 | $twigBaseDirs = array( |
||
263 | __DIR__ . '/../../../res/twig', |
||
264 | ); |
||
265 | if (isset($this->config['twig']['baseDirs']) && is_array($this->config['twig']['baseDirs'])) { |
||
266 | $twigBaseDirs = array_merge(array_reverse($this->config['twig']['baseDirs']), $twigBaseDirs); |
||
267 | } |
||
268 | $helperSet->set(new TwigHelper($twigBaseDirs), 'twig'); |
||
269 | |||
270 | foreach ($this->config['helpers'] as $helperName => $helperClass) { |
||
271 | if (class_exists($helperClass)) { |
||
272 | $helperSet->set(new $helperClass(), $helperName); |
||
273 | } |
||
274 | } |
||
275 | } |
||
276 | |||
277 | /** |
||
278 | * Adds autoloader prefixes from user's config |
||
279 | */ |
||
280 | protected function registerCustomAutoloaders() |
||
281 | { |
||
282 | View Code Duplication | if (isset($this->config['autoloaders']) && is_array($this->config['autoloaders'])) { |
|
|
|||
283 | foreach ($this->config['autoloaders'] as $prefix => $path) { |
||
284 | $this->autoloader->add($prefix, $path); |
||
285 | } |
||
286 | } |
||
287 | |||
288 | View Code Duplication | if (isset($this->config['autoloaders_psr4']) && is_array($this->config['autoloaders_psr4'])) { |
|
289 | foreach ($this->config['autoloaders_psr4'] as $prefix => $path) { |
||
290 | $this->autoloader->addPsr4($prefix, $path); |
||
291 | } |
||
292 | } |
||
293 | |||
294 | View Code Duplication | if (isset($this->config['autoload_files']) && is_array($this->config['autoload_files'])) { |
|
295 | foreach ($this->config['autoload_files'] as $file) { |
||
296 | require $file; |
||
297 | } |
||
298 | } |
||
299 | } |
||
300 | |||
301 | /** |
||
302 | * @return bool |
||
303 | */ |
||
304 | protected function hasCustomCommands() |
||
309 | |||
310 | /** |
||
311 | * @return void |
||
312 | */ |
||
313 | protected function registerCustomCommands() |
||
314 | { |
||
315 | if (!$this->hasCustomCommands()) { |
||
316 | return; |
||
317 | } |
||
318 | |||
319 | foreach ($this->config['commands']['customCommands'] as $commandClass) { |
||
320 | if (is_array($commandClass)) { // Support for key => value (name -> class) |
||
321 | $resolvedCommandClass = current($commandClass); |
||
322 | if ($this->isCommandDisabled($resolvedCommandClass)) { |
||
323 | continue; |
||
324 | } |
||
325 | $command = new $resolvedCommandClass(); |
||
326 | $command->setName(key($commandClass)); |
||
327 | } elseif ($this->isCommandDisabled($commandClass)) { |
||
328 | continue; |
||
329 | } else { |
||
330 | $command = new $commandClass(); |
||
331 | } |
||
332 | $this->add($command); |
||
333 | } |
||
334 | } |
||
335 | |||
336 | /** |
||
337 | * @param string $class |
||
338 | * @return bool |
||
339 | */ |
||
340 | protected function isCommandDisabled($class) |
||
341 | { |
||
342 | return in_array($class, $this->config['commands']['disabled']); |
||
343 | } |
||
344 | |||
345 | /** |
||
346 | * Override standard command registration. We want alias support. |
||
347 | * |
||
348 | * @param Command $command |
||
349 | * |
||
350 | * @return Command |
||
351 | */ |
||
352 | public function add(Command $command) |
||
353 | { |
||
354 | $this->registerConfigCommandAlias($command); |
||
355 | |||
356 | return parent::add($command); |
||
357 | } |
||
358 | |||
359 | /** |
||
360 | * @param Command $command |
||
361 | */ |
||
362 | protected function registerConfigCommandAlias(Command $command) |
||
363 | { |
||
364 | if ($this->hasConfigCommandAliases()) { |
||
365 | foreach ($this->config['commands']['aliases'] as $alias) { |
||
366 | if (!is_array($alias)) { |
||
367 | continue; |
||
368 | } |
||
369 | |||
370 | $aliasCommandName = key($alias); |
||
371 | $commandString = $alias[$aliasCommandName]; |
||
372 | |||
373 | list($originalCommand) = explode(' ', $commandString); |
||
374 | if ($command->getName() == $originalCommand) { |
||
375 | $currentCommandAliases = $command->getAliases(); |
||
376 | $currentCommandAliases[] = $aliasCommandName; |
||
377 | $command->setAliases($currentCommandAliases); |
||
378 | } |
||
379 | } |
||
380 | } |
||
381 | } |
||
382 | |||
383 | /** |
||
384 | * @return bool |
||
385 | */ |
||
386 | private function hasConfigCommandAliases() |
||
387 | { |
||
388 | return isset($this->config['commands']['aliases']) && is_array($this->config['commands']['aliases']); |
||
389 | } |
||
390 | |||
391 | /** |
||
392 | * @param bool $mode |
||
393 | */ |
||
394 | public function setPharMode($mode) |
||
395 | { |
||
396 | $this->_isPharMode = $mode; |
||
397 | } |
||
398 | |||
399 | /** |
||
400 | * @return bool |
||
401 | */ |
||
402 | public function isPharMode() |
||
403 | { |
||
404 | return $this->_isPharMode; |
||
405 | } |
||
406 | |||
407 | /** |
||
408 | * @TODO Move logic into "EventSubscriber" |
||
409 | * |
||
410 | * @param OutputInterface $output |
||
411 | * @return null|false |
||
412 | */ |
||
413 | public function checkVarDir(OutputInterface $output) |
||
470 | |||
471 | /** |
||
472 | * Loads and initializes the Magento application |
||
473 | * |
||
474 | * @param bool $soft |
||
475 | * |
||
476 | * @return bool false if magento root folder is not set, true otherwise |
||
477 | */ |
||
478 | public function initMagento($soft = false) |
||
493 | |||
494 | /** |
||
495 | * @return string |
||
496 | */ |
||
497 | public function getHelp() |
||
498 | { |
||
499 | return self::$logo . parent::getHelp(); |
||
500 | } |
||
501 | |||
502 | public function getLongVersion() |
||
503 | { |
||
504 | return parent::getLongVersion() . ' by <info>netz98 new media GmbH</info>'; |
||
505 | } |
||
506 | |||
507 | /** |
||
508 | * @return boolean |
||
509 | */ |
||
510 | public function isMagentoEnterprise() |
||
511 | { |
||
512 | return $this->_magentoEnterprise; |
||
513 | } |
||
514 | |||
515 | /** |
||
516 | * @return string |
||
517 | */ |
||
518 | public function getMagentoRootFolder() |
||
519 | { |
||
520 | return $this->_magentoRootFolder; |
||
521 | } |
||
522 | |||
523 | /** |
||
524 | * @param string $magentoRootFolder |
||
525 | */ |
||
526 | public function setMagentoRootFolder($magentoRootFolder) |
||
527 | { |
||
528 | $this->_magentoRootFolder = $magentoRootFolder; |
||
529 | } |
||
530 | |||
531 | /** |
||
532 | * @return int |
||
533 | */ |
||
534 | public function getMagentoMajorVersion() |
||
535 | { |
||
536 | return $this->_magentoMajorVersion; |
||
537 | } |
||
538 | |||
539 | /** |
||
540 | * @return ClassLoader |
||
541 | */ |
||
542 | public function getAutoloader() |
||
543 | { |
||
544 | return $this->autoloader; |
||
545 | } |
||
546 | |||
547 | /** |
||
548 | * @param ClassLoader $autoloader |
||
549 | */ |
||
550 | public function setAutoloader($autoloader) |
||
551 | { |
||
552 | $this->autoloader = $autoloader; |
||
553 | } |
||
554 | |||
555 | /** |
||
556 | * @return array |
||
557 | */ |
||
558 | public function getConfig() |
||
559 | { |
||
560 | return $this->config; |
||
561 | } |
||
562 | |||
563 | /** |
||
564 | * @param array $config |
||
565 | */ |
||
566 | public function setConfig($config) |
||
567 | { |
||
568 | $this->config = $config; |
||
569 | } |
||
570 | |||
571 | /** |
||
572 | * @return boolean |
||
573 | */ |
||
574 | public function isMagerunStopFileFound() |
||
575 | { |
||
576 | return $this->_magerunStopFileFound; |
||
577 | } |
||
578 | |||
579 | /** |
||
580 | * Runs the current application with possible command aliases |
||
581 | * |
||
582 | * @param InputInterface $input An Input instance |
||
583 | * @param OutputInterface $output An Output instance |
||
584 | * |
||
585 | * @return integer 0 if everything went fine, or an error code |
||
586 | */ |
||
587 | public function doRun(InputInterface $input, OutputInterface $output) |
||
605 | |||
606 | /** |
||
607 | * @param InputInterface $input |
||
608 | * |
||
609 | * @return ArgvInput|InputInterface |
||
610 | */ |
||
611 | protected function checkConfigCommandAlias(InputInterface $input) |
||
640 | |||
641 | /** |
||
642 | * @param InputInterface $input |
||
643 | * @param OutputInterface $output |
||
644 | * @return int |
||
645 | */ |
||
646 | public function run(InputInterface $input = null, OutputInterface $output = null) |
||
647 | { |
||
648 | if (null === $input) { |
||
649 | $input = new ArgvInput(); |
||
650 | } |
||
651 | |||
652 | if (null === $output) { |
||
653 | $output = new ConsoleOutput(); |
||
654 | } |
||
655 | $this->_addOutputStyles($output); |
||
656 | if ($output instanceof ConsoleOutput) { |
||
657 | $this->_addOutputStyles($output->getErrorOutput()); |
||
658 | } |
||
659 | |||
660 | $this->configureIO($input, $output); |
||
661 | |||
662 | try { |
||
663 | $this->init(array(), $input, $output); |
||
664 | } catch (Exception $e) { |
||
665 | $output = new ConsoleOutput(); |
||
666 | $this->renderException($e, $output->getErrorOutput()); |
||
667 | } |
||
668 | |||
669 | $return = parent::run($input, $output); |
||
670 | |||
671 | // Fix for no return values -> used in interactive shell to prevent error output |
||
672 | if ($return === null) { |
||
673 | return 0; |
||
674 | } |
||
675 | |||
676 | return $return; |
||
677 | } |
||
678 | |||
679 | /** |
||
680 | * @param array $initConfig |
||
681 | * @param InputInterface $input |
||
682 | * @param OutputInterface $output |
||
683 | * |
||
684 | * @return void |
||
685 | */ |
||
686 | public function init(array $initConfig = array(), InputInterface $input = null, OutputInterface $output = null) |
||
726 | |||
727 | /** |
||
728 | * @param array $initConfig |
||
729 | * @param InputInterface $input |
||
730 | * @param OutputInterface $output |
||
731 | */ |
||
732 | public function reinit($initConfig = array(), InputInterface $input = null, OutputInterface $output = null) |
||
733 | { |
||
734 | $this->_isInitialized = false; |
||
735 | $this->_magentoDetected = false; |
||
736 | $this->_magentoRootFolder = null; |
||
737 | $this->init($initConfig, $input, $output); |
||
738 | } |
||
739 | |||
740 | /** |
||
741 | * @return void |
||
742 | */ |
||
743 | protected function registerEventSubscribers() |
||
744 | { |
||
745 | foreach ($this->config['event']['subscriber'] as $subscriberClass) { |
||
746 | $subscriber = new $subscriberClass(); |
||
747 | $this->dispatcher->addSubscriber($subscriber); |
||
748 | } |
||
749 | } |
||
750 | |||
751 | /** |
||
752 | * @param InputInterface $input |
||
753 | * @return bool |
||
754 | */ |
||
755 | protected function _checkSkipConfigOption(InputInterface $input) |
||
756 | { |
||
757 | return $input->hasParameterOption('--skip-config'); |
||
758 | } |
||
759 | |||
760 | /** |
||
761 | * @param InputInterface $input |
||
762 | * @return string |
||
763 | */ |
||
764 | protected function _checkRootDirOption(InputInterface $input) |
||
765 | { |
||
766 | $definedRootDir = $input->getParameterOption('--root-dir'); |
||
767 | |||
768 | if (!empty($definedRootDir)) { |
||
769 | if ($definedRootDir[0] == '~') { |
||
770 | $definedRootDir = OperatingSystem::getHomeDir() . substr($definedRootDir, 1); |
||
771 | } |
||
772 | |||
773 | $folder = realpath($definedRootDir); |
||
774 | $this->_directRootDir = true; |
||
775 | if (is_dir($folder)) { |
||
776 | \chdir($folder); |
||
777 | |||
778 | return; |
||
779 | } |
||
780 | } |
||
781 | } |
||
782 | |||
783 | /** |
||
784 | * @param bool $soft |
||
785 | * @return void |
||
786 | */ |
||
787 | protected function _initMagento1($soft = false) |
||
788 | { |
||
789 | if (!class_exists('Mage', false)) { |
||
790 | // Create a new AutoloadRestorer to capture currenjt auto-öpaders |
||
791 | $restorer = new AutoloadRestorer(); |
||
792 | // require app/Mage.php from Magento in a function of it's own to have it's own variable scope |
||
793 | $this->requireOnce($this->_magentoRootFolder . '/app/Mage.php'); |
||
794 | // Restore auto-loaders that might be removed by extensions that overwrite Varien/Autoload |
||
795 | $restorer->restore(); |
||
796 | } |
||
797 | |||
798 | // skip Mage::app init routine and return |
||
799 | if ($soft === true) { |
||
800 | return; |
||
801 | } |
||
802 | |||
803 | $initSettings = $this->config['init']; |
||
804 | |||
805 | Mage::app($initSettings['code'], $initSettings['type'], $initSettings['options']); |
||
806 | } |
||
807 | |||
808 | /** |
||
809 | * use require-once inside a function with it's own variable scope w/o any other variables |
||
810 | * and $this unbound. |
||
811 | * |
||
812 | * @param string $path |
||
813 | */ |
||
814 | private function requireOnce($path) |
||
825 | |||
826 | /** |
||
827 | * show compatibility notice about Magento 2 |
||
828 | */ |
||
829 | protected function _initMagento2() |
||
864 | |||
865 | /** |
||
866 | * @return EventDispatcher |
||
867 | */ |
||
868 | public function getDispatcher() |
||
872 | |||
873 | /** |
||
874 | * @param array $initConfig |
||
875 | * @param OutputInterface $output |
||
876 | * @return ConfigurationLoader |
||
877 | */ |
||
878 | public function getConfigurationLoader(array $initConfig, OutputInterface $output) |
||
890 | |||
891 | /** |
||
892 | * @param ConfigurationLoader $configurationLoader |
||
893 | * |
||
894 | * @return $this |
||
895 | */ |
||
896 | public function setConfigurationLoader($configurationLoader) |
||
897 | { |
||
898 | $this->configurationLoader = $configurationLoader; |
||
899 | |||
900 | return $this; |
||
901 | } |
||
902 | |||
903 | /** |
||
904 | * @param OutputInterface $output |
||
905 | */ |
||
906 | protected function _addOutputStyles(OutputInterface $output) |
||
907 | { |
||
908 | $output->getFormatter()->setStyle('debug', new OutputFormatterStyle('magenta', 'white')); |
||
909 | $output->getFormatter()->setStyle('warning', new OutputFormatterStyle('red', 'yellow', array('bold'))); |
||
910 | } |
||
911 | } |
||
912 |
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.