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 Tasks 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 Tasks, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
30 | abstract class Tasks extends Task |
||
31 | { |
||
32 | /** |
||
33 | * @var \Netresearch\Kite\Service\Factory |
||
34 | */ |
||
35 | protected $factory; |
||
36 | |||
37 | /** |
||
38 | * @var bool|array |
||
39 | */ |
||
40 | private $isPrepare; |
||
41 | |||
42 | /** |
||
43 | * @var \Netresearch\Kite\Task[] |
||
44 | */ |
||
45 | private $tasks = array(); |
||
46 | |||
47 | /** |
||
48 | * @var array |
||
49 | */ |
||
50 | private $deferredTasks = array(); |
||
51 | |||
52 | /** |
||
53 | * @var bool |
||
54 | */ |
||
55 | private $started = false; |
||
56 | |||
57 | /** |
||
58 | * @var bool |
||
59 | */ |
||
60 | private $initialized = false; |
||
61 | |||
62 | /** |
||
63 | * @var bool |
||
64 | */ |
||
65 | private $isWorkflow = false; |
||
66 | |||
67 | /** |
||
68 | * Tasks constructor. |
||
69 | * |
||
70 | * @param Variables $parent Parent object (Task/Job/Workflow) |
||
71 | */ |
||
72 | public function __construct(Variables $parent) |
||
77 | |||
78 | /** |
||
79 | * Clone and reparent the tasks to $this |
||
80 | * |
||
81 | * @return void |
||
82 | */ |
||
83 | function __clone() |
||
99 | |||
100 | |||
101 | /** |
||
102 | * Configures the available options |
||
103 | * |
||
104 | * @return array |
||
105 | */ |
||
106 | View Code Duplication | protected function configureVariables() |
|
128 | |||
129 | /** |
||
130 | * Called from parent task as soon as task is ready to run - which doesn't |
||
131 | * necessarely mean that it'll be run. |
||
132 | * |
||
133 | * @return void |
||
134 | */ |
||
135 | protected function initialize() |
||
145 | |||
146 | |||
147 | /** |
||
148 | * Override to create the tasks from the according options |
||
149 | * |
||
150 | * @param string $name Variable name |
||
151 | * @param mixed $value Variable value |
||
152 | * |
||
153 | * @return void |
||
154 | */ |
||
155 | public function offsetSet($name, $value) |
||
194 | |||
195 | /** |
||
196 | * Run an array of tasks |
||
197 | * |
||
198 | * @return $this |
||
199 | */ |
||
200 | public function run() |
||
268 | |||
269 | /** |
||
270 | * Adds tasks that should be run before/after the task with $name |
||
271 | * |
||
272 | * @param array $tasks The tasks to add the deferred tasks to |
||
273 | * @param string $type "before" or "after" |
||
274 | * @param string $name The task name |
||
275 | * |
||
276 | * @return int |
||
277 | */ |
||
278 | private function addDeferredTasks(&$tasks, $type, $name) |
||
293 | |||
294 | /** |
||
295 | * Run a task |
||
296 | * |
||
297 | * @param Task $task The task |
||
298 | * |
||
299 | * @internal Use addTask unless you know what you're doing |
||
300 | * |
||
301 | * @return mixed|null The task return value or null when if failed or dry run |
||
302 | */ |
||
303 | protected function runTask(Task $task) |
||
331 | |||
332 | /** |
||
333 | * Add a task - or run it immediately when $this->started |
||
334 | * |
||
335 | * @param Task $task The task |
||
336 | * |
||
337 | * @return $this|mixed $this or the task return value when this is running |
||
338 | */ |
||
339 | public function addTask(Task $task) |
||
368 | |||
369 | /** |
||
370 | * Setup and add (which eventually runs) a task |
||
371 | * |
||
372 | * @param string|array $type The task type or configuration |
||
373 | * @param array $options The options |
||
374 | * |
||
375 | * @return \Netresearch\Kite\Task|mixed The task or the task return when !$this->prepare |
||
376 | */ |
||
377 | private function createAndAddTask($type, array $options = array()) |
||
397 | |||
398 | /** |
||
399 | * Makes that the next fetched task (from the methods below) |
||
400 | * is not added to the workflow |
||
401 | * |
||
402 | * @return $this |
||
403 | */ |
||
404 | public function prepare() |
||
409 | |||
410 | /** |
||
411 | * Execute the next fetched task before given $task |
||
412 | * |
||
413 | * @param Task|string $task Task or task name |
||
414 | * |
||
415 | * @return $this |
||
416 | */ |
||
417 | public function before($task) |
||
422 | |||
423 | /** |
||
424 | * Execute the next fetched task after given $task |
||
425 | * |
||
426 | * @param Task|string $task Task or task name |
||
427 | * |
||
428 | * @return $this |
||
429 | */ |
||
430 | public function after($task) |
||
435 | |||
436 | // Following are shortcuts to create and eventually run tasks |
||
437 | |||
438 | /** |
||
439 | * Answer a question |
||
440 | * |
||
441 | * @param string $question The question |
||
442 | * @param string $default The default value |
||
443 | * |
||
444 | * @return mixed|\Netresearch\Kite\Task |
||
445 | */ |
||
446 | public function answer($question, $default = null) |
||
450 | |||
451 | /** |
||
452 | * Run a callback |
||
453 | * |
||
454 | * @param callable $callback The callback |
||
455 | * |
||
456 | * @return mixed|\Netresearch\Kite\Task\CallbackTask |
||
457 | */ |
||
458 | public function callback($callback) |
||
462 | |||
463 | /** |
||
464 | * Ask a selection question |
||
465 | * |
||
466 | * @param string $question The question |
||
467 | * @param array $choices The choices |
||
468 | * @param mixed $default Default value |
||
469 | * |
||
470 | * @return mixed|\Netresearch\Kite\Task\ChooseTask |
||
471 | */ |
||
472 | public function choose($question, array $choices, $default = null) |
||
476 | |||
477 | /** |
||
478 | * Clear the TYPO3 cache |
||
479 | * |
||
480 | * @param string $cmd The clearcache command |
||
481 | * |
||
482 | * @return null|\Netresearch\Kite\Task\IncludeTask |
||
483 | */ |
||
484 | public function clearCache($cmd = null) |
||
488 | |||
489 | /** |
||
490 | * Ask a confirmation question |
||
491 | * |
||
492 | * @param string $question The question |
||
493 | * @param bool $default Default value |
||
494 | * |
||
495 | * @return bool|\Netresearch\Kite\Task\ConfirmTask |
||
496 | */ |
||
497 | public function confirm($question, $default = true) |
||
501 | |||
502 | /** |
||
503 | * Run a composer command |
||
504 | * |
||
505 | * @param string $command The command to execute |
||
506 | * @param array|string|null $optArg Options and arguments |
||
507 | * {@see \Netresearch\Kite\Task\ShellTask} |
||
508 | * @param array $processSettings Settings for symfony process class |
||
509 | * |
||
510 | * @return string|\Netresearch\Kite\Task\ComposerTask |
||
511 | */ |
||
512 | public function composer($command, $optArg = null, array $processSettings = array()) |
||
516 | |||
517 | /** |
||
518 | * Evaluate an expression |
||
519 | * |
||
520 | * {@see http://symfony.com/doc/current/components/expression_language/syntax.html} |
||
521 | * |
||
522 | * @param string $expression The expression |
||
523 | * |
||
524 | * @return mixed|\Netresearch\Kite\Task\EvaluateTask |
||
525 | */ |
||
526 | public function evaluate($expression) |
||
530 | |||
531 | /** |
||
532 | * Break a tasks loop |
||
533 | * |
||
534 | * @param string $message The message |
||
535 | * |
||
536 | * @return void |
||
537 | */ |
||
538 | public function doBreak($message = '') |
||
542 | |||
543 | /** |
||
544 | * Exit - return code is return code of application |
||
545 | * (thus, when it's not 0 the message will be rendered as exception) |
||
546 | * |
||
547 | * @param string $message The message |
||
548 | * @param int $code The code |
||
549 | * |
||
550 | * @return void |
||
551 | */ |
||
552 | public function doExit($message = '', $code = 0) |
||
556 | |||
557 | /** |
||
558 | * Run a git command |
||
559 | * |
||
560 | * @param string $command The command to execute |
||
561 | * @param string|null $cwd The directory to change into before execution |
||
562 | * @param array|string|null $optArg Options and arguments |
||
563 | * {@see \Netresearch\Kite\Task\ShellTask} |
||
564 | * @param array $processSettings Settings for symfony process class |
||
565 | * |
||
566 | * @return Task\GitTask|string |
||
567 | */ |
||
568 | public function git($command, $cwd = null, $optArg = null, array $processSettings = array()) |
||
572 | |||
573 | /** |
||
574 | * Run a workflow for each of the $array's values. |
||
575 | * |
||
576 | * @param array|\Traversable $array The object to iterate over |
||
577 | * @param string|array $as Either string for |
||
578 | * foreach ($array as $as) |
||
579 | * or array for |
||
580 | * foreach($array as key($as) => current($as)) |
||
581 | * @param string|null $workflow Optional workflow class name |
||
582 | * |
||
583 | * @return array|\Netresearch\Kite\Task\IterateTask |
||
584 | */ |
||
585 | public function iterate($array, $as, $workflow = null) |
||
593 | |||
594 | /** |
||
595 | * Do something on the filesystem |
||
596 | * |
||
597 | * @return \Netresearch\Kite\Task\FsTask |
||
598 | */ |
||
599 | public function fs() |
||
603 | |||
604 | /** |
||
605 | * Output a message |
||
606 | * |
||
607 | * @param string $message The message |
||
608 | * @param int|bool $severityOrNewLine Severity or whether to print a newline |
||
609 | * @param bool $newLine Whether to print a newline |
||
610 | * |
||
611 | * @return mixed|\Netresearch\Kite\Task\OutputTask |
||
612 | */ |
||
613 | public function output($message, $severityOrNewLine = OutputInterface::VERBOSITY_NORMAL, $newLine = true) |
||
623 | |||
624 | /** |
||
625 | * Execute a command remote |
||
626 | * |
||
627 | * @param string $command The command to execute |
||
628 | * @param string|null $cwd The directory to change into before execution |
||
629 | * @param array|string|null $optArg Options and arguments |
||
630 | * {@see \Netresearch\Kite\Task\ShellTask} |
||
631 | * @param array $processSettings Settings for symfony process class |
||
632 | * |
||
633 | * @return Task\RemoteShellTask|string |
||
634 | */ |
||
635 | public function remoteShell($command, $cwd = null, $optArg = null, array $processSettings = array()) |
||
639 | |||
640 | /** |
||
641 | * Rsync from/to somewhere - prefix $from/$to with {node}: to rsync from/to nodes |
||
642 | * |
||
643 | * @param string $from From |
||
644 | * @param string $to To |
||
645 | * @param array $options Options for rsync |
||
646 | * @param array $exclude Files/dirs to exclude |
||
647 | * @param array $include Files/dirs to explicitely include |
||
648 | * |
||
649 | * @return string|\Netresearch\Kite\Task\RsyncTask |
||
650 | */ |
||
651 | public function rsync($from, $to, array $options = array(), array $exclude = array(), array $include = array()) |
||
655 | |||
656 | /** |
||
657 | * Migrate the TYPO3 schema definitions from ext_table.sql files |
||
658 | * |
||
659 | * @return string|SchemaMigrationTask |
||
660 | */ |
||
661 | public function schemaMigration() |
||
665 | |||
666 | /** |
||
667 | * Upload a file via scp |
||
668 | * |
||
669 | * @param string $from File to upload (prefix with {node}: to download) |
||
670 | * @param string $to Path to upload to (prefix with {node}: to upload) |
||
671 | * |
||
672 | * @return mixed|\Netresearch\Kite\Task |
||
673 | */ |
||
674 | public function scp($from, $to) |
||
678 | |||
679 | /** |
||
680 | * Execute a command locally |
||
681 | * |
||
682 | * @param string $command The command to execute |
||
683 | * @param string|null $cwd The directory to change into before execution |
||
684 | * @param array|string|null $optArg Options and arguments |
||
685 | * {@see \Netresearch\Kite\Task\ShellTask} |
||
686 | * @param array $processSettings Settings for symfony process class |
||
687 | * |
||
688 | * @return Task\ShellTask|string |
||
689 | */ |
||
690 | public function shell($command, $cwd = null, $optArg = null, array $processSettings = array()) |
||
694 | |||
695 | /** |
||
696 | * Run tasks as sub tasks |
||
697 | * |
||
698 | * @param string|array $workflowOrOptions Options for the class factory or workflow class name |
||
699 | * @param array $workflowOptions Options for the workflow (when $workflowOrOptions is string) |
||
700 | * |
||
701 | * @return Task\SubTask|Workflow |
||
702 | */ |
||
703 | public function sub($workflowOrOptions = array(), array $workflowOptions = array()) |
||
710 | |||
711 | /** |
||
712 | * Run tasks as sub tasks and catch exceptions |
||
713 | * |
||
714 | * @param string $errorMessage Error message to display on failure |
||
715 | * |
||
716 | * @return \Netresearch\Kite\Task\TryCatchTask |
||
717 | */ |
||
718 | public function tryCatch($errorMessage = null) |
||
722 | |||
723 | /** |
||
724 | * Create a Tar archive from the file or files in $file |
||
725 | * |
||
726 | * @param string|array $files File(s) to tar |
||
727 | * @param string $toFile Path to tar file |
||
728 | * |
||
729 | * @return mixed|\Netresearch\Kite\Task\TarTask |
||
730 | */ |
||
731 | public function tar($files, $toFile) |
||
735 | } |
||
736 | ?> |
||
737 |
Adding explicit visibility (
private
,protected
, orpublic
) is generally recommend to communicate to other developers how, and from where this method is intended to be used.