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 Aggregate 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 Aggregate, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
16 | class Aggregate implements InternallyMappable |
||
17 | { |
||
18 | /** |
||
19 | * The Root Entity |
||
20 | * |
||
21 | * @var \Analogue\ORM\System\Wrappers\Wrapper |
||
22 | */ |
||
23 | protected $wrappedEntity; |
||
24 | |||
25 | /** |
||
26 | * Parent Root Aggregate |
||
27 | * |
||
28 | * @var \Analogue\ORM\System\Aggregate |
||
29 | */ |
||
30 | protected $parent; |
||
31 | |||
32 | /** |
||
33 | * Parent's relationship method |
||
34 | * |
||
35 | * @var string |
||
36 | */ |
||
37 | protected $parentRelationship; |
||
38 | |||
39 | /** |
||
40 | * Root Entity |
||
41 | * |
||
42 | * @var \Analogue\ORM\System\Aggregate |
||
43 | */ |
||
44 | protected $root; |
||
45 | |||
46 | /** |
||
47 | * An associative array containing entity's |
||
48 | * relationships converted to Aggregates |
||
49 | * |
||
50 | * @var array |
||
51 | */ |
||
52 | protected $relationships = []; |
||
53 | |||
54 | /** |
||
55 | * Relationship that need post-command synchronization |
||
56 | * |
||
57 | * @var array |
||
58 | */ |
||
59 | protected $needSync = []; |
||
60 | |||
61 | /** |
||
62 | * Mapper |
||
63 | * |
||
64 | * @var \Analogue\ORM\System\Mapper; |
||
65 | */ |
||
66 | protected $mapper; |
||
67 | |||
68 | /** |
||
69 | * Entity Map |
||
70 | * |
||
71 | * @var \Analogue\ORM\EntityMap; |
||
72 | */ |
||
73 | protected $entityMap; |
||
74 | |||
75 | /** |
||
76 | * Create a new Aggregated Entity instance |
||
77 | * |
||
78 | * @param mixed $entity |
||
79 | * @param Aggregate|null $parent |
||
80 | * @param string $parentRelationship |
||
81 | * @param Aggregate|null $root |
||
82 | * @throws MappingException |
||
83 | */ |
||
84 | public function __construct($entity, Aggregate $parent = null, $parentRelationship = null, Aggregate $root = null) |
||
102 | |||
103 | /** |
||
104 | * Parse Every relationships defined on the entity |
||
105 | * |
||
106 | * @throws MappingException |
||
107 | * @return void |
||
108 | */ |
||
109 | protected function parseRelationships() |
||
119 | |||
120 | /** |
||
121 | * Parse for values common to single & many relations |
||
122 | * |
||
123 | * @param string $relation |
||
124 | * @throws MappingException |
||
125 | * @return mixed|boolean |
||
126 | */ |
||
127 | protected function parseForCommonValues($relation) |
||
153 | |||
154 | /** |
||
155 | * Parse a 'single' relationship |
||
156 | * |
||
157 | * @param string $relation |
||
158 | * @throws MappingException |
||
159 | * @return boolean |
||
160 | */ |
||
161 | protected function parseSingleRelationship($relation) |
||
201 | |||
202 | /** |
||
203 | * Check if value isn't parent or root in the aggregate |
||
204 | * |
||
205 | * @param mixed |
||
206 | * @return boolean|null |
||
207 | */ |
||
208 | protected function isParentOrRoot($value) |
||
224 | |||
225 | /** |
||
226 | * Parse a 'many' relationship |
||
227 | * |
||
228 | * @param string $relation |
||
229 | * @throws MappingException |
||
230 | * @return boolean |
||
231 | */ |
||
232 | protected function parseManyRelationship($relation) |
||
264 | |||
265 | /** |
||
266 | * Return Entity's relationship attribute |
||
267 | * |
||
268 | * @param string $relation |
||
269 | * @throws MappingException |
||
270 | * @return mixed |
||
271 | */ |
||
272 | protected function getRelationshipValue($relation) |
||
282 | |||
283 | /** |
||
284 | * Create a child, aggregated entity |
||
285 | * |
||
286 | * @param mixed $entities |
||
287 | * @param string $relation |
||
288 | * @return array |
||
289 | */ |
||
290 | protected function createSubAggregates($entities, $relation) |
||
300 | |||
301 | /** |
||
302 | * Create a related subAggregate |
||
303 | * |
||
304 | * @param mixed $entity |
||
305 | * @param string $relation |
||
306 | * @throws MappingException |
||
307 | * @return self |
||
308 | */ |
||
309 | protected function createSubAggregate($entity, $relation) |
||
320 | |||
321 | /** |
||
322 | * Get the Entity's primary key attribute |
||
323 | * |
||
324 | * @return string|integer |
||
325 | */ |
||
326 | public function getEntityId() |
||
330 | |||
331 | /** |
||
332 | * Get the name of the primary key |
||
333 | * |
||
334 | * @return string |
||
335 | */ |
||
336 | public function getEntityKey() |
||
340 | |||
341 | /** |
||
342 | * Return the entity map for the current entity |
||
343 | * |
||
344 | * @return \Analogue\ORM\EntityMap |
||
345 | */ |
||
346 | public function getEntityMap() |
||
350 | |||
351 | /** |
||
352 | * Return the Entity's hash $class.$id |
||
353 | * |
||
354 | * @return string |
||
355 | */ |
||
356 | public function getEntityHash() |
||
360 | |||
361 | /** |
||
362 | * Get wrapped entity class |
||
363 | * |
||
364 | * @return string |
||
365 | */ |
||
366 | public function getEntityClass() |
||
370 | |||
371 | /** |
||
372 | * Return the Mapper's entity cache |
||
373 | * |
||
374 | * @return \Analogue\ORM\System\EntityCache |
||
375 | */ |
||
376 | protected function getEntityCache() |
||
380 | |||
381 | /** |
||
382 | * Get a relationship as an aggregated entities' array |
||
383 | * |
||
384 | * @param string $name |
||
385 | * @return array |
||
386 | */ |
||
387 | public function getRelationship($name) |
||
395 | |||
396 | /** |
||
397 | * [TO IMPLEMENT] |
||
398 | * |
||
399 | * @return array |
||
400 | */ |
||
401 | public function getPivotAttributes() |
||
405 | |||
406 | /** |
||
407 | * Get Non existing related entities from several relationships |
||
408 | * |
||
409 | * @param array $relationships |
||
410 | * @return array |
||
411 | */ |
||
412 | public function getNonExistingRelated(array $relationships) |
||
424 | |||
425 | /** |
||
426 | * Get non-existing related entities from a single relation |
||
427 | * |
||
428 | * @param string $relation |
||
429 | * @return array |
||
430 | */ |
||
431 | protected function getNonExistingFromRelation($relation) |
||
443 | |||
444 | /** |
||
445 | * Synchronize relationships if needed |
||
446 | */ |
||
447 | public function syncRelationships(array $relationships) |
||
457 | |||
458 | /** |
||
459 | * Synchronize a relationship attribute |
||
460 | * |
||
461 | * @param $relation |
||
462 | */ |
||
463 | protected function synchronize($relation) |
||
469 | |||
470 | /** |
||
471 | * Returns an array of Missing related Entities for the |
||
472 | * given $relation |
||
473 | * |
||
474 | * @param string $relation |
||
475 | * @return array |
||
476 | */ |
||
477 | public function getMissingEntities($relation) |
||
495 | |||
496 | /** |
||
497 | * Get Relationships who have dirty attributes / dirty relationships |
||
498 | * |
||
499 | * @return array |
||
500 | */ |
||
501 | public function getDirtyRelationships() |
||
515 | |||
516 | /** |
||
517 | * Compare the object's raw attributes with the record in cache |
||
518 | * |
||
519 | * @return boolean |
||
520 | */ |
||
521 | public function isDirty() |
||
529 | |||
530 | /** |
||
531 | * Get Raw Entity's attributes, as they are represented |
||
532 | * in the database, including value objects & foreign keys |
||
533 | * |
||
534 | * @return array |
||
535 | */ |
||
536 | public function getRawAttributes() |
||
550 | |||
551 | /** |
||
552 | * Convert Value Objects to raw db attributes |
||
553 | * |
||
554 | * @param array $attributes |
||
555 | * @return array |
||
556 | */ |
||
557 | protected function flattenEmbeddables($attributes) |
||
585 | |||
586 | /** |
||
587 | * Return's entity raw attributes in the state they were at last |
||
588 | * query. |
||
589 | * |
||
590 | * @param array|null $columns |
||
591 | * @return array |
||
592 | */ |
||
593 | View Code Duplication | protected function getCachedRawAttributes(array $columns = null) |
|
603 | |||
604 | /** |
||
605 | * Return a single attribute from the cache |
||
606 | * @param string $key |
||
607 | * @return mixed |
||
608 | */ |
||
609 | View Code Duplication | protected function getCachedAttribute($key) |
|
619 | |||
620 | /** |
||
621 | * Convert related Entity's attributes to foreign keys |
||
622 | * |
||
623 | * @return array |
||
624 | */ |
||
625 | protected function getForeignKeyAttributes() |
||
643 | |||
644 | /** |
||
645 | * Return an associative array containing the key-value pair(s) from |
||
646 | * the related entity. |
||
647 | * |
||
648 | * @param string $relation |
||
649 | * @return array |
||
650 | */ |
||
651 | protected function getForeignKeyAttributesFromRelation($relation) |
||
666 | |||
667 | /** |
||
668 | * Get foreign key attribute(s) from a parent entity in this |
||
669 | * aggregate context |
||
670 | * |
||
671 | * @return array |
||
672 | */ |
||
673 | protected function getForeignKeyAttributesFromParent() |
||
695 | |||
696 | /** |
||
697 | * Update Pivot records on loaded relationships, by comparing the |
||
698 | * values from the Entity Cache to the actual relationship inside |
||
699 | * the aggregated entity. |
||
700 | * |
||
701 | * @return void |
||
702 | */ |
||
703 | public function updatePivotRecords() |
||
713 | |||
714 | /** |
||
715 | * Update Single pivot relationship |
||
716 | * |
||
717 | * @param string $relation |
||
718 | * @return void |
||
719 | */ |
||
720 | protected function updatePivotRelation($relation) |
||
748 | |||
749 | /** |
||
750 | * Compare existing pivot record in cache and update it |
||
751 | * if the pivot attributes are dirty |
||
752 | * |
||
753 | * @param string $pivotHash |
||
754 | * @param string $relation |
||
755 | * @return void |
||
756 | */ |
||
757 | protected function updatePivotIfDirty($pivotHash, $relation) |
||
777 | |||
778 | /** |
||
779 | * Compare two attributes array and return dirty attributes |
||
780 | * |
||
781 | * @param array $actual |
||
782 | * @param array $cached |
||
783 | * @return array |
||
784 | */ |
||
785 | protected function getDirtyAttributes(array $actual, array $cached) |
||
797 | |||
798 | /** |
||
799 | * |
||
800 | * @param string $pivotHash |
||
801 | * @param string $relation |
||
802 | * @return array |
||
803 | */ |
||
804 | protected function getPivotAttributesFromCache($pivotHash, $relation) |
||
816 | |||
817 | /** |
||
818 | * Returns an array of related Aggregates from its entity hashes |
||
819 | * |
||
820 | * @param array $hashes |
||
821 | * @param string $relation |
||
822 | * @return array |
||
823 | */ |
||
824 | protected function getRelatedAggregatesFromHashes(array $hashes, $relation) |
||
838 | |||
839 | /** |
||
840 | * Get related aggregate from its hash |
||
841 | * |
||
842 | * @param string $hash |
||
843 | * @param string $relation |
||
844 | * @return \Analogue\ORM\System\Aggregate|null |
||
845 | */ |
||
846 | protected function getRelatedAggregateFromHash($hash, $relation) |
||
855 | |||
856 | /** |
||
857 | * Return an array of Entity Hashes from a specific relation |
||
858 | * |
||
859 | * @param string $relation |
||
860 | * @return array |
||
861 | */ |
||
862 | protected function getEntityHashesFromRelation($relation) |
||
868 | |||
869 | /** |
||
870 | * Check the existence of an actual relationship |
||
871 | * |
||
872 | * @param string $relation |
||
873 | * @return boolean |
||
874 | */ |
||
875 | protected function isActualRelationships($relation) |
||
880 | |||
881 | /** |
||
882 | * Return cache instance for the current entity type |
||
883 | * |
||
884 | * @return \Analogue\ORM\System\EntityCache |
||
885 | */ |
||
886 | protected function getCache() |
||
890 | |||
891 | /** |
||
892 | * Get Only Raw Entiy's attributes which have been modified |
||
893 | * since last query |
||
894 | * |
||
895 | * @return array |
||
896 | */ |
||
897 | public function getDirtyRawAttributes() |
||
919 | |||
920 | /** |
||
921 | * @param $key |
||
922 | * @return bool |
||
923 | */ |
||
924 | protected function isRelation($key) |
||
928 | |||
929 | /** |
||
930 | * Determine if the new and old values for a given key are numerically equivalent. |
||
931 | * |
||
932 | * @param $current |
||
933 | * @param $original |
||
934 | * @return boolean |
||
935 | */ |
||
936 | protected function originalIsNumericallyEquivalent($current, $original) |
||
940 | |||
941 | /** |
||
942 | * Get the underlying entity object |
||
943 | * |
||
944 | * @return mixed |
||
945 | */ |
||
946 | public function getEntityObject() |
||
950 | |||
951 | /** |
||
952 | * Return the Mapper instance for the current Entity Type |
||
953 | * |
||
954 | * @return \Analogue\ORM\System\Mapper |
||
955 | */ |
||
956 | public function getMapper() |
||
960 | |||
961 | /** |
||
962 | * Check that the entity already exists in the database, by checking |
||
963 | * if it has an EntityCache record |
||
964 | * |
||
965 | * @return boolean |
||
966 | */ |
||
967 | public function exists() |
||
971 | |||
972 | /** |
||
973 | * Set the object attribute raw values (hydration) |
||
974 | * |
||
975 | * @param array $attributes |
||
976 | */ |
||
977 | public function setEntityAttributes(array $attributes) |
||
981 | |||
982 | /** |
||
983 | * Get the raw object's values. |
||
984 | * |
||
985 | * @return array |
||
986 | */ |
||
987 | public function getEntityAttributes() |
||
991 | |||
992 | /** |
||
993 | * Set the raw entity attributes |
||
994 | * @param string $key |
||
995 | * @param string $value |
||
996 | */ |
||
997 | public function setEntityAttribute($key, $value) |
||
1001 | |||
1002 | /** |
||
1003 | * Return the entity's attribute |
||
1004 | * @param string $key |
||
1005 | * @return mixed |
||
1006 | */ |
||
1007 | public function getEntityAttribute($key) |
||
1011 | |||
1012 | /** |
||
1013 | * Does the attribute exists on the entity |
||
1014 | * |
||
1015 | * @param string $key |
||
1016 | * @return boolean |
||
1017 | */ |
||
1018 | public function hasAttribute($key) |
||
1022 | |||
1023 | /** |
||
1024 | * Set the lazyloading proxies on the wrapped entity |
||
1025 | */ |
||
1026 | public function setProxies() |
||
1030 | } |
||
1031 |
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.