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 |
||
13 | abstract class AbstractEvent implements EventInterface { |
||
14 | |||
15 | const BAT_DAY = 'bat_day'; |
||
16 | const BAT_HOUR = 'bat_hour'; |
||
17 | const BAT_MINUTE = 'bat_minute'; |
||
18 | const BAT_HOURLY = 'bat_hourly'; |
||
19 | const BAT_DAILY = 'bat_daily'; |
||
20 | |||
21 | /** |
||
22 | * The booking unit the event is relevant to |
||
23 | * @var int |
||
24 | */ |
||
25 | protected $unit_id; |
||
26 | |||
27 | /** |
||
28 | * The unit the event is relevant to |
||
29 | */ |
||
30 | protected $unit; |
||
31 | |||
32 | /** |
||
33 | * The start date for the event. |
||
34 | * |
||
35 | * @var \DateTime |
||
36 | */ |
||
37 | protected $start_date; |
||
38 | |||
39 | /** |
||
40 | * The end date for the event. |
||
41 | * |
||
42 | * @var \DateTime |
||
43 | */ |
||
44 | protected $end_date; |
||
45 | |||
46 | /** |
||
47 | * The value associated with this event. |
||
48 | * This can represent an availability state or a pricing value |
||
49 | * |
||
50 | * @var int |
||
51 | */ |
||
52 | protected $value; |
||
53 | |||
54 | /** |
||
55 | * Returns the value. |
||
56 | * |
||
57 | * @return int |
||
58 | */ |
||
59 | public function getValue() { |
||
62 | |||
63 | /** |
||
64 | * Set the value. |
||
65 | * |
||
66 | * @param int $value |
||
67 | */ |
||
68 | public function setValue($value) { |
||
71 | |||
72 | /** |
||
73 | * Returns the unit id. |
||
74 | * |
||
75 | * @return int |
||
76 | */ |
||
77 | public function getUnitId() { |
||
80 | |||
81 | /** |
||
82 | * Set the unit id. |
||
83 | * |
||
84 | * @param int $unit_id |
||
85 | */ |
||
86 | public function setUnitId($unit_id) { |
||
89 | |||
90 | /** |
||
91 | * Returns the start date. |
||
92 | * |
||
93 | * @return DateTime |
||
94 | */ |
||
95 | public function getStartDate() { |
||
98 | |||
99 | /** |
||
100 | * Utility function to always give us a standard format for viewing the start date. |
||
101 | * @return mixed |
||
102 | */ |
||
103 | public function startDateToString($format = 'Y-m-d H:i') { |
||
106 | |||
107 | /** |
||
108 | * Set the start date. |
||
109 | * |
||
110 | * @param DateTime $start_date |
||
111 | */ |
||
112 | public function setStartDate(\DateTime $start_date) { |
||
115 | |||
116 | /** |
||
117 | * Returns the end date. |
||
118 | * |
||
119 | * @return DateTime |
||
120 | */ |
||
121 | public function getEndDate() { |
||
124 | |||
125 | /** |
||
126 | * Utility function to always give us a standard format for viewing the end date. |
||
127 | * @return mixed |
||
128 | */ |
||
129 | public function endDateToString($format = 'Y-m-d H:i') { |
||
132 | |||
133 | /** |
||
134 | * Set the end date. |
||
135 | * |
||
136 | * @param DateTime $end_date |
||
137 | */ |
||
138 | public function setEndDate(\DateTime $end_date) { |
||
141 | |||
142 | /** |
||
143 | * {@inheritdoc} |
||
144 | */ |
||
145 | public function startDay($format = 'j') { |
||
148 | |||
149 | /** |
||
150 | * {@inheritdoc} |
||
151 | */ |
||
152 | public function endDay($format = 'j') { |
||
155 | |||
156 | /** |
||
157 | * {@inheritdoc} |
||
158 | */ |
||
159 | public function startMonth($format = 'n') { |
||
162 | |||
163 | /** |
||
164 | * {@inheritdoc} |
||
165 | */ |
||
166 | public function endMonth($format = 'n') { |
||
169 | |||
170 | /** |
||
171 | *{@inheritdoc) |
||
172 | */ |
||
173 | public function endMonthDate(\DateTime $date) { |
||
178 | |||
179 | /** |
||
180 | * {@inheritdoc} |
||
181 | */ |
||
182 | public function startYear($format = 'Y') { |
||
185 | |||
186 | /** |
||
187 | * {@inheritdoc} |
||
188 | */ |
||
189 | public function endYear($format = 'Y') { |
||
192 | |||
193 | /** |
||
194 | * {@inheritdoc} |
||
195 | */ |
||
196 | public function startWeek($format = 'W') { |
||
199 | |||
200 | /** |
||
201 | * {@inheritdoc} |
||
202 | */ |
||
203 | public function endWeek($format = 'W') { |
||
206 | |||
207 | /** |
||
208 | * {@inheritdoc} |
||
209 | */ |
||
210 | public function startHour($format = 'G') { |
||
213 | |||
214 | /** |
||
215 | * {@inheritdoc} |
||
216 | */ |
||
217 | public function endHour($format = 'G') { |
||
220 | |||
221 | /** |
||
222 | * {@inheritdoc} |
||
223 | */ |
||
224 | public function startMinute($format = 'i') { |
||
227 | |||
228 | /** |
||
229 | * {@inheritdoc} |
||
230 | */ |
||
231 | public function endMinute($format = 'i') { |
||
234 | |||
235 | /** |
||
236 | * {@inheritdoc} |
||
237 | */ |
||
238 | public function isFirstMonth($date) { |
||
245 | |||
246 | /** |
||
247 | * {@inheritdoc} |
||
248 | */ |
||
249 | public function isLastMonth($date) { |
||
256 | |||
257 | /** |
||
258 | * {@inheritdoc} |
||
259 | */ |
||
260 | public function isFirstDay($date) { |
||
267 | |||
268 | /** |
||
269 | * {@inheritdoc} |
||
270 | */ |
||
271 | public function isFirstHour($date) { |
||
278 | |||
279 | /** |
||
280 | * {@inheritdoc} |
||
281 | */ |
||
282 | public function isSameYear() { |
||
289 | |||
290 | /** |
||
291 | * {@inheritdoc} |
||
292 | */ |
||
293 | public function isSameMonth() { |
||
300 | |||
301 | /** |
||
302 | * {@inheritdoc} |
||
303 | */ |
||
304 | public function isSameDay() { |
||
311 | |||
312 | /** |
||
313 | * {@inheritdoc} |
||
314 | */ |
||
315 | public function isSameHour() { |
||
322 | |||
323 | /** |
||
324 | * {@inheritdoc} |
||
325 | */ |
||
326 | public function diff() { |
||
330 | |||
331 | /** |
||
332 | * Returns true if the event overlaps at all with the time period within |
||
333 | * the start and end time. |
||
334 | * |
||
335 | * @param \DateTime $start |
||
336 | * @param \DateTime $end |
||
337 | * @return bool |
||
338 | */ |
||
339 | public function overlaps(\DateTime $start, \DateTime $end) { |
||
353 | |||
354 | /** |
||
355 | * Checks if date supplied is in range of event |
||
356 | * |
||
357 | * @param \DateTime $date |
||
358 | * @return bool |
||
359 | */ |
||
360 | public function dateIsInRange(\DateTime $date) { |
||
374 | |||
375 | /** |
||
376 | * Checks if the date supplied starts earlier than our event |
||
377 | * @param \DateTime $date |
||
378 | * @return bool |
||
379 | */ |
||
380 | View Code Duplication | public function dateIsEarlier(\DateTime $date) { |
|
393 | |||
394 | /** |
||
395 | * Checks if the date supplied ends after our event ends |
||
396 | * @param \DateTime $date |
||
397 | * @return bool |
||
398 | */ |
||
399 | View Code Duplication | public function dateIsLater(\DateTime $date) { |
|
412 | |||
413 | /** |
||
414 | * Checks if our event ends after the date supplied |
||
415 | * @param \DateTime $date |
||
416 | * @return bool |
||
417 | */ |
||
418 | View Code Duplication | public function endsLater(\DateTime $date) { |
|
431 | |||
432 | /** |
||
433 | * Checks if our event starts earlier than the date supplied |
||
434 | * @param \DateTime $date |
||
435 | * @return bool |
||
436 | */ |
||
437 | View Code Duplication | public function startsEarlier(\DateTime $date) { |
|
450 | |||
451 | /** |
||
452 | * Transforms the event in a breakdown of days, hours and minutes with associated states. |
||
453 | * |
||
454 | * @return array |
||
455 | */ |
||
456 | public function itemize($itemizer, $granularity = AbstractEvent::BAT_HOURLY) { |
||
460 | |||
461 | /** |
||
462 | * Saves an event using the Store object |
||
463 | * |
||
464 | * @param \Roomify\Bat\\Store\Store $store |
||
465 | * @param string $granularity |
||
466 | * |
||
467 | * @return boolean |
||
468 | */ |
||
469 | public function saveEvent(Store $store, $granularity = AbstractEvent::BAT_HOURLY) { |
||
472 | |||
473 | } |
||
474 |
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.