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 AbstractWorkflow 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 AbstractWorkflow, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
45 | abstract class AbstractWorkflow implements WorkflowInterface |
||
46 | { |
||
47 | /** |
||
48 | * @var string |
||
49 | */ |
||
50 | const CURRENT_STEPS = 'currentSteps'; |
||
51 | |||
52 | /** |
||
53 | * @var string |
||
54 | */ |
||
55 | const HISTORY_STEPS = 'historySteps'; |
||
56 | |||
57 | /** |
||
58 | * @var WorkflowContextInterface |
||
59 | */ |
||
60 | protected $context; |
||
61 | |||
62 | /** |
||
63 | * @var ConfigurationInterface |
||
64 | */ |
||
65 | protected $configuration; |
||
66 | |||
67 | |||
68 | /** |
||
69 | * @var TypeResolverInterface |
||
70 | */ |
||
71 | protected $typeResolver; |
||
72 | |||
73 | /** |
||
74 | * Логер |
||
75 | * |
||
76 | * @var LoggerInterface |
||
77 | */ |
||
78 | protected $log; |
||
79 | |||
80 | /** |
||
81 | * Резолвер для создания провайдеров отвечающих за исполнение функций, проверку условий, выполнение валидаторов и т.д. |
||
82 | * |
||
83 | * @var string |
||
84 | */ |
||
85 | protected $defaultTypeResolverClass = TypeResolver::class; |
||
86 | |||
87 | /** |
||
88 | * Карта переходов состояния процесса workflow |
||
89 | * |
||
90 | * @var null|array |
||
91 | */ |
||
92 | protected $mapEntryState; |
||
93 | |||
94 | /** |
||
95 | * Менеджер движков |
||
96 | * |
||
97 | * @var EngineManagerInterface |
||
98 | */ |
||
99 | protected $engineManager; |
||
100 | |||
101 | /** |
||
102 | * AbstractWorkflow constructor. |
||
103 | * |
||
104 | * @throws InternalWorkflowException |
||
105 | */ |
||
106 | 19 | public function __construct() |
|
111 | |||
112 | /** |
||
113 | * Устанавливает менеджер движков |
||
114 | * |
||
115 | * @return EngineManagerInterface |
||
116 | */ |
||
117 | 19 | public function getEngineManager() |
|
126 | |||
127 | /** |
||
128 | * Возвращает менеджер движков |
||
129 | * |
||
130 | * @param EngineManagerInterface $engineManager |
||
131 | * |
||
132 | * @return $this |
||
133 | */ |
||
134 | public function setEngineManager(EngineManagerInterface $engineManager) |
||
140 | |||
141 | /** |
||
142 | * Инициация карты переходов состояния процесса workflow |
||
143 | */ |
||
144 | 19 | protected function initMapEntryState() |
|
166 | |||
167 | /** |
||
168 | * Инициализация системы логирования |
||
169 | * |
||
170 | * @throws InternalWorkflowException |
||
171 | */ |
||
172 | 19 | protected function initLoger() |
|
180 | |||
181 | /** |
||
182 | * Инициализация workflow. Workflow нужно иницаилизровать прежде, чем выполнять какие либо действия. |
||
183 | * Workflow может быть инициализированно только один раз |
||
184 | * |
||
185 | * @param string $workflowName Имя workflow |
||
186 | * @param integer $initialAction Имя первого шага, с которого начинается workflow |
||
187 | * @param TransientVarsInterface $inputs Данные введеные пользователем |
||
188 | * |
||
189 | * @return integer |
||
190 | * |
||
191 | * @throws InternalWorkflowException |
||
192 | * @throws InvalidActionException |
||
193 | * @throws InvalidRoleException |
||
194 | * @throws \OldTown\Workflow\Exception\ArgumentNotNumericException |
||
195 | * @throws InvalidArgumentException |
||
196 | * @throws WorkflowException |
||
197 | */ |
||
198 | 19 | public function initialize($workflowName, $initialAction, TransientVarsInterface $inputs = null) |
|
248 | |||
249 | /** |
||
250 | * @param $id |
||
251 | * @param $inputs |
||
252 | * |
||
253 | * @return array |
||
254 | * |
||
255 | */ |
||
256 | 2 | public function getAvailableActions($id, TransientVarsInterface $inputs = null) |
|
324 | |||
325 | /** |
||
326 | * Создает хранилище переменных |
||
327 | * |
||
328 | * @param $class |
||
329 | * |
||
330 | * @return TransientVarsInterface |
||
331 | */ |
||
332 | protected function transientVarsFactory($class = BaseTransientVars::class) |
||
337 | |||
338 | /** |
||
339 | * |
||
340 | * |
||
341 | * Осуществляет переходл в новое состояние, для заданного процесса workflow |
||
342 | * |
||
343 | * @param integer $entryId id запущенного процесса workflow |
||
344 | * @param integer $actionId id действия, доступного та текущем шаеге процессса workflow |
||
345 | * @param TransientVarsInterface $inputs Входные данные для перехода |
||
346 | * |
||
347 | * @return void |
||
348 | * |
||
349 | * @throws WorkflowException |
||
350 | * @throws InvalidActionException |
||
351 | * @throws InvalidArgumentException |
||
352 | * @throws InternalWorkflowException |
||
353 | * @throws \OldTown\Workflow\Exception\ArgumentNotNumericException |
||
354 | */ |
||
355 | 8 | public function doAction($entryId, $actionId, TransientVarsInterface $inputs = null) |
|
410 | |||
411 | /** |
||
412 | * @param WorkflowDescriptor $wf |
||
413 | * @param $actionId |
||
414 | * @param TransientVarsInterface $transientVars |
||
415 | * @param PropertySetInterface $ps |
||
416 | * |
||
417 | * @return bool |
||
418 | */ |
||
419 | 8 | protected function isValidGlobalActions(WorkflowDescriptor $wf, $actionId, TransientVarsInterface $transientVars, PropertySetInterface $ps) |
|
435 | |||
436 | |||
437 | /** |
||
438 | * |
||
439 | * @param SplObjectStorage $currentSteps |
||
440 | * @param WorkflowDescriptor $wf |
||
441 | * @param $actionId |
||
442 | * @param TransientVarsInterface $transientVars |
||
443 | * @param PropertySetInterface $ps |
||
444 | * |
||
445 | * @return bool |
||
446 | * |
||
447 | * @throws \OldTown\Workflow\Exception\ArgumentNotNumericException |
||
448 | * @throws InternalWorkflowException |
||
449 | */ |
||
450 | 8 | protected function isValidActionsFromCurrentSteps(SplObjectStorage $currentSteps, WorkflowDescriptor $wf, $actionId, TransientVarsInterface $transientVars, PropertySetInterface $ps) |
|
479 | |||
480 | /** |
||
481 | * @param ActionDescriptor $action |
||
482 | * @param $id |
||
483 | * |
||
484 | * @return void |
||
485 | * |
||
486 | * @throws \OldTown\Workflow\Exception\ArgumentNotNumericException |
||
487 | * @throws InvalidArgumentException |
||
488 | * @throws InternalWorkflowException |
||
489 | */ |
||
490 | protected function checkImplicitFinish(ActionDescriptor $action, $id) |
||
518 | |||
519 | |||
520 | |||
521 | /** |
||
522 | * |
||
523 | * Check if the state of the specified workflow instance can be changed to the new specified one. |
||
524 | * |
||
525 | * @param integer $id The workflow instance id. |
||
526 | * @param integer $newState The new state id. |
||
527 | * |
||
528 | * @return boolean true if the state of the workflow can be modified, false otherwise. |
||
529 | * |
||
530 | * @throws InternalWorkflowException |
||
531 | */ |
||
532 | 16 | public function canModifyEntryState($id, $newState) |
|
541 | |||
542 | |||
543 | /** |
||
544 | * |
||
545 | * Возвращает коллекцию объектов описывающие состояние для текущего экземпляра workflow |
||
546 | * |
||
547 | * @param integer $entryId id экземпляра workflow |
||
548 | * |
||
549 | * @return SplObjectStorage|StepInterface[] |
||
550 | * |
||
551 | * @throws InternalWorkflowException |
||
552 | */ |
||
553 | public function getCurrentSteps($entryId) |
||
557 | |||
558 | /** |
||
559 | * Возвращает информацию о том в какие шаги, были осуществленны переходы, для процесса workflow с заданным id |
||
560 | * |
||
561 | * @param integer $entryId уникальный идентификатор процесса workflow |
||
562 | * |
||
563 | * @return StepInterface[]|SplObjectStorage список шагов |
||
564 | * |
||
565 | * @throws InternalWorkflowException |
||
566 | */ |
||
567 | public function getHistorySteps($entryId) |
||
571 | |||
572 | /** |
||
573 | * Получение шагов информации о шагах процесса workflow |
||
574 | * |
||
575 | * @param $entryId |
||
576 | * @param $type |
||
577 | * |
||
578 | * @return Spi\StepInterface[]|SplObjectStorage |
||
579 | * |
||
580 | * @throws InternalWorkflowException |
||
581 | */ |
||
582 | 19 | protected function getStepFromStorage($entryId, $type) |
|
602 | |||
603 | |||
604 | |||
605 | /** |
||
606 | * |
||
607 | * |
||
608 | * Modify the state of the specified workflow instance. |
||
609 | * @param integer $id The workflow instance id. |
||
610 | * @param integer $newState the new state to change the workflow instance to. |
||
611 | * |
||
612 | * @throws InvalidArgumentException |
||
613 | * @throws InvalidEntryStateException |
||
614 | * @throws InternalWorkflowException |
||
615 | */ |
||
616 | 16 | public function changeEntryState($id, $newState) |
|
654 | |||
655 | |||
656 | |||
657 | |||
658 | |||
659 | /** |
||
660 | * Проверяет имеет ли пользователь достаточно прав, что бы иниициировать вызываемый процесс |
||
661 | * |
||
662 | * @param string $workflowName имя workflow |
||
663 | * @param integer $initialAction id начального состояния |
||
664 | * @param TransientVarsInterface $inputs |
||
665 | * |
||
666 | * @return bool |
||
667 | * |
||
668 | * @throws InvalidArgumentException |
||
669 | * @throws WorkflowException |
||
670 | * @throws InternalWorkflowException |
||
671 | * @throws \OldTown\Workflow\Exception\ArgumentNotNumericException |
||
672 | */ |
||
673 | public function canInitialize($workflowName, $initialAction, TransientVarsInterface $inputs = null) |
||
716 | |||
717 | |||
718 | /** |
||
719 | * Проверяет имеет ли пользователь достаточно прав, что бы иниициировать вызываемый процесс |
||
720 | * |
||
721 | * @param string $workflowName имя workflow |
||
722 | * @param integer $initialAction id начального состояния |
||
723 | * @param TransientVarsInterface $transientVars |
||
724 | * |
||
725 | * @param PropertySetInterface $ps |
||
726 | * |
||
727 | * @return bool |
||
728 | * |
||
729 | * @throws \OldTown\Workflow\Exception\ArgumentNotNumericException |
||
730 | * @throws InvalidActionException |
||
731 | * @throws InternalWorkflowException |
||
732 | * @throws WorkflowException |
||
733 | */ |
||
734 | 19 | protected function canInitializeInternal($workflowName, $initialAction, TransientVarsInterface $transientVars, PropertySetInterface $ps) |
|
761 | |||
762 | /** |
||
763 | * Возвращает резолвер |
||
764 | * |
||
765 | * @return TypeResolverInterface |
||
766 | */ |
||
767 | 19 | public function getResolver() |
|
780 | |||
781 | /** |
||
782 | * Возвращает хранилище состояния workflow |
||
783 | * |
||
784 | * @return WorkflowStoreInterface |
||
785 | * |
||
786 | * @throws InternalWorkflowException |
||
787 | */ |
||
788 | 19 | protected function getPersistence() |
|
792 | |||
793 | /** |
||
794 | * Получить конфигурацию workflow. Метод также проверяет была ли иницилазированн конфигурация, если нет, то |
||
795 | * инициализирует ее. |
||
796 | * |
||
797 | * Если конфигурация не была установленна, то возвращает конфигурацию по умолчанию |
||
798 | * |
||
799 | * @return ConfigurationInterface|DefaultConfiguration Конфигурация которая была установленна |
||
800 | * |
||
801 | * @throws InternalWorkflowException |
||
802 | */ |
||
803 | 19 | public function getConfiguration() |
|
819 | |||
820 | /** |
||
821 | * @return LoggerInterface |
||
822 | */ |
||
823 | 17 | public function getLog() |
|
827 | |||
828 | /** |
||
829 | * @param LoggerInterface $log |
||
830 | * |
||
831 | * @return $this |
||
832 | * |
||
833 | * @throws InternalWorkflowException |
||
834 | */ |
||
835 | public function setLog($log) |
||
849 | |||
850 | |||
851 | /** |
||
852 | * Get the workflow descriptor for the specified workflow name. |
||
853 | * |
||
854 | * @param string $workflowName The workflow name. |
||
855 | * @return WorkflowDescriptor |
||
856 | * |
||
857 | * @throws InternalWorkflowException |
||
858 | */ |
||
859 | public function getWorkflowDescriptor($workflowName) |
||
869 | |||
870 | |||
871 | /** |
||
872 | * Executes a special trigger-function using the context of the given workflow instance id. |
||
873 | * Note that this method is exposed for Quartz trigger jobs, user code should never call it. |
||
874 | * |
||
875 | * @param integer $id The workflow instance id |
||
876 | * @param integer $triggerId The id of the special trigger-function |
||
877 | * |
||
878 | * @throws InvalidArgumentException |
||
879 | * @throws WorkflowException |
||
880 | * @throws InternalWorkflowException |
||
881 | * @throws \OldTown\Workflow\Exception\ArgumentNotNumericException |
||
882 | */ |
||
883 | public function executeTriggerFunction($id, $triggerId) |
||
908 | |||
909 | |||
910 | /** |
||
911 | * @param WorkflowDescriptor $wf |
||
912 | * @param StepInterface $step |
||
913 | * @param TransientVarsInterface $transientVars |
||
914 | * @param PropertySetInterface $ps |
||
915 | * |
||
916 | * @return array |
||
917 | * |
||
918 | * @throws InternalWorkflowException |
||
919 | * @throws WorkflowException |
||
920 | * @throws \OldTown\Workflow\Exception\ArgumentNotNumericException |
||
921 | */ |
||
922 | protected function getAvailableActionsForStep(WorkflowDescriptor $wf, StepInterface $step, TransientVarsInterface $transientVars, PropertySetInterface $ps) |
||
965 | |||
966 | /** |
||
967 | * @param ConfigurationInterface $configuration |
||
968 | * |
||
969 | * @return $this |
||
970 | */ |
||
971 | 19 | public function setConfiguration(ConfigurationInterface $configuration) |
|
977 | |||
978 | /** |
||
979 | * Возвращает состояние для текущего экземпляра workflow |
||
980 | * |
||
981 | * @param integer $id id экземпляра workflow |
||
982 | * @return integer id текущего состояния |
||
983 | * |
||
984 | * @throws InternalWorkflowException |
||
985 | */ |
||
986 | public function getEntryState($id) |
||
1002 | |||
1003 | |||
1004 | /** |
||
1005 | * Настройки хранилища |
||
1006 | * |
||
1007 | * @return array |
||
1008 | * |
||
1009 | * @throws InternalWorkflowException |
||
1010 | */ |
||
1011 | public function getPersistenceProperties() |
||
1015 | |||
1016 | |||
1017 | /** |
||
1018 | * Get the PropertySet for the specified workflow instance id. |
||
1019 | * @param integer $id The workflow instance id. |
||
1020 | * |
||
1021 | * @return PropertySetInterface |
||
1022 | * @throws InternalWorkflowException |
||
1023 | */ |
||
1024 | public function getPropertySet($id) |
||
1040 | |||
1041 | /** |
||
1042 | * @return string[] |
||
1043 | * |
||
1044 | * @throws InternalWorkflowException |
||
1045 | */ |
||
1046 | public function getWorkflowNames() |
||
1057 | |||
1058 | /** |
||
1059 | * @param TypeResolverInterface $typeResolver |
||
1060 | * |
||
1061 | * @return $this |
||
1062 | */ |
||
1063 | public function setTypeResolver(TypeResolverInterface $typeResolver) |
||
1069 | |||
1070 | |||
1071 | /** |
||
1072 | * Get a collection (Strings) of currently defined permissions for the specified workflow instance. |
||
1073 | * @param integer $id id the workflow instance id. |
||
1074 | * @param TransientVarsInterface $inputs inputs The inputs to the workflow instance. |
||
1075 | * |
||
1076 | * @return array A List of permissions specified currently (a permission is a string name). |
||
1077 | * |
||
1078 | */ |
||
1079 | public function getSecurityPermissions($id, TransientVarsInterface $inputs = null) |
||
1140 | |||
1141 | |||
1142 | /** |
||
1143 | * Get the name of the specified workflow instance. |
||
1144 | * |
||
1145 | * @param integer $id the workflow instance id. |
||
1146 | * |
||
1147 | * @return string |
||
1148 | * |
||
1149 | * @throws InternalWorkflowException |
||
1150 | */ |
||
1151 | public function getWorkflowName($id) |
||
1170 | |||
1171 | /** |
||
1172 | * Удаляет workflow |
||
1173 | * |
||
1174 | * @param string $workflowName |
||
1175 | * |
||
1176 | * @return bool |
||
1177 | * |
||
1178 | * @throws InternalWorkflowException |
||
1179 | */ |
||
1180 | public function removeWorkflowDescriptor($workflowName) |
||
1184 | |||
1185 | /** |
||
1186 | * @param $workflowName |
||
1187 | * @param WorkflowDescriptor $descriptor |
||
1188 | * @param $replace |
||
1189 | * |
||
1190 | * @return bool |
||
1191 | * |
||
1192 | * @throws InternalWorkflowException |
||
1193 | */ |
||
1194 | public function saveWorkflowDescriptor($workflowName, WorkflowDescriptor $descriptor, $replace) |
||
1200 | |||
1201 | |||
1202 | /** |
||
1203 | * Query the workflow store for matching instances |
||
1204 | * |
||
1205 | * @param WorkflowExpressionQuery $query |
||
1206 | * |
||
1207 | * @return array |
||
1208 | * |
||
1209 | * @throws InternalWorkflowException |
||
1210 | */ |
||
1211 | public function query(WorkflowExpressionQuery $query) |
||
1215 | |||
1216 | /** |
||
1217 | * @return string |
||
1218 | */ |
||
1219 | 19 | public function getDefaultTypeResolverClass() |
|
1223 | |||
1224 | /** |
||
1225 | * @param string $defaultTypeResolverClass |
||
1226 | * |
||
1227 | * @return $this |
||
1228 | */ |
||
1229 | public function setDefaultTypeResolverClass($defaultTypeResolverClass) |
||
1235 | |||
1236 | |||
1237 | /** |
||
1238 | * @return WorkflowContextInterface |
||
1239 | */ |
||
1240 | 19 | public function getContext() |
|
1244 | } |
||
1245 |
It seems like the type of the argument is not accepted by the function/method which you are calling.
In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.
We suggest to add an explicit type cast like in the following example: