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 MemoryWorkflowStore 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 MemoryWorkflowStore, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
31 | class MemoryWorkflowStore implements WorkflowStoreInterface |
||
32 | { |
||
33 | /** |
||
34 | * @var SimpleWorkflowEntry[] |
||
35 | */ |
||
36 | protected static $entryCache = []; |
||
37 | |||
38 | /** |
||
39 | * @var SplObjectStorage[]|SimpleStep[] |
||
40 | */ |
||
41 | protected static $currentStepsCache = []; |
||
42 | |||
43 | /** |
||
44 | * @var SplObjectStorage[]|SimpleStep[] |
||
45 | */ |
||
46 | protected static $historyStepsCache = []; |
||
47 | |||
48 | /** |
||
49 | * @var array |
||
50 | */ |
||
51 | protected static $propertySetCache = []; |
||
52 | |||
53 | /** |
||
54 | * @var int |
||
55 | */ |
||
56 | protected static $globalEntryId = 1; |
||
57 | |||
58 | /** |
||
59 | * @var int |
||
60 | */ |
||
61 | protected static $globalStepId = 1; |
||
62 | |||
63 | /** |
||
64 | * Вызывается один раз, при инициализации хранилища |
||
65 | * |
||
66 | * @param array $props |
||
67 | * @throws StoreException |
||
68 | */ |
||
69 | 20 | public function init(array $props = []) |
|
73 | |||
74 | /** |
||
75 | * Возвращает PropertySet that связанный с данным экземпляром workflow |
||
76 | * @param integer $entryId id workflow |
||
77 | * @return PropertySetInterface |
||
78 | * @throws StoreException |
||
79 | * @throws \OldTown\PropertySet\Exception\RuntimeException |
||
80 | * @throws \OldTown\Workflow\Exception\ArgumentNotNumericException |
||
81 | */ |
||
82 | 22 | View Code Duplication | public function getPropertySet($entryId) |
99 | |||
100 | /** |
||
101 | * Создаем экземпляр PropertySet |
||
102 | * |
||
103 | * @return PropertySetInterface |
||
104 | */ |
||
105 | 19 | protected function createPropertySet() |
|
109 | |||
110 | //~ Methods //////////////////////////////////////////////////////////////// |
||
111 | |||
112 | /** |
||
113 | * Устанавливает статус для сущности workflow с заданным id |
||
114 | * |
||
115 | * @param int $entryId |
||
116 | * @param int $state |
||
117 | * |
||
118 | * @return $this |
||
119 | * @throws StoreException |
||
120 | * @throws NotFoundWorkflowEntryException |
||
121 | * @throws ArgumentNotNumericException |
||
122 | * @throws InvalidWorkflowEntryException |
||
123 | */ |
||
124 | 17 | public function setEntryState($entryId, $state) |
|
130 | |||
131 | /** |
||
132 | * Ищет сущность workflow с заданным id во внутреннем кеше |
||
133 | * |
||
134 | * @param int $entryId |
||
135 | * |
||
136 | * @return WorkflowEntryInterface |
||
137 | * @throws NotFoundWorkflowEntryException |
||
138 | * @throws ArgumentNotNumericException |
||
139 | * @throws InvalidWorkflowEntryException |
||
140 | */ |
||
141 | 20 | public function findEntry($entryId) |
|
163 | |||
164 | /** |
||
165 | * Создает экземпляр workflow |
||
166 | * |
||
167 | * @param string $workflowName |
||
168 | * |
||
169 | * @return SimpleWorkflowEntry |
||
170 | */ |
||
171 | 32 | public function createEntry($workflowName) |
|
179 | |||
180 | /** |
||
181 | * Создает новый шаг |
||
182 | * |
||
183 | * @param integer $entryId |
||
184 | * @param integer $stepId |
||
185 | * @param string $owner |
||
186 | * @param DateTime $startDate |
||
187 | * @param DateTime $dueDate |
||
188 | * @param string $status |
||
189 | * @param array $previousIds |
||
190 | * |
||
191 | * @return SimpleStep |
||
192 | */ |
||
193 | 20 | public function createCurrentStep($entryId, $stepId, $owner = null, DateTime $startDate, DateTime $dueDate = null, $status, array $previousIds = []) |
|
208 | |||
209 | /** |
||
210 | * Ищет текущий набор шагов для сущности workflow c заданным id |
||
211 | * |
||
212 | * @param Integer $entryId |
||
213 | * |
||
214 | * @return SimpleStep[]|SplObjectStorage |
||
215 | * @throws ArgumentNotNumericException |
||
216 | */ |
||
217 | 21 | View Code Duplication | public function findCurrentSteps($entryId) |
232 | |||
233 | /** |
||
234 | * Пометить текущий шаг как выполненный |
||
235 | * |
||
236 | * @param StepInterface $step |
||
237 | * @param integer $actionId |
||
238 | * @param DateTime $finishDate |
||
239 | * @param string $status |
||
240 | * @param string $caller |
||
241 | * |
||
242 | * @return null|SimpleStep |
||
243 | * |
||
244 | * @throws ArgumentNotNumericException |
||
245 | */ |
||
246 | 8 | public function markFinished(StepInterface $step, $actionId, DateTime $finishDate, $status, $caller) |
|
264 | |||
265 | /** |
||
266 | * Сбрасывает внутренние кеш хранилища. |
||
267 | */ |
||
268 | 34 | public static function reset() |
|
277 | |||
278 | /** |
||
279 | * Перенос шага в историю |
||
280 | * |
||
281 | * @param StepInterface $step |
||
282 | * |
||
283 | * @return void |
||
284 | * |
||
285 | * @throws \OldTown\Workflow\Exception\ArgumentNotNumericException |
||
286 | */ |
||
287 | 8 | public function moveToHistory(StepInterface $step) |
|
313 | |||
314 | /** |
||
315 | * Поиск по истории шагов |
||
316 | * |
||
317 | * @param $entryId |
||
318 | * |
||
319 | * @return SimpleStep[]|SplObjectStorage |
||
320 | */ |
||
321 | 2 | public function findHistorySteps($entryId) |
|
329 | |||
330 | /** |
||
331 | * Поиск в хранилище |
||
332 | * |
||
333 | * @param WorkflowExpressionQuery $query |
||
334 | * |
||
335 | * @return array |
||
336 | * |
||
337 | * @throws \OldTown\Workflow\Exception\InvalidArgumentException |
||
338 | */ |
||
339 | 13 | public function query(WorkflowExpressionQuery $query) |
|
351 | |||
352 | /** |
||
353 | * Реализация поиска в харинилище |
||
354 | * |
||
355 | * @param integer $entryId |
||
356 | * @param WorkflowExpressionQuery $query |
||
357 | * |
||
358 | * @return bool |
||
359 | * |
||
360 | * @throws \OldTown\Workflow\Exception\InvalidArgumentException |
||
361 | */ |
||
362 | 12 | protected function queryInternal($entryId, WorkflowExpressionQuery $query) |
|
372 | |||
373 | // |
||
374 | |||
375 | /** |
||
376 | * Проверка выражения |
||
377 | * |
||
378 | * @param integer $entryId |
||
379 | * @param FieldExpression $expression |
||
380 | * |
||
381 | * @return bool |
||
382 | * |
||
383 | * @throws InvalidArgumentException |
||
384 | */ |
||
385 | 12 | private function checkExpression($entryId, FieldExpression $expression) |
|
582 | |||
583 | /** |
||
584 | * Проверка вложенных выражений |
||
585 | * |
||
586 | * @param integer $entryId |
||
587 | * @param NestedExpression $nestedExpression |
||
588 | * |
||
589 | * @return bool |
||
590 | * @throws InvalidArgumentException |
||
591 | */ |
||
592 | 3 | private function checkNestedExpression($entryId, NestedExpression $nestedExpression) |
|
620 | |||
621 | /** |
||
622 | * Сравнение дат |
||
623 | * |
||
624 | * @param DateTime $value1 |
||
625 | * @param DateTime $value2 |
||
626 | * @param integer $operator |
||
627 | * |
||
628 | * @return bool |
||
629 | * @throws InvalidArgumentException |
||
630 | */ |
||
631 | 2 | private function compareDate(DateTime $value1, DateTime $value2, $operator) |
|
650 | |||
651 | /** |
||
652 | * Сравнивает целые числа |
||
653 | * |
||
654 | * @param string $value1 |
||
655 | * @param string $value2 |
||
656 | * @param integer $operator |
||
657 | * |
||
658 | * @return bool |
||
659 | * |
||
660 | * @throws InvalidArgumentException |
||
661 | */ |
||
662 | 6 | private function compareLong($value1, $value2, $operator) |
|
681 | |||
682 | /** |
||
683 | * |
||
684 | * @todo поправить для юникода |
||
685 | * |
||
686 | * Сравнение строк |
||
687 | * |
||
688 | * @param $value1 |
||
689 | * @param $value2 |
||
690 | * @param $operator |
||
691 | * |
||
692 | * @return bool |
||
693 | * |
||
694 | * @throws \OldTown\Workflow\Exception\InvalidArgumentException |
||
695 | */ |
||
696 | 5 | private function compareText($value1, $value2, $operator) |
|
715 | } |
||
716 |
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.