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 Column 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 Column, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
16 | abstract class Column extends Ublaboo\DataGrid\Object |
||
17 | { |
||
18 | |||
19 | /** |
||
20 | * @var string |
||
21 | */ |
||
22 | protected $column; |
||
23 | |||
24 | /** |
||
25 | * @var string |
||
26 | */ |
||
27 | protected $name; |
||
28 | |||
29 | /** |
||
30 | * @var array |
||
31 | */ |
||
32 | protected $replacements = []; |
||
33 | |||
34 | /** |
||
35 | * @var Renderer|NULL |
||
36 | */ |
||
37 | protected $renderer; |
||
38 | |||
39 | /** |
||
40 | * @var string |
||
41 | */ |
||
42 | protected $template; |
||
43 | |||
44 | /** |
||
45 | * @var boolean |
||
46 | */ |
||
47 | protected $is_sortable = FALSE; |
||
48 | |||
49 | /** |
||
50 | * @var array |
||
51 | */ |
||
52 | protected $sort; |
||
53 | |||
54 | /** |
||
55 | * @var bool |
||
56 | */ |
||
57 | protected $template_escaping = TRUE; |
||
58 | |||
59 | /** |
||
60 | * @var string |
||
61 | */ |
||
62 | protected $align; |
||
63 | |||
64 | /** |
||
65 | * @var array |
||
66 | */ |
||
67 | protected $template_variables; |
||
68 | |||
69 | /** |
||
70 | * @var callable |
||
71 | */ |
||
72 | protected $editable_callback; |
||
73 | |||
74 | |||
75 | /** |
||
76 | * @param string $column |
||
77 | * @param string $name |
||
78 | */ |
||
79 | public function __construct($column, $name) |
||
84 | |||
85 | |||
86 | /** |
||
87 | * Render row item into template |
||
88 | * @param Row $row |
||
89 | * @return mixed |
||
90 | */ |
||
91 | public function render(Row $row) |
||
116 | |||
117 | |||
118 | /** |
||
119 | * Should be column values escaped in latte? |
||
120 | * @param boolean $template_escaping |
||
121 | */ |
||
122 | public function setTemplateEscaping($template_escaping = TRUE) |
||
128 | |||
129 | |||
130 | public function isTemplateEscaped() |
||
134 | |||
135 | |||
136 | /** |
||
137 | * Set column sortable or not |
||
138 | * @param bool $sortable |
||
139 | */ |
||
140 | public function setSortable($sortable = TRUE) |
||
146 | |||
147 | |||
148 | /** |
||
149 | * Tell whether column is sortable |
||
150 | * @return boolean |
||
151 | */ |
||
152 | public function isSortable() |
||
156 | |||
157 | |||
158 | /** |
||
159 | * Get column name |
||
160 | * @return string |
||
161 | */ |
||
162 | public function getColumnName() |
||
166 | |||
167 | |||
168 | /** |
||
169 | * Get column value of row item |
||
170 | * @param Row $row |
||
171 | * @return mixed |
||
172 | */ |
||
173 | public function getColumnValue(Row $row) |
||
177 | |||
178 | |||
179 | public function getName() |
||
183 | |||
184 | |||
185 | /** |
||
186 | * Set column replacements |
||
187 | * @param array $replacements |
||
188 | * @return Column |
||
189 | */ |
||
190 | public function setReplacement(array $replacements) |
||
196 | |||
197 | |||
198 | /** |
||
199 | * Tell whether columns has replacements |
||
200 | * @return boolean |
||
201 | */ |
||
202 | public function hasReplacements() |
||
206 | |||
207 | |||
208 | /** |
||
209 | * Apply replacements |
||
210 | * @param Row $row |
||
211 | * @return array |
||
212 | */ |
||
213 | public function applyReplacements(Row $row) |
||
223 | |||
224 | |||
225 | /** |
||
226 | * Set renderer callback and (it may be optional - the condition callback will decide) |
||
227 | * @param callable $renderer |
||
228 | */ |
||
229 | public function setRenderer($renderer, $condition_callback = NULL) |
||
253 | |||
254 | |||
255 | /** |
||
256 | * Set renderer callback just if condition is truthy |
||
257 | * @param callable $renderer |
||
258 | */ |
||
259 | public function setRendererOnCondition($renderer, $condition_callback) |
||
263 | |||
264 | |||
265 | /** |
||
266 | * Return custom renderer callback |
||
267 | * @return Renderer|null |
||
268 | */ |
||
269 | public function getRenderer() |
||
273 | |||
274 | |||
275 | /** |
||
276 | * Column may have its own template |
||
277 | * @param string $template |
||
278 | */ |
||
279 | public function setTemplate($template, array $template_variables = []) |
||
286 | |||
287 | |||
288 | /** |
||
289 | * Column can have variables that will be passed to custom template scope |
||
290 | * @return array |
||
291 | */ |
||
292 | public function getTemplateVariables() |
||
296 | |||
297 | |||
298 | /** |
||
299 | * Tell whether column has its owntemplate |
||
300 | * @return bool |
||
301 | */ |
||
302 | public function hasTemplate() |
||
306 | |||
307 | |||
308 | /** |
||
309 | * Get column template path |
||
310 | * @return string |
||
311 | */ |
||
312 | public function getTemplate() |
||
316 | |||
317 | |||
318 | /** |
||
319 | * Tell whether data source is sorted by this collumn |
||
320 | * @return boolean |
||
321 | */ |
||
322 | public function isSortedBy() |
||
326 | |||
327 | |||
328 | /** |
||
329 | * Tell column his sorting options |
||
330 | * @param array $sort |
||
331 | */ |
||
332 | public function setSort(array $sort) |
||
338 | |||
339 | |||
340 | /** |
||
341 | * What sorting will be applied after next click? |
||
342 | * @return array |
||
343 | */ |
||
344 | public function getSortNext() |
||
354 | |||
355 | |||
356 | /** |
||
357 | * Is sorting ascending? |
||
358 | * @return boolean |
||
359 | */ |
||
360 | public function isSortAsc() |
||
364 | |||
365 | |||
366 | /** |
||
367 | * Set column alignment |
||
368 | * @param string $align |
||
369 | */ |
||
370 | public function setAlign($align) |
||
376 | |||
377 | |||
378 | /** |
||
379 | * Has column some alignment? |
||
380 | * @return boolean [description] |
||
381 | */ |
||
382 | public function hasAlign() |
||
386 | |||
387 | |||
388 | /** |
||
389 | * Get column alignment |
||
390 | * @return string |
||
391 | */ |
||
392 | public function getAlign() |
||
396 | |||
397 | |||
398 | /** |
||
399 | * Set callback that will be called after inline editing |
||
400 | * @param callable $editable_callback |
||
401 | */ |
||
402 | public function setEditableCallback(callable $editable_callback) |
||
408 | |||
409 | |||
410 | /** |
||
411 | * Return callback that is used after inline editing |
||
412 | * @return callable |
||
413 | */ |
||
414 | public function getEditableCallback() |
||
418 | |||
419 | |||
420 | /** |
||
421 | * Is column editable? |
||
422 | * @return boolean |
||
423 | */ |
||
424 | public function isEditable() |
||
428 | |||
429 | |||
430 | /** |
||
431 | * Create link to custom destination |
||
432 | * @param string $href |
||
433 | * @param array $params |
||
434 | * @return string |
||
435 | * @throws DataGridHasToBeAttachedToPresenterComponentException |
||
436 | * @throws InvalidArgumentException |
||
437 | */ |
||
438 | protected function createLink($href, $params) |
||
454 | |||
455 | } |
||
456 |
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.