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 UiItemTrait 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 UiItemTrait, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
12 | trait UiItemTrait |
||
13 | { |
||
14 | |||
15 | /** |
||
16 | * @var boolean |
||
17 | */ |
||
18 | private $active = true; |
||
19 | |||
20 | /** |
||
21 | * The UI item's sorting index. |
||
22 | * |
||
23 | * @var integer |
||
24 | */ |
||
25 | private $priority = 0; |
||
26 | |||
27 | /** |
||
28 | * The UI item type. |
||
29 | * |
||
30 | * @var string|null |
||
31 | */ |
||
32 | private $type; |
||
33 | |||
34 | /** |
||
35 | * The UI item's template. |
||
36 | * |
||
37 | * @var string|null |
||
38 | */ |
||
39 | private $template; |
||
40 | |||
41 | /** |
||
42 | * The UI item's icon. |
||
43 | * |
||
44 | * Note: Only icons from the {@link http://fontawesome.io/ Font Awesome} |
||
45 | * library are supported. |
||
46 | * |
||
47 | * @var string|null |
||
48 | */ |
||
49 | private $icon; |
||
50 | |||
51 | /** |
||
52 | * The UI item's title. |
||
53 | * |
||
54 | * @var \Charcoal\Translator\Translation |
||
55 | */ |
||
56 | private $title = ''; |
||
57 | |||
58 | /** |
||
59 | * The UI item's sub-title. |
||
60 | * |
||
61 | * @var \Charcoal\Translator\Translation |
||
62 | */ |
||
63 | private $subtitle = ''; |
||
64 | |||
65 | /** |
||
66 | * The UI item's description. |
||
67 | * |
||
68 | * @var \Charcoal\Translator\Translation |
||
69 | */ |
||
70 | private $description = ''; |
||
71 | |||
72 | /** |
||
73 | * The UI item's notes. |
||
74 | * |
||
75 | * @var \Charcoal\Translator\Translation |
||
76 | */ |
||
77 | private $notes = ''; |
||
78 | |||
79 | /** |
||
80 | * The title is displayed by default. |
||
81 | * |
||
82 | * @var boolean |
||
83 | */ |
||
84 | private $showTitle = true; |
||
85 | |||
86 | /** |
||
87 | * The sub-title is displayed by default. |
||
88 | * |
||
89 | * @var boolean |
||
90 | */ |
||
91 | private $showSubtitle = true; |
||
92 | |||
93 | /** |
||
94 | * The description is displayed by default. |
||
95 | * |
||
96 | * @var boolean |
||
97 | */ |
||
98 | private $showDescription = true; |
||
99 | |||
100 | /** |
||
101 | * The notes are displayed by default. |
||
102 | * |
||
103 | * @var boolean |
||
104 | */ |
||
105 | private $showNotes = true; |
||
106 | |||
107 | /** |
||
108 | * The icon is displayed by default. |
||
109 | * |
||
110 | * @var boolean |
||
111 | */ |
||
112 | private $showIcon = true; |
||
113 | |||
114 | /** |
||
115 | * The header is displayed by default. |
||
116 | * |
||
117 | * @var boolean |
||
118 | */ |
||
119 | private $showHeader = true; |
||
120 | |||
121 | /** |
||
122 | * The footer is displayed by default. |
||
123 | * |
||
124 | * @var boolean |
||
125 | */ |
||
126 | private $showFooter = true; |
||
127 | |||
128 | /** |
||
129 | * Activates/deactivates the UI item. |
||
130 | * |
||
131 | * @param boolean $active Activate (TRUE) or deactivate (FALSE) the UI item. |
||
132 | * @return AbstractUiItem Chainable |
||
133 | */ |
||
134 | public function setActive($active) |
||
140 | |||
141 | /** |
||
142 | * Determine if the UI item is active. |
||
143 | * |
||
144 | * @return boolean |
||
145 | */ |
||
146 | public function active() |
||
150 | |||
151 | /** |
||
152 | * Set the UI item type. |
||
153 | * |
||
154 | * @param string|null $type The UI item type. |
||
155 | * @throws InvalidArgumentException If the type is not a string (or null). |
||
156 | * @return UiItemInterface Chainable |
||
157 | */ |
||
158 | View Code Duplication | public function setType($type) |
|
170 | |||
171 | /** |
||
172 | * Retrieve the UI item type. |
||
173 | * |
||
174 | * If it is not explicitely set (or null), then return the object's FQN. |
||
175 | * |
||
176 | * @return string |
||
177 | */ |
||
178 | public function type() |
||
185 | |||
186 | /** |
||
187 | * Set the UI item's template. |
||
188 | * |
||
189 | * Usually, a path to a file containing the template to be rendered. |
||
190 | * |
||
191 | * @param string $template A template (identifier). |
||
192 | * @throws InvalidArgumentException If the template is not a string. |
||
193 | * @return UiItemInterface Chainable |
||
194 | */ |
||
195 | public function setTemplate($template) |
||
207 | |||
208 | /** |
||
209 | * Retrieve the UI item's template. |
||
210 | * |
||
211 | * @return string If unset, returns the UI item type. |
||
212 | */ |
||
213 | public function template() |
||
221 | |||
222 | /** |
||
223 | * Set the group's priority or sorting index. |
||
224 | * |
||
225 | * @param integer|mixed $priority An index, for sorting. |
||
226 | * @throws InvalidArgumentException If the priority is not an integer / numeric. |
||
227 | * @return self |
||
228 | */ |
||
229 | View Code Duplication | public function setPriority($priority) |
|
241 | |||
242 | /** |
||
243 | * Retrieve the group's priority or sorting index. |
||
244 | * |
||
245 | * @return integer |
||
246 | */ |
||
247 | public function priority() |
||
251 | |||
252 | |||
253 | /** |
||
254 | * Set the UI item's title. |
||
255 | * |
||
256 | * @param mixed $title A title. |
||
257 | * @return UiItemInterface Chainable |
||
258 | */ |
||
259 | public function setTitle($title) |
||
264 | |||
265 | /** |
||
266 | * Retrieve the title. |
||
267 | * |
||
268 | * @return \Charcoal\Translator\Translation|null |
||
269 | */ |
||
270 | public function title() |
||
274 | |||
275 | /** |
||
276 | * Set the UI item's sub-title. |
||
277 | * |
||
278 | * @param mixed $subtitle A sub-title. |
||
279 | * @return UiItemInterface Chainable |
||
280 | */ |
||
281 | public function setSubtitle($subtitle) |
||
286 | |||
287 | /** |
||
288 | * Retrieve the sub-title. |
||
289 | * |
||
290 | * @return \Charcoal\Translator\Translation|null |
||
291 | */ |
||
292 | public function subtitle() |
||
296 | |||
297 | /** |
||
298 | * Set the UI item's description. |
||
299 | * |
||
300 | * @param mixed $description A description. |
||
301 | * @return UiItemInterface Chainable |
||
302 | */ |
||
303 | public function setDescription($description) |
||
308 | |||
309 | /** |
||
310 | * Retrieve the description. |
||
311 | * |
||
312 | * @return \Charcoal\Translator\Translation|null |
||
313 | */ |
||
314 | public function description() |
||
318 | |||
319 | /** |
||
320 | * Set notes about the UI item. |
||
321 | * |
||
322 | * @param mixed $notes Notes. |
||
323 | * @return UiItemInterface Chainable |
||
324 | */ |
||
325 | public function setNotes($notes) |
||
330 | |||
331 | /** |
||
332 | * Retrieve the notes. |
||
333 | * |
||
334 | * @return \Charcoal\Translator\Translation|null |
||
335 | */ |
||
336 | public function notes() |
||
340 | |||
341 | /** |
||
342 | * Retrieve the path to the item's icon. |
||
343 | * |
||
344 | * @todo [mcaskill 2016-09-16] Move this to a tab interface in charcoal-admin |
||
345 | * so as to focus the icon getter/setter on being a Glyphicon. |
||
346 | * @return string |
||
347 | */ |
||
348 | public function icon() |
||
352 | |||
353 | /** |
||
354 | * Set the path to the item's icon associated with the object. |
||
355 | * |
||
356 | * @param string $icon A path to an image. |
||
357 | * @return UiItemInterface Chainable |
||
358 | */ |
||
359 | public function setIcon($icon) |
||
365 | |||
366 | /** |
||
367 | * Show/hide the UI item's title. |
||
368 | * |
||
369 | * @param boolean $show Show (TRUE) or hide (FALSE) the title. |
||
370 | * @return UiItemInterface Chainable |
||
371 | */ |
||
372 | public function setShowTitle($show) |
||
378 | |||
379 | /** |
||
380 | * Determine if the title is to be displayed. |
||
381 | * |
||
382 | * @return boolean If TRUE or unset, check if there is a title. |
||
383 | */ |
||
384 | public function showTitle() |
||
392 | |||
393 | /** |
||
394 | * Show/hide the UI item's sub-title. |
||
395 | * |
||
396 | * @param boolean $show Show (TRUE) or hide (FALSE) the sub-title. |
||
397 | * @return UiItemInterface Chainable |
||
398 | */ |
||
399 | public function setShowSubtitle($show) |
||
405 | |||
406 | /** |
||
407 | * Determine if the sub-title is to be displayed. |
||
408 | * |
||
409 | * @return boolean If TRUE or unset, check if there is a sub-title. |
||
410 | */ |
||
411 | public function showSubtitle() |
||
419 | |||
420 | /** |
||
421 | * Show/hide the UI item's description. |
||
422 | * |
||
423 | * @param boolean $show Show (TRUE) or hide (FALSE) the description. |
||
424 | * @return UiItemInterface Chainable |
||
425 | */ |
||
426 | public function setShowDescription($show) |
||
432 | |||
433 | /** |
||
434 | * Determine if the description is to be displayed. |
||
435 | * |
||
436 | * @return boolean If TRUE or unset, check if there is a description. |
||
437 | */ |
||
438 | public function showDescription() |
||
446 | |||
447 | /** |
||
448 | * Show/hide the UI item's notes. |
||
449 | * |
||
450 | * @param boolean $show Show (TRUE) or hide (FALSE) the notes. |
||
451 | * @return UiItemInterface Chainable |
||
452 | */ |
||
453 | public function setShowNotes($show) |
||
459 | |||
460 | /** |
||
461 | * Determine if the notes is to be displayed. |
||
462 | * |
||
463 | * @return boolean If TRUE or unset, check if there are notes. |
||
464 | */ |
||
465 | public function showNotes() |
||
473 | |||
474 | /** |
||
475 | * Show/hide the UI item's icon. |
||
476 | * |
||
477 | * @param boolean $show Show (TRUE) or hide (FALSE) the icon. |
||
478 | * @return UiItemInterface Chainable |
||
479 | */ |
||
480 | public function setShowIcon($show) |
||
486 | |||
487 | /** |
||
488 | * Determine if the icon is to be displayed. |
||
489 | * |
||
490 | * @return boolean If TRUE or unset, check if there is an icon. |
||
491 | */ |
||
492 | public function showIcon() |
||
500 | |||
501 | /** |
||
502 | * Show/hide the UI item's header. |
||
503 | * |
||
504 | * @param boolean $show Show (TRUE) or hide (FALSE) the header. |
||
505 | * @return UiItemInterface Chainable |
||
506 | */ |
||
507 | public function setShowHeader($show) |
||
513 | |||
514 | /** |
||
515 | * Determine if the header is to be displayed. |
||
516 | * |
||
517 | * @return boolean If TRUE or unset, check if there is a title. |
||
518 | */ |
||
519 | public function showHeader() |
||
527 | |||
528 | /** |
||
529 | * Show/hide the UI item's footer. |
||
530 | * |
||
531 | * @param boolean $show Show (TRUE) or hide (FALSE) the footer. |
||
532 | * @return UiItemInterface Chainable |
||
533 | */ |
||
534 | public function setShowFooter($show) |
||
540 | |||
541 | /** |
||
542 | * Determine if the footer is to be displayed. |
||
543 | * |
||
544 | * @return boolean If TRUE or unset, check if there are notes. |
||
545 | */ |
||
546 | public function showFooter() |
||
554 | |||
555 | /** |
||
556 | * Static comparison function used by {@see uasort()}. |
||
557 | * |
||
558 | * @param UiItemInterface $a Widget A. |
||
559 | * @param UiItemInterface $b Widget B. |
||
560 | * @return integer Sorting value: -1 or 1 |
||
561 | */ |
||
562 | protected static function sortItemsByPriority(UiItemInterface $a, UiItemInterface $b) |
||
572 | |||
573 | /** |
||
574 | * All UI objects are translatable, therefore are `translator`-aware. |
||
575 | * |
||
576 | * @return \Charcoal\Translator\Translator |
||
577 | */ |
||
578 | abstract protected function translator(); |
||
579 | } |
||
580 |
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.