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 DumpCommand 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 DumpCommand, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
14 | class DumpCommand extends AbstractDatabaseCommand |
||
15 | { |
||
16 | /** |
||
17 | * @var array |
||
18 | */ |
||
19 | protected $tableDefinitions = null; |
||
20 | |||
21 | /** |
||
22 | * @var array |
||
23 | */ |
||
24 | protected $commandConfig = null; |
||
25 | |||
26 | protected function configure() |
||
128 | |||
129 | /** |
||
130 | * @return bool |
||
131 | */ |
||
132 | public function isEnabled() |
||
133 | { |
||
134 | return function_exists('exec') && !OperatingSystem::isWindows(); |
||
135 | } |
||
136 | |||
137 | /** |
||
138 | * @return array |
||
139 | * |
||
140 | * @deprecated Use database helper |
||
141 | * @throws RuntimeException |
||
142 | */ |
||
143 | public function getTableDefinitions() |
||
172 | |||
173 | /** |
||
174 | * Generate help for table definitions |
||
175 | * |
||
176 | * @return string |
||
177 | */ |
||
178 | public function getTableDefinitionHelp() |
||
203 | |||
204 | public function getHelp() |
||
210 | |||
211 | /** |
||
212 | * @param InputInterface $input |
||
213 | * @param OutputInterface $output |
||
214 | * @return int|void |
||
215 | */ |
||
216 | protected function execute(InputInterface $input, OutputInterface $output) |
||
228 | |||
229 | /** |
||
230 | * @param InputInterface $input |
||
231 | * @param OutputInterface $output |
||
232 | * @return Execs |
||
233 | */ |
||
234 | private function createExecs(InputInterface $input, OutputInterface $output) |
||
279 | |||
280 | /** |
||
281 | * @param Execs $execs |
||
282 | * @param InputInterface $input |
||
283 | * @param OutputInterface $output |
||
284 | */ |
||
285 | private function runExecs(Execs $execs, InputInterface $input, OutputInterface $output) |
||
316 | |||
317 | /** |
||
318 | * @param string $command |
||
319 | * @param InputInterface $input |
||
320 | * @param OutputInterface $output |
||
321 | * @return bool |
||
322 | */ |
||
323 | private function runExec($command, InputInterface $input, OutputInterface $output) |
||
342 | |||
343 | /** |
||
344 | * @param InputInterface $input |
||
345 | * @param OutputInterface $output |
||
346 | * @return false|array |
||
347 | */ |
||
348 | private function stripTables(InputInterface $input, OutputInterface $output) |
||
367 | |||
368 | /** |
||
369 | * Commands which filter mysql data. Piped to mysqldump command |
||
370 | * |
||
371 | * @return string |
||
372 | */ |
||
373 | protected function postDumpPipeCommands() |
||
374 | { |
||
375 | return ' | sed -e ' . escapeshellarg('s/DEFINER[ ]*=[ ]*[^*]*\*/\*/'); |
||
376 | } |
||
377 | |||
378 | /** |
||
379 | * @param InputInterface $input |
||
380 | * @param OutputInterface $output |
||
381 | * @param AbstractCompressor $compressor |
||
382 | * @return string |
||
383 | */ |
||
384 | protected function getFileName( |
||
385 | InputInterface $input, |
||
386 | OutputInterface $output, |
||
387 | AbstractCompressor $compressor |
||
388 | ) { |
||
389 | $namePrefix = ''; |
||
390 | $nameSuffix = ''; |
||
391 | $nameExtension = '.sql'; |
||
392 | |||
393 | if ($input->getOption('add-time') !== false) { |
||
394 | $timeStamp = date('Y-m-d_His'); |
||
395 | |||
396 | if ($input->getOption('add-time') == 'suffix') { |
||
397 | $nameSuffix = '_' . $timeStamp; |
||
398 | } else { |
||
399 | $namePrefix = $timeStamp . '_'; |
||
400 | } |
||
401 | } |
||
402 | |||
403 | if ( |
||
404 | ( |
||
405 | ($fileName = $input->getArgument('filename')) === null |
||
406 | || ($isDir = is_dir($fileName)) |
||
407 | ) |
||
408 | && !$input->getOption('stdout') |
||
409 | ) { |
||
410 | $defaultName = $namePrefix . $this->dbSettings['dbname'] . $nameSuffix . $nameExtension; |
||
411 | if (isset($isDir) && $isDir) { |
||
412 | $defaultName = rtrim($fileName, '/') . '/' . $defaultName; |
||
413 | } |
||
414 | if (!$input->getOption('force')) { |
||
415 | /** @var DialogHelper $dialog */ |
||
416 | $dialog = $this->getHelper('dialog'); |
||
417 | $fileName = $dialog->ask( |
||
418 | $output, |
||
419 | '<question>Filename for SQL dump:</question> [<comment>' . $defaultName . '</comment>]', |
||
420 | $defaultName |
||
421 | ); |
||
422 | } else { |
||
423 | $fileName = $defaultName; |
||
424 | } |
||
425 | } else { |
||
426 | if ($input->getOption('add-time')) { |
||
427 | $pathParts = pathinfo($fileName); |
||
428 | $fileName = ($pathParts['dirname'] == '.' ? '' : $pathParts['dirname'] . '/') . |
||
429 | $namePrefix . $pathParts['filename'] . $nameSuffix . '.' . $pathParts['extension']; |
||
430 | } |
||
431 | } |
||
432 | |||
433 | $fileName = $compressor->getFileName($fileName); |
||
434 | |||
435 | return $fileName; |
||
436 | } |
||
437 | |||
438 | /** |
||
439 | * @param InputInterface $input |
||
440 | * @return bool |
||
441 | */ |
||
442 | private function nonCommandOutput(InputInterface $input) |
||
449 | } |
||
450 |
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.