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 AbstractEvent 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 AbstractEvent, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
37 | abstract class AbstractEvent extends Content implements |
||
38 | CategorizableInterface, |
||
39 | EventInterface, |
||
40 | MetatagInterface, |
||
41 | PublishableInterface, |
||
42 | RoutableInterface, |
||
43 | SearchableInterface, |
||
44 | TemplateableInterface |
||
45 | { |
||
46 | use CategorizableTrait; |
||
47 | use PublishableTrait; |
||
48 | use MetatagTrait; |
||
49 | use RoutableTrait; |
||
50 | use SearchableTrait; |
||
51 | use TemplateableTrait; |
||
52 | |||
53 | /** |
||
54 | * @var Translation|string|null |
||
55 | */ |
||
56 | private $title; |
||
57 | |||
58 | /** |
||
59 | * @var Translation|string|null |
||
60 | */ |
||
61 | private $subtitle; |
||
62 | |||
63 | /** |
||
64 | * @var Translation|string|null |
||
65 | */ |
||
66 | private $summary; |
||
67 | |||
68 | /** |
||
69 | * @var Translation|string|null |
||
70 | */ |
||
71 | private $content; |
||
72 | |||
73 | /** |
||
74 | * @var Translation|string|null |
||
75 | */ |
||
76 | private $image; |
||
77 | |||
78 | /** |
||
79 | * @var DateTimeInterface|null |
||
80 | */ |
||
81 | private $startDate; |
||
82 | |||
83 | /** |
||
84 | * @var DateTimeInterface|null |
||
85 | */ |
||
86 | private $endDate; |
||
87 | |||
88 | /** |
||
89 | * @var array |
||
90 | */ |
||
91 | protected $keywords; |
||
92 | |||
93 | // ========================================================================== |
||
94 | // INIT |
||
95 | // ========================================================================== |
||
96 | |||
97 | /** |
||
98 | * Section constructor. |
||
99 | * @param array $data The data. |
||
100 | */ |
||
101 | View Code Duplication | public function __construct(array $data = null) |
|
109 | |||
110 | // ========================================================================== |
||
111 | // FUNCTIONS |
||
112 | // ========================================================================== |
||
113 | |||
114 | /** |
||
115 | * Some dates cannot be null |
||
116 | * @return void |
||
117 | */ |
||
118 | public function verifyDates() |
||
132 | |||
133 | /** |
||
134 | * @return string The date filtered for admin dual select input and others. |
||
135 | */ |
||
136 | public function adminDateFilter() |
||
149 | |||
150 | // ========================================================================== |
||
151 | // SETTERS and GETTERS |
||
152 | // ========================================================================== |
||
153 | |||
154 | /** |
||
155 | * @param mixed $title The event title (localized). |
||
156 | * @return self |
||
157 | */ |
||
158 | public function setTitle($title) |
||
164 | |||
165 | /** |
||
166 | * @return Translation|string|null |
||
167 | */ |
||
168 | public function title() |
||
172 | |||
173 | /** |
||
174 | * @param mixed $subtitle The event subtitle (localized). |
||
175 | * @return self |
||
176 | */ |
||
177 | public function setSubtitle($subtitle) |
||
183 | |||
184 | /** |
||
185 | * @return Translation|string|null |
||
186 | */ |
||
187 | public function subtitle() |
||
191 | |||
192 | /** |
||
193 | * @param mixed $summary The news summary (localized). |
||
194 | * @return self |
||
195 | */ |
||
196 | public function setSummary($summary) |
||
202 | |||
203 | /** |
||
204 | * @return Translation|string|null |
||
205 | */ |
||
206 | public function summary() |
||
210 | |||
211 | /** |
||
212 | * @param mixed $content The event content (localized). |
||
213 | * @return self |
||
214 | */ |
||
215 | public function setContent($content) |
||
221 | |||
222 | /** |
||
223 | * @return Translation|string|null |
||
224 | */ |
||
225 | public function content() |
||
229 | |||
230 | /** |
||
231 | * @param mixed $image The section main image (localized). |
||
232 | * @return self |
||
233 | */ |
||
234 | public function setImage($image) |
||
240 | |||
241 | /** |
||
242 | * @return Translation|string|null |
||
243 | */ |
||
244 | public function image() |
||
248 | |||
249 | /** |
||
250 | * @param string|DateTimeInterface $startDate Event starting date. |
||
251 | * @throws InvalidArgumentException If the timestamp is invalid. |
||
252 | * @return self |
||
253 | */ |
||
254 | View Code Duplication | public function setStartDate($startDate) |
|
273 | |||
274 | /** |
||
275 | * @return DateTimeInterface|null |
||
276 | */ |
||
277 | public function startDate() |
||
281 | |||
282 | /** |
||
283 | * @param string|DateTimeInterface $endDate Event end date. |
||
284 | * @throws InvalidArgumentException If the timestamp is invalid. |
||
285 | * @return self |
||
286 | */ |
||
287 | View Code Duplication | public function setEndDate($endDate) |
|
306 | |||
307 | /** |
||
308 | * @return DateTimeInterface|null |
||
309 | */ |
||
310 | public function endDate() |
||
314 | |||
315 | // ========================================================================== |
||
316 | // META TAGS |
||
317 | // ========================================================================== |
||
318 | |||
319 | /** |
||
320 | * MetatagTrait > canonical_url |
||
321 | * |
||
322 | * @todo |
||
323 | * @return string |
||
324 | */ |
||
325 | public function canonicalUrl() |
||
329 | |||
330 | /** |
||
331 | * @return Translation|string|null |
||
332 | */ |
||
333 | public function defaultMetaTitle() |
||
337 | |||
338 | /** |
||
339 | * @return Translation|string|null |
||
340 | */ |
||
341 | View Code Duplication | public function defaultMetaDescription() |
|
355 | |||
356 | /** |
||
357 | * @return Translation|string|null |
||
358 | */ |
||
359 | public function defaultMetaImage() |
||
363 | |||
364 | /** |
||
365 | * Retrieve the object's keywords. |
||
366 | * |
||
367 | * @return string[] |
||
368 | */ |
||
369 | public function keywords() |
||
373 | |||
374 | // ========================================================================== |
||
375 | // EVENTS |
||
376 | // ========================================================================== |
||
377 | |||
378 | /** |
||
379 | * {@inheritdoc} |
||
380 | * |
||
381 | * @return boolean |
||
382 | */ |
||
383 | public function preSave() |
||
391 | |||
392 | /** |
||
393 | * {@inheritdoc} |
||
394 | * |
||
395 | * @param array $properties Optional properties to update. |
||
396 | * @return boolean |
||
397 | */ |
||
398 | public function preUpdate(array $properties = null) |
||
406 | |||
407 | /** |
||
408 | * @return boolean Parent postSave(). |
||
409 | */ |
||
410 | public function postSave() |
||
417 | |||
418 | /** |
||
419 | * @param array|null $properties Properties. |
||
420 | * @return boolean |
||
421 | */ |
||
422 | public function postUpdate(array $properties = null) |
||
429 | |||
430 | /** |
||
431 | * GenericRoute checks if the route is active. |
||
432 | * Default in RoutableTrait. |
||
433 | * |
||
434 | * @return boolean |
||
435 | */ |
||
436 | public function isActiveRoute() |
||
443 | } |
||
444 |
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.