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: