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 Model 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 Model, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
27 | abstract class Model extends Component |
||
28 | { |
||
29 | |||
30 | use ModelRecordBehavior; |
||
31 | |||
32 | /** |
||
33 | * @var BaseModel[] |
||
34 | */ |
||
35 | protected $_cacheAll; |
||
36 | |||
37 | /** |
||
38 | * @var BaseModel[] |
||
39 | */ |
||
40 | protected $_cacheById = []; |
||
41 | |||
42 | |||
43 | /******************************************* |
||
44 | * MODEL CLASSES |
||
45 | *******************************************/ |
||
46 | |||
47 | /** |
||
48 | * @return string |
||
49 | */ |
||
50 | public abstract static function modelClass(): string; |
||
51 | |||
52 | /** |
||
53 | * @return string |
||
54 | */ |
||
55 | public static function modelClassInstance(): string |
||
59 | |||
60 | /******************************************* |
||
61 | * CREATE |
||
62 | *******************************************/ |
||
63 | |||
64 | /** |
||
65 | * @param array $config |
||
66 | * @param string|null $toScenario |
||
67 | * @throws InvalidConfigException |
||
68 | * @return BaseModel |
||
69 | */ |
||
70 | View Code Duplication | public function create($config = [], string $toScenario = null): BaseModel |
|
93 | |||
94 | /** |
||
95 | * @param Record $record |
||
96 | * @param string|null $toScenario |
||
97 | * @throws InvalidConfigException |
||
98 | * @return BaseModel |
||
99 | */ |
||
100 | protected function createFromRecord(Record $record, string $toScenario = null): BaseModel |
||
119 | |||
120 | /******************************************* |
||
121 | * FIND/GET ALL |
||
122 | *******************************************/ |
||
123 | |||
124 | /** |
||
125 | * @param string $toScenario |
||
126 | * @return BaseModel[] |
||
127 | */ |
||
128 | View Code Duplication | public function findAll(string $toScenario = null) |
|
152 | |||
153 | /** |
||
154 | * @param string $toScenario |
||
155 | * @return BaseModel[] |
||
156 | * @throws ModelNotFoundException |
||
157 | */ |
||
158 | public function getAll(string $toScenario = null): array |
||
170 | |||
171 | /******************************************* |
||
172 | * FIND/GET |
||
173 | *******************************************/ |
||
174 | |||
175 | /** |
||
176 | * @param $identifier |
||
177 | * @param string $toScenario |
||
178 | * @return BaseModel|null |
||
179 | */ |
||
180 | public function find($identifier, string $toScenario = null) |
||
206 | |||
207 | /** |
||
208 | * @param $identifier |
||
209 | * @param string $toScenario |
||
210 | * @return BaseModel |
||
211 | * @throws ModelNotFoundException |
||
212 | */ |
||
213 | public function get($identifier, string $toScenario = null): BaseModel |
||
226 | |||
227 | /******************************************* |
||
228 | * FIND/GET BY ID |
||
229 | *******************************************/ |
||
230 | |||
231 | /** |
||
232 | * @param int $id |
||
233 | * @param string|null $toScenario |
||
234 | * @return BaseModel|null |
||
235 | */ |
||
236 | View Code Duplication | public function findById(int $id, string $toScenario = null) |
|
261 | |||
262 | /** |
||
263 | * @param int $id |
||
264 | * @param string|null $toScenario |
||
265 | * @return BaseModel |
||
266 | * @throws ModelNotFoundException |
||
267 | */ |
||
268 | View Code Duplication | public function getById(int $id, string $toScenario = null): BaseModel |
|
281 | |||
282 | /** |
||
283 | * @param int $id |
||
284 | * @param string|null $toScenario |
||
285 | * @return BaseModel|null |
||
286 | */ |
||
287 | public function freshFindById(int $id, string $toScenario = null) |
||
301 | |||
302 | /** |
||
303 | * @param int $id |
||
304 | * @param string|null $toScenario |
||
305 | * @return BaseModel |
||
306 | * @throws ModelNotFoundException |
||
307 | */ |
||
308 | View Code Duplication | public function freshGetById(int $id, string $toScenario = null): BaseModel |
|
320 | |||
321 | /******************************************* |
||
322 | * FIND/GET BY QUERY |
||
323 | *******************************************/ |
||
324 | |||
325 | /** |
||
326 | * @param QueryInterface $query |
||
327 | * @param string $toScenario |
||
328 | * @return BaseModel[] |
||
329 | */ |
||
330 | View Code Duplication | public function findAllByQuery(QueryInterface $query, string $toScenario = null): array |
|
342 | |||
343 | /** |
||
344 | * @param QueryInterface $query |
||
345 | * @param string $toScenario |
||
346 | * @return BaseModel|null |
||
347 | */ |
||
348 | View Code Duplication | public function findByQuery(QueryInterface $query, string $toScenario = null) |
|
359 | |||
360 | /******************************************* |
||
361 | * FIND/GET BY CONDITION |
||
362 | *******************************************/ |
||
363 | |||
364 | /** |
||
365 | * @param $condition |
||
366 | * @param string $toScenario |
||
367 | * @return BaseModel[] |
||
368 | */ |
||
369 | public function findAllByCondition($condition, string $toScenario = null): array |
||
386 | |||
387 | /** |
||
388 | * @param $condition |
||
389 | * @param string $toScenario |
||
390 | * @return BaseModel[] |
||
391 | * @throws ModelNotFoundException |
||
392 | */ |
||
393 | public function getAllByCondition($condition, string $toScenario = null): array |
||
405 | |||
406 | /** |
||
407 | * @param $condition |
||
408 | * @param string $toScenario |
||
409 | * @return BaseModel|null |
||
410 | */ |
||
411 | View Code Duplication | public function findByCondition($condition, string $toScenario = null) |
|
422 | |||
423 | /** |
||
424 | * @param $condition |
||
425 | * @param string $toScenario |
||
426 | * @return BaseModel |
||
427 | * @throws ModelNotFoundException |
||
428 | */ |
||
429 | public function getByCondition($condition, string $toScenario = null): BaseModel |
||
441 | |||
442 | /******************************************* |
||
443 | * FIND/GET BY CRITERIA |
||
444 | *******************************************/ |
||
445 | |||
446 | /** |
||
447 | * @param $criteria |
||
448 | * @param string $toScenario |
||
449 | * @return BaseModel[] |
||
450 | */ |
||
451 | View Code Duplication | public function findAllByCriteria($criteria, string $toScenario = null): array |
|
469 | |||
470 | /** |
||
471 | * @param $criteria |
||
472 | * @param string $toScenario |
||
473 | * @return BaseModel[] |
||
474 | * @throws ModelNotFoundException |
||
475 | */ |
||
476 | public function getAllByCriteria($criteria, string $toScenario = null): array |
||
488 | |||
489 | /** |
||
490 | * @param $criteria |
||
491 | * @param string $toScenario |
||
492 | * @return BaseModel|null |
||
493 | */ |
||
494 | View Code Duplication | public function findByCriteria($criteria, string $toScenario = null) |
|
505 | |||
506 | /** |
||
507 | * @param $criteria |
||
508 | * @param string $toScenario |
||
509 | * @return BaseModel |
||
510 | * @throws ModelNotFoundException |
||
511 | */ |
||
512 | public function getByCriteria($criteria, string $toScenario = null): BaseModel |
||
524 | |||
525 | |||
526 | /******************************************* |
||
527 | * FIND/GET BY RECORD |
||
528 | *******************************************/ |
||
529 | |||
530 | /** |
||
531 | * @param Record $record |
||
532 | * @param string $toScenario |
||
533 | * @return BaseModel |
||
534 | */ |
||
535 | View Code Duplication | public function findByRecord(Record $record, string $toScenario = null): BaseModel |
|
552 | |||
553 | /** |
||
554 | * @param Record $record |
||
555 | * @param string $toScenario |
||
556 | * @return BaseModel |
||
557 | */ |
||
558 | public function getByRecord(Record $record, string $toScenario = null): BaseModel |
||
562 | |||
563 | |||
564 | /******************************************* |
||
565 | * CACHE |
||
566 | *******************************************/ |
||
567 | |||
568 | /** |
||
569 | * @param $identifier |
||
570 | * @return BaseModel|null |
||
571 | */ |
||
572 | View Code Duplication | public function findCache($identifier) |
|
588 | |||
589 | /** |
||
590 | * Find an existing cache by ID |
||
591 | * |
||
592 | * @param $id |
||
593 | * @return BaseModel|null |
||
594 | */ |
||
595 | public function findCacheById(int $id) |
||
608 | |||
609 | /** |
||
610 | * Identify whether in cache by ID |
||
611 | * |
||
612 | * @param $id |
||
613 | * @return bool |
||
614 | */ |
||
615 | protected function isCachedById(int $id) |
||
619 | |||
620 | /** |
||
621 | * @param BaseModel $model |
||
622 | * @return $this |
||
623 | */ |
||
624 | protected function cacheById(BaseModel $model) |
||
638 | |||
639 | /** |
||
640 | * @param Record $record |
||
641 | * @return BaseModel|null |
||
642 | */ |
||
643 | public function findCacheByRecord(Record $record) |
||
655 | |||
656 | /** |
||
657 | * @param BaseModel $model |
||
658 | * @return static |
||
659 | */ |
||
660 | public function addToCache(BaseModel $model) |
||
667 | |||
668 | |||
669 | /******************************************* |
||
670 | * FIND/GET RECORD BY ID |
||
671 | *******************************************/ |
||
672 | |||
673 | /** |
||
674 | * @param int $id |
||
675 | * @param string $toScenario |
||
676 | * @return Record|null |
||
677 | */ |
||
678 | public function findRecordById(int $id, string $toScenario = null) |
||
687 | |||
688 | /** |
||
689 | * @param int $id |
||
690 | * @param string|null $toScenario |
||
691 | * @return Record |
||
692 | */ |
||
693 | public function getRecordById(int $id, string $toScenario = null): Record |
||
702 | |||
703 | |||
704 | /******************************************* |
||
705 | * EXCEPTIONS |
||
706 | *******************************************/ |
||
707 | |||
708 | /** |
||
709 | * @throws ModelNotFoundException |
||
710 | */ |
||
711 | protected function notFoundException() |
||
721 | |||
722 | /** |
||
723 | * @param int|null $id |
||
724 | * @throws ModelNotFoundException |
||
725 | */ |
||
726 | protected function notFoundByIdException(int $id = null) |
||
737 | |||
738 | /** |
||
739 | * @param null $criteria |
||
740 | * @throws ModelNotFoundException |
||
741 | */ |
||
742 | protected function notFoundByCriteriaException($criteria = null) |
||
753 | |||
754 | /** |
||
755 | * @param null $condition |
||
756 | * @throws ModelNotFoundException |
||
757 | */ |
||
758 | protected function notFoundByConditionException($condition = null) |
||
769 | |||
770 | } |
||
771 |