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 Manager 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 Manager, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
40 | class Manager |
||
41 | { |
||
42 | /** |
||
43 | * @var \Phinx\Config\ConfigInterface |
||
44 | */ |
||
45 | protected $config; |
||
46 | |||
47 | /** |
||
48 | * @var \Symfony\Component\Console\Input\InputInterface |
||
49 | */ |
||
50 | protected $input; |
||
51 | |||
52 | /** |
||
53 | * @var \Symfony\Component\Console\Output\OutputInterface |
||
54 | */ |
||
55 | protected $output; |
||
56 | |||
57 | /** |
||
58 | * @var array |
||
59 | */ |
||
60 | protected $environments; |
||
61 | |||
62 | /** |
||
63 | * @var array |
||
64 | */ |
||
65 | protected $migrations; |
||
66 | |||
67 | /** |
||
68 | * @var array |
||
69 | */ |
||
70 | protected $seeds; |
||
71 | |||
72 | /** |
||
73 | * @var integer |
||
74 | */ |
||
75 | const EXIT_STATUS_DOWN = 3; |
||
76 | |||
77 | /** |
||
78 | * @var integer |
||
79 | */ |
||
80 | const EXIT_STATUS_MISSING = 2; |
||
81 | |||
82 | /** |
||
83 | * Class Constructor. |
||
84 | * |
||
85 | * @param \Phinx\Config\ConfigInterface $config Configuration Object |
||
86 | * @param \Symfony\Component\Console\Input\InputInterface $input Console Input |
||
87 | * @param \Symfony\Component\Console\Output\OutputInterface $output Console Output |
||
88 | */ |
||
89 | 432 | public function __construct(ConfigInterface $config, InputInterface $input, OutputInterface $output) |
|
95 | |||
96 | /** |
||
97 | * Prints the specified environment's migration status. |
||
98 | * |
||
99 | * @param string $environment |
||
100 | * @param null $format |
||
101 | * @return int 0 if all migrations are up, or an error code |
||
102 | */ |
||
103 | 22 | public function printStatus($environment, $format = null) |
|
250 | |||
251 | /** |
||
252 | * Print Missing Version |
||
253 | * |
||
254 | * @param array $version The missing version to print (in the format returned by Environment.getVersionLog). |
||
255 | * @param int $maxNameLength The maximum migration name length. |
||
256 | */ |
||
257 | 10 | private function printMissingVersion($version, $maxNameLength) |
|
258 | { |
||
259 | 10 | $this->getOutput()->writeln(sprintf( |
|
260 | 10 | ' <error>up</error> %14.0f %19s %19s <comment>%s</comment> <error>** MISSING **</error>', |
|
261 | 10 | $version['version'], |
|
262 | 10 | $version['start_time'], |
|
263 | 10 | $version['end_time'], |
|
264 | 10 | str_pad($version['migration_name'], $maxNameLength, ' ') |
|
265 | 10 | )); |
|
266 | |||
267 | 10 | if ($version && $version['breakpoint']) { |
|
268 | 1 | $this->getOutput()->writeln(' <error>BREAKPOINT SET</error>'); |
|
269 | 1 | } |
|
270 | 10 | } |
|
271 | |||
272 | /** |
||
273 | * Migrate to the version of the database on a given date. |
||
274 | * |
||
275 | * @param string $environment Environment |
||
276 | * @param \DateTime $dateTime Date to migrate to |
||
277 | * @param bool $fake flag that if true, we just record running the migration, but not actually do the |
||
278 | * migration |
||
279 | * |
||
280 | 4 | * @return void |
|
281 | */ |
||
282 | 4 | public function migrateToDateTime($environment, \DateTime $dateTime, $fake = false) |
|
297 | |||
298 | /** |
||
299 | * Migrate an environment to the specified version. |
||
300 | * |
||
301 | * @param string $environment Environment |
||
302 | * @param int $version version to migrate to |
||
303 | 8 | * @param bool $fake flag that if true, we just record running the migration, but not actually do the migration |
|
304 | * @return void |
||
305 | 8 | */ |
|
306 | 8 | public function migrate($environment, $version = null, $fake = false) |
|
358 | |||
359 | /** |
||
360 | * Execute a migration against the specified environment. |
||
361 | * |
||
362 | * @param string $name Environment Name |
||
363 | 119 | * @param \Phinx\Migration\MigrationInterface $migration Migration |
|
364 | * @param string $direction Direction |
||
365 | 119 | * @param bool $fake flag that if true, we just record running the migration, but not actually do the migration |
|
366 | 119 | * @return void |
|
367 | */ |
||
368 | 119 | public function executeMigration($name, MigrationInterface $migration, $direction = MigrationInterface::UP, $fake = false) |
|
389 | |||
390 | /** |
||
391 | * Execute a seeder against the specified environment. |
||
392 | 6 | * |
|
393 | * @param string $name Environment Name |
||
394 | 6 | * @param \Phinx\Seed\SeedInterface $seed Seed |
|
395 | 6 | * @return void |
|
396 | */ |
||
397 | 6 | public function executeSeed($name, SeedInterface $seed) |
|
418 | |||
419 | /** |
||
420 | * Rollback an environment to the specified version. |
||
421 | * |
||
422 | * @param string $environment Environment |
||
423 | 349 | * @param int|string $target |
|
424 | * @param bool $force |
||
425 | * @param bool $targetMustMatchVersion |
||
426 | 349 | * @param bool $fake flag that if true, we just record running the migration, but not actually do the migration |
|
427 | * @return void |
||
428 | */ |
||
429 | 349 | public function rollback($environment, $target = null, $force = false, $targetMustMatchVersion = true, $fake = false) |
|
529 | |||
530 | 9 | /** |
|
531 | * Run database seeders against an environment. |
||
532 | 9 | * |
|
533 | * @param string $environment Environment |
||
534 | 3 | * @param string $seed Seeder |
|
535 | 3 | * @return void |
|
536 | 3 | */ |
|
537 | 3 | public function seed($environment, $seed = null) |
|
557 | 381 | ||
558 | 381 | /** |
|
559 | * Sets the environments. |
||
560 | * |
||
561 | * @param array $environments Environments |
||
562 | * @return \Phinx\Migration\Manager |
||
563 | */ |
||
564 | public function setEnvironments($environments = []) |
||
570 | 382 | ||
571 | 380 | /** |
|
572 | * Gets the manager class for the given environment. |
||
573 | * |
||
574 | * @param string $name Environment Name |
||
575 | 7 | * @throws \InvalidArgumentException |
|
576 | 1 | * @return \Phinx\Migration\Manager\Environment |
|
577 | 1 | */ |
|
578 | public function getEnvironment($name) |
||
603 | 400 | ||
604 | /** |
||
605 | * Sets the console input. |
||
606 | * |
||
607 | * @param \Symfony\Component\Console\Input\InputInterface $input Input |
||
608 | * @return \Phinx\Migration\Manager |
||
609 | */ |
||
610 | public function setInput(InputInterface $input) |
||
611 | 393 | { |
|
612 | $this->input = $input; |
||
613 | 393 | ||
614 | return $this; |
||
615 | } |
||
616 | |||
617 | /** |
||
618 | * Gets the console input. |
||
619 | * |
||
620 | * @return \Symfony\Component\Console\Input\InputInterface |
||
621 | */ |
||
622 | 400 | public function getInput() |
|
623 | { |
||
624 | 400 | return $this->input; |
|
625 | 400 | } |
|
626 | |||
627 | /** |
||
628 | * Sets the console output. |
||
629 | * |
||
630 | * @param \Symfony\Component\Console\Output\OutputInterface $output Output |
||
631 | * @return \Phinx\Migration\Manager |
||
632 | */ |
||
633 | 395 | public function setOutput(OutputInterface $output) |
|
639 | |||
640 | /** |
||
641 | * Gets the console output. |
||
642 | * |
||
643 | * @return \Symfony\Component\Console\Output\OutputInterface |
||
644 | 379 | */ |
|
645 | public function getOutput() |
||
649 | |||
650 | /** |
||
651 | * Sets the database migrations. |
||
652 | * |
||
653 | * @param array $migrations Migrations |
||
654 | * @return \Phinx\Migration\Manager |
||
655 | */ |
||
656 | public function setMigrations(array $migrations) |
||
662 | |||
663 | 388 | /** |
|
664 | * Gets an array of the database migrations, indexed by migration name (aka creation time) and sorted in ascending |
||
665 | 388 | * order |
|
666 | * |
||
667 | 388 | * @param string $environment Environment |
|
668 | 387 | * @throws \InvalidArgumentException |
|
669 | 387 | * @return \Phinx\Migration\AbstractMigration[] |
|
670 | */ |
||
671 | 387 | public function getMigrations($environment) |
|
760 | |||
761 | /** |
||
762 | * Returns a list of migration files found in the provided migration paths. |
||
763 | 11 | * |
|
764 | * @return string[] |
||
765 | 11 | */ |
|
766 | 11 | View Code Duplication | protected function getMigrationFiles() |
767 | { |
||
768 | $config = $this->getConfig(); |
||
769 | 11 | $paths = $config->getMigrationPaths(); |
|
770 | $files = []; |
||
771 | 11 | ||
772 | foreach ($paths as $path) { |
||
773 | 11 | $files = array_merge( |
|
774 | 11 | $files, |
|
775 | 11 | Util::glob($path . DIRECTORY_SEPARATOR . '*.php') |
|
776 | 11 | ); |
|
777 | } |
||
778 | // glob() can return the same file multiple times |
||
779 | 11 | // This will cause the migration to fail with a |
|
780 | 11 | // false assumption of duplicate migrations |
|
781 | // http://php.net/manual/en/function.glob.php#110340 |
||
782 | $files = array_unique($files); |
||
783 | |||
784 | 11 | return $files; |
|
785 | 11 | } |
|
786 | |||
787 | /** |
||
788 | * Sets the database seeders. |
||
789 | * |
||
790 | * @param array $seeds Seeders |
||
791 | * @return \Phinx\Migration\Manager |
||
792 | */ |
||
793 | public function setSeeds(array $seeds) |
||
799 | |||
800 | /** |
||
801 | * Get seed dependencies instances from seed dependency array |
||
802 | * |
||
803 | * @param AbstractSeed $seed Seed |
||
804 | 11 | * |
|
805 | 11 | * @return AbstractSeed[] |
|
806 | 11 | */ |
|
807 | private function getSeedDependenciesInstances(AbstractSeed $seed) |
||
823 | 11 | ||
824 | 11 | /** |
|
825 | * Order seeds by dependencies |
||
826 | 11 | * |
|
827 | 11 | * @param AbstractSeed[] $seeds Seeds |
|
828 | 11 | * |
|
829 | 11 | * @return AbstractSeed[] |
|
830 | 11 | */ |
|
831 | 11 | private function orderSeedsByDependencies(array $seeds) |
|
847 | |||
848 | /** |
||
849 | * Gets an array of database seeders. |
||
850 | * |
||
851 | * @throws \InvalidArgumentException |
||
852 | * @return \Phinx\Seed\AbstractSeed[] |
||
853 | 399 | */ |
|
854 | public function getSeeds() |
||
906 | 1 | ||
907 | /** |
||
908 | 1 | * Returns a list of seed files found in the provided seed paths. |
|
909 | 1 | * |
|
910 | 1 | * @return string[] |
|
911 | 1 | */ |
|
912 | 1 | View Code Duplication | protected function getSeedFiles() |
913 | { |
||
914 | $config = $this->getConfig(); |
||
915 | $paths = $config->getSeedPaths(); |
||
916 | $files = []; |
||
917 | |||
918 | foreach ($paths as $path) { |
||
919 | $files = array_merge( |
||
920 | $files, |
||
921 | Util::glob($path . DIRECTORY_SEPARATOR . '*.php') |
||
922 | ); |
||
923 | } |
||
924 | // glob() can return the same file multiple times |
||
925 | // This will cause the migration to fail with a |
||
926 | // false assumption of duplicate migrations |
||
927 | // http://php.net/manual/en/function.glob.php#110340 |
||
928 | $files = array_unique($files); |
||
929 | |||
930 | return $files; |
||
931 | } |
||
932 | |||
933 | /** |
||
934 | * Sets the config. |
||
935 | * |
||
936 | * @param \Phinx\Config\ConfigInterface $config Configuration Object |
||
937 | * @return \Phinx\Migration\Manager |
||
938 | */ |
||
939 | public function setConfig(ConfigInterface $config) |
||
945 | |||
946 | /** |
||
947 | * Gets the config. |
||
948 | * |
||
949 | * @return \Phinx\Config\ConfigInterface |
||
950 | */ |
||
951 | public function getConfig() |
||
955 | |||
956 | /** |
||
957 | * Toggles the breakpoint for a specific version. |
||
958 | * |
||
959 | * @param string $environment |
||
960 | * @param int $version |
||
961 | * @return void |
||
962 | */ |
||
963 | public function toggleBreakpoint($environment, $version) |
||
964 | { |
||
965 | $migrations = $this->getMigrations($environment); |
||
966 | $this->getMigrations($environment); |
||
967 | $env = $this->getEnvironment($environment); |
||
968 | $versions = $env->getVersionLog(); |
||
969 | |||
970 | if (empty($versions) || empty($migrations)) { |
||
971 | return; |
||
972 | } |
||
973 | |||
974 | if ($version === null) { |
||
975 | $lastVersion = end($versions); |
||
976 | $version = $lastVersion['version']; |
||
977 | } |
||
978 | |||
979 | View Code Duplication | if (0 != $version && !isset($migrations[$version])) { |
|
980 | $this->output->writeln(sprintf( |
||
981 | '<comment>warning</comment> %s is not a valid version', |
||
982 | $version |
||
983 | )); |
||
984 | |||
985 | return; |
||
986 | } |
||
987 | |||
988 | $env->getAdapter()->toggleBreakpoint($migrations[$version]); |
||
989 | |||
990 | $versions = $env->getVersionLog(); |
||
991 | |||
992 | $this->getOutput()->writeln( |
||
993 | ' Breakpoint ' . ($versions[$version]['breakpoint'] ? 'set' : 'cleared') . |
||
994 | ' for <info>' . $version . '</info>' . |
||
995 | ' <comment>' . $migrations[$version]->getName() . '</comment>' |
||
996 | ); |
||
997 | } |
||
998 | |||
999 | /** |
||
1000 | * Remove all breakpoints |
||
1001 | * |
||
1002 | * @param string $environment |
||
1003 | * @return void |
||
1004 | */ |
||
1005 | public function removeBreakpoints($environment) |
||
1006 | { |
||
1007 | $this->getOutput()->writeln(sprintf( |
||
1008 | ' %d breakpoints cleared.', |
||
1009 | $this->getEnvironment($environment)->getAdapter()->resetAllBreakpoints() |
||
1010 | )); |
||
1011 | } |
||
1012 | } |
||
1013 |
This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.
Both the
$myVar
assignment in line 1 and the$higher
assignment in line 2 are dead. The first because$myVar
is never used and the second because$higher
is always overwritten for every possible time line.