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 Entity 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 Entity, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
25 | class Entity extends Generic |
||
26 | { |
||
27 | /** @var array Collection of all additional fields names */ |
||
28 | public static $fieldNames = array(); |
||
29 | |||
30 | /** @var array Collection of localized additional fields identifiers */ |
||
31 | public static $localizedFieldIDs = array(); |
||
32 | |||
33 | /** @var array Collection of NOT localized additional fields identifiers */ |
||
34 | public static $notLocalizedFieldIDs = array(); |
||
35 | |||
36 | /** @var array Collection of all additional fields identifiers */ |
||
37 | public static $fieldIDs = array(); |
||
38 | |||
39 | /** @var @var array Collection of additional fields value column names */ |
||
40 | public static $fieldValueColumns = array(); |
||
41 | |||
42 | /** @var Condition Collection of entity field filter */ |
||
43 | protected $fieldFilter = array(); |
||
44 | |||
45 | /** @var string Query locale */ |
||
46 | protected $locale = ''; |
||
47 | |||
48 | /** @var array Collection of additional fields for ordering */ |
||
49 | protected $entityOrderBy = array(); |
||
50 | |||
51 | /** @var array Collection of search fields for query */ |
||
52 | protected $searchFilter = array(); |
||
53 | |||
54 | /** |
||
55 | * Generic constructor. |
||
56 | * |
||
57 | * @param QueryInterface $query Database query instance |
||
58 | * @param string $locale Query localization |
||
59 | */ |
||
60 | public function __construct(QueryInterface $query = null, $locale = null) |
||
61 | { |
||
62 | $this->locale = $locale; |
||
63 | |||
64 | parent::__construct(null === $query ? new dbQuery() : $query); |
||
65 | |||
66 | // Work only with active entities |
||
67 | $this->active(true); |
||
68 | } |
||
69 | |||
70 | /** |
||
71 | * Select specified entity fields. |
||
72 | * If this method is called then only selected entity fields |
||
73 | * would be filled in entity instances. |
||
74 | * |
||
75 | * @param mixed $fieldNames Entity field name or collection of names |
||
76 | * |
||
77 | *@return $this Chaining |
||
78 | */ |
||
79 | View Code Duplication | public function select($fieldNames) |
|
93 | |||
94 | /** |
||
95 | * Set additional field for sorting. |
||
96 | * |
||
97 | * @param string $fieldName Additional field name |
||
98 | * @param string $order Sorting order |
||
99 | * @return $this Chaining |
||
100 | */ |
||
101 | public function orderBy($fieldName, $order = 'ASC') |
||
111 | |||
112 | /** |
||
113 | * Search entity fields by text. |
||
114 | * |
||
115 | * @param string $text Searching text |
||
116 | * @return $this |
||
117 | */ |
||
118 | public function search($text) |
||
124 | |||
125 | /** |
||
126 | * Set resulting query limits. |
||
127 | * |
||
128 | * @param integer $offset Starting index |
||
129 | * @param integer|null $count Entities count |
||
130 | * @return $this Chaining |
||
131 | */ |
||
132 | public function limit($offset, $count = null) |
||
138 | |||
139 | /** |
||
140 | * Perform SamsonCMS query and get collection of entities. |
||
141 | * |
||
142 | * @param int $page Page number |
||
143 | * @param int $size Page size |
||
144 | * |
||
145 | * @return \samsoncms\api\Entity[] Collection of entity fields |
||
146 | */ |
||
147 | public function find($page = null, $size = null) |
||
186 | |||
187 | /** |
||
188 | * Prepare entity identifiers. |
||
189 | * |
||
190 | * @param array $entityIDs Collection of identifier for filtering |
||
191 | * @return array Collection of entity identifiers |
||
192 | */ |
||
193 | protected function findEntityIDs(array $entityIDs = array()) |
||
233 | |||
234 | /** |
||
235 | * Get collection of entity identifiers filtered by additional field and its value. |
||
236 | * |
||
237 | * @param Condition[] $additionalFields Collection of additional field identifiers => values |
||
238 | * @param array $entityIDs Additional collection of entity identifiers for filtering |
||
239 | * @return array Collection of material identifiers by navigation identifiers |
||
240 | */ |
||
241 | protected function findByAdditionalFields($additionalFields, $entityIDs = array()) |
||
261 | |||
262 | /** |
||
263 | * Get collection of entity identifiers filtered by navigation identifiers. |
||
264 | * |
||
265 | * @param array $entityIDs Additional collection of entity identifiers for filtering |
||
266 | * |
||
267 | * @return array Collection of material identifiers by navigation identifiers |
||
268 | */ |
||
269 | protected function findByNavigationIDs($entityIDs = array()) |
||
273 | |||
274 | /** |
||
275 | * Add sorting to entity identifiers. |
||
276 | * |
||
277 | * @param array $entityIDs |
||
278 | * @param string $fieldName Additional field name for sorting |
||
279 | * @param string $order Sorting order(ASC|DESC) |
||
280 | * @return array Collection of entity identifiers ordered by additional field value |
||
281 | */ |
||
282 | protected function applySorting(array $entityIDs, $fieldName, $order = 'ASC') |
||
299 | |||
300 | /** |
||
301 | * Get entities additional field values. |
||
302 | * |
||
303 | * @param array $entityIDs Collection of entity identifiers |
||
304 | * @return array Collection of entities additional fields EntityID => [Additional field name => Value] |
||
305 | * @throws EntityFieldNotFound |
||
306 | */ |
||
307 | protected function findAdditionalFields($entityIDs) |
||
369 | |||
370 | /** |
||
371 | * @param array $entityIDs |
||
372 | * |
||
373 | * @return array |
||
374 | */ |
||
375 | protected function applySearch(array $entityIDs) |
||
393 | |||
394 | /** |
||
395 | * Fill entity additional fields. |
||
396 | * |
||
397 | * @param \samsoncms\api\Entity $entity Entity instance for filling |
||
398 | * @param array $additionalFields Collection of additional field values |
||
399 | * @return Entity With filled additional field values |
||
400 | */ |
||
401 | protected function fillEntityFields($entity, array $additionalFields) |
||
417 | |||
418 | /** |
||
419 | * Perform SamsonCMS query and get first matching entity. |
||
420 | * |
||
421 | * @return \samsoncms\api\Entity Firt matching entity |
||
422 | */ |
||
423 | public function first() |
||
437 | |||
438 | /** |
||
439 | * Perform SamsonCMS query and get collection of entities fields. |
||
440 | * |
||
441 | * @param string $fieldName Entity field name |
||
442 | * @return array Collection of entity fields |
||
443 | * @throws EntityFieldNotFound |
||
444 | */ |
||
445 | public function fields($fieldName) |
||
473 | |||
474 | /** |
||
475 | * Add condition to current query. |
||
476 | * |
||
477 | * @param string $fieldName Entity field name |
||
478 | * @param string $fieldValue Value |
||
479 | * @param string $fieldRelation Entity field to value relation |
||
480 | * |
||
481 | * @return $this Chaining |
||
482 | */ |
||
483 | public function where($fieldName, $fieldValue = null, $fieldRelation = ArgumentInterface::EQUAL) |
||
498 | |||
499 | /** |
||
500 | * Perform SamsonCMS query and get amount resulting entities. |
||
501 | * |
||
502 | * @return int Amount of resulting entities |
||
503 | */ |
||
504 | public function count() |
||
524 | } |
||
525 |
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.