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 Datagrid 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 Datagrid, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
23 | class Datagrid |
||
24 | { |
||
25 | /** |
||
26 | * @var array |
||
27 | */ |
||
28 | protected $options = []; |
||
29 | |||
30 | /** |
||
31 | * @var SessionContainer |
||
32 | */ |
||
33 | protected $session; |
||
34 | |||
35 | /** |
||
36 | * @var Cache\Storage\StorageInterface |
||
37 | */ |
||
38 | protected $cache; |
||
39 | |||
40 | /** |
||
41 | * @var string |
||
42 | */ |
||
43 | protected $cacheId; |
||
44 | |||
45 | /** |
||
46 | * @var MvcEvent |
||
47 | */ |
||
48 | protected $mvcEvent; |
||
49 | |||
50 | /** |
||
51 | * @var array |
||
52 | */ |
||
53 | protected $parameters = []; |
||
54 | |||
55 | /** |
||
56 | * @var mixed |
||
57 | */ |
||
58 | protected $url; |
||
59 | |||
60 | /** |
||
61 | * @var HttpRequest |
||
62 | */ |
||
63 | protected $request; |
||
64 | |||
65 | /** |
||
66 | * View or Response. |
||
67 | * |
||
68 | * @var \Zend\Http\Response\Stream|\Zend\View\Model\ViewModel |
||
69 | */ |
||
70 | protected $response; |
||
71 | |||
72 | /** |
||
73 | * @var Renderer\AbstractRenderer |
||
74 | */ |
||
75 | private $renderer; |
||
76 | |||
77 | /** |
||
78 | * @var Translator |
||
79 | */ |
||
80 | protected $translator; |
||
81 | |||
82 | /** |
||
83 | * @var string |
||
84 | */ |
||
85 | protected $id; |
||
86 | |||
87 | /** |
||
88 | * The grid title. |
||
89 | * |
||
90 | * @var string |
||
91 | */ |
||
92 | protected $title = ''; |
||
93 | |||
94 | /** |
||
95 | * @var DataSource\DataSourceInterface |
||
96 | */ |
||
97 | protected $dataSource = null; |
||
98 | |||
99 | /** |
||
100 | * @var int |
||
101 | */ |
||
102 | protected $defaulItemsPerPage = 25; |
||
103 | |||
104 | /** |
||
105 | * @var array |
||
106 | */ |
||
107 | protected $columns = []; |
||
108 | |||
109 | /** |
||
110 | * @var Style\AbstractStyle[] |
||
111 | */ |
||
112 | protected $rowStyles = []; |
||
113 | |||
114 | /** |
||
115 | * @var Column\Action\AbstractAction |
||
116 | */ |
||
117 | protected $rowClickAction; |
||
118 | |||
119 | /** |
||
120 | * @var Action\Mass |
||
121 | */ |
||
122 | protected $massActions = []; |
||
123 | |||
124 | /** |
||
125 | * The prepared data. |
||
126 | * |
||
127 | * @var array |
||
128 | */ |
||
129 | protected $preparedData = []; |
||
130 | |||
131 | /** |
||
132 | * @var array |
||
133 | */ |
||
134 | protected $isUserFilterEnabled = true; |
||
135 | |||
136 | /** |
||
137 | * @var Paginator |
||
138 | */ |
||
139 | protected $paginator = null; |
||
140 | |||
141 | /** |
||
142 | * @var array |
||
143 | */ |
||
144 | protected $exportRenderers; |
||
145 | |||
146 | /** |
||
147 | * @var string|null |
||
148 | */ |
||
149 | protected $toolbarTemplate; |
||
150 | |||
151 | /** |
||
152 | * @var array |
||
153 | */ |
||
154 | protected $toolbarTemplateVariables = []; |
||
155 | |||
156 | /** |
||
157 | * @var ViewModel |
||
158 | */ |
||
159 | protected $viewModel; |
||
160 | |||
161 | /** |
||
162 | * @var bool |
||
163 | */ |
||
164 | protected $isInit = false; |
||
165 | |||
166 | /** |
||
167 | * @var bool |
||
168 | */ |
||
169 | protected $isDataLoaded = false; |
||
170 | |||
171 | /** |
||
172 | * @var bool |
||
173 | */ |
||
174 | protected $isRendered = false; |
||
175 | |||
176 | /** |
||
177 | * @var string |
||
178 | */ |
||
179 | protected $forceRenderer; |
||
180 | |||
181 | /** |
||
182 | * @var Renderer\AbstractRenderer |
||
183 | */ |
||
184 | private $rendererService; |
||
185 | |||
186 | /** |
||
187 | * @var array |
||
188 | */ |
||
189 | private $specialMethods = [ |
||
190 | 'filterSelectOptions', |
||
191 | 'rendererParameter', |
||
192 | 'replaceValues', |
||
193 | 'select', |
||
194 | 'sortDefault', |
||
195 | ]; |
||
196 | |||
197 | /** |
||
198 | * @var ServiceLocatorInterface |
||
199 | */ |
||
200 | protected $serviceLocator = null; |
||
201 | |||
202 | /** |
||
203 | * Init method is called automatically with the service creation. |
||
204 | */ |
||
205 | public function init() |
||
214 | |||
215 | /** |
||
216 | * @return bool |
||
217 | */ |
||
218 | public function isInit() |
||
222 | |||
223 | /** |
||
224 | * Set the options from config. |
||
225 | * |
||
226 | * @param array $config |
||
227 | */ |
||
228 | public function setOptions(array $config) |
||
232 | |||
233 | /** |
||
234 | * Get the config options. |
||
235 | * |
||
236 | * @return array |
||
237 | */ |
||
238 | public function getOptions() |
||
242 | |||
243 | /** |
||
244 | * Set the grid id. |
||
245 | * |
||
246 | * @param string $id |
||
247 | */ |
||
248 | public function setId($id = null) |
||
256 | |||
257 | /** |
||
258 | * Get the grid id. |
||
259 | * |
||
260 | * @return string |
||
261 | */ |
||
262 | public function getId() |
||
270 | |||
271 | /** |
||
272 | * Set the session. |
||
273 | * |
||
274 | * @param \Zend\Session\Container $session |
||
275 | */ |
||
276 | public function setSession(SessionContainer $session) |
||
280 | |||
281 | /** |
||
282 | * Get session container. |
||
283 | * |
||
284 | * Instantiate session container if none currently exists |
||
285 | * |
||
286 | * @return SessionContainer |
||
287 | */ |
||
288 | public function getSession() |
||
297 | |||
298 | /** |
||
299 | * @param Cache\Storage\StorageInterface $cache |
||
300 | */ |
||
301 | public function setCache(Cache\Storage\StorageInterface $cache) |
||
305 | |||
306 | /** |
||
307 | * @return Cache\Storage\StorageInterface |
||
308 | */ |
||
309 | public function getCache() |
||
313 | |||
314 | /** |
||
315 | * Set the cache id. |
||
316 | * |
||
317 | * @param string $id |
||
318 | */ |
||
319 | public function setCacheId($id) |
||
323 | |||
324 | /** |
||
325 | * Get the cache id. |
||
326 | * |
||
327 | * @return string |
||
328 | */ |
||
329 | public function getCacheId() |
||
339 | |||
340 | /** |
||
341 | * @param MvcEvent $mvcEvent |
||
342 | */ |
||
343 | public function setMvcEvent(MvcEvent $mvcEvent) |
||
348 | |||
349 | /** |
||
350 | * @return MvcEvent |
||
351 | */ |
||
352 | public function getMvcEvent() |
||
356 | |||
357 | /** |
||
358 | * @return HttpRequest |
||
359 | */ |
||
360 | public function getRequest() |
||
364 | |||
365 | /** |
||
366 | * Set the translator. |
||
367 | * |
||
368 | * @param Translator $translator |
||
369 | * |
||
370 | * @throws \InvalidArgumentException |
||
371 | */ |
||
372 | View Code Duplication | public function setTranslator($translator = null) |
|
380 | |||
381 | /** |
||
382 | * @return Translator |
||
383 | */ |
||
384 | public function getTranslator() |
||
388 | |||
389 | /** |
||
390 | * @return bool |
||
391 | */ |
||
392 | public function hasTranslator() |
||
400 | |||
401 | /** |
||
402 | * Set the data source. |
||
403 | * |
||
404 | * @param mixed $data |
||
405 | * |
||
406 | * @throws \Exception |
||
407 | */ |
||
408 | public function setDataSource($data) |
||
434 | |||
435 | /** |
||
436 | * @return \ZfcDatagrid\DataSource\DataSourceInterface |
||
437 | */ |
||
438 | public function getDataSource() |
||
442 | |||
443 | /** |
||
444 | * Datasource defined? |
||
445 | * |
||
446 | * @return bool |
||
447 | */ |
||
448 | public function hasDataSource() |
||
456 | |||
457 | /** |
||
458 | * Set default items per page (-1 for unlimited). |
||
459 | * |
||
460 | * @param int $count |
||
461 | */ |
||
462 | public function setDefaultItemsPerPage($count = 25) |
||
466 | |||
467 | /** |
||
468 | * @return int |
||
469 | */ |
||
470 | public function getDefaultItemsPerPage() |
||
474 | |||
475 | /** |
||
476 | * Set the title. |
||
477 | * |
||
478 | * @param string $title |
||
479 | */ |
||
480 | public function setTitle($title) |
||
484 | |||
485 | /** |
||
486 | * @return string |
||
487 | */ |
||
488 | public function getTitle() |
||
492 | |||
493 | /** |
||
494 | * Add a external parameter. |
||
495 | * |
||
496 | * @param string $name |
||
497 | * @param mixed $value |
||
498 | */ |
||
499 | public function addParameter($name, $value) |
||
503 | |||
504 | /** |
||
505 | * These parameters are handled to the view + over all grid actions. |
||
506 | * |
||
507 | * @param array $parameters |
||
508 | */ |
||
509 | public function setParameters(array $parameters) |
||
513 | |||
514 | /** |
||
515 | * @return array |
||
516 | */ |
||
517 | public function getParameters() |
||
521 | |||
522 | /** |
||
523 | * Has parameters? |
||
524 | * |
||
525 | * @return bool |
||
526 | */ |
||
527 | public function hasParameters() |
||
531 | |||
532 | /** |
||
533 | * Set the base url. |
||
534 | * |
||
535 | * @param string $url |
||
536 | */ |
||
537 | public function setUrl($url) |
||
541 | |||
542 | /** |
||
543 | * @return string |
||
544 | */ |
||
545 | public function getUrl() |
||
549 | |||
550 | /** |
||
551 | * Set the export renderers (overwrite the config). |
||
552 | * |
||
553 | * @param array $renderers |
||
554 | */ |
||
555 | public function setExportRenderers(array $renderers = []) |
||
559 | |||
560 | /** |
||
561 | * Get the export renderers. |
||
562 | * |
||
563 | * @return array |
||
564 | */ |
||
565 | public function getExportRenderers() |
||
574 | |||
575 | /** |
||
576 | * Create a column from array instanceof. |
||
577 | * |
||
578 | * @param array $config |
||
579 | * |
||
580 | * @return Column\AbstractColumn |
||
581 | */ |
||
582 | private function createColumn($config) |
||
636 | |||
637 | /** |
||
638 | * Set multiple columns by array (willoverwrite all existing). |
||
639 | * |
||
640 | * @param array $columns |
||
641 | */ |
||
642 | public function setColumns(array $columns) |
||
653 | |||
654 | /** |
||
655 | * Add a column by array config or instanceof Column\AbstractColumn. |
||
656 | * |
||
657 | * @param array|Column\AbstractColumn $col |
||
658 | */ |
||
659 | public function addColumn($col) |
||
664 | |||
665 | /** |
||
666 | * @return \ZfcDatagrid\Column\AbstractColumn[] |
||
667 | */ |
||
668 | public function getColumns() |
||
672 | |||
673 | /** |
||
674 | * @param string $id |
||
675 | * |
||
676 | * @return Column\AbstractColumn null |
||
677 | */ |
||
678 | public function getColumnByUniqueId($id) |
||
686 | |||
687 | /** |
||
688 | * @param Style\AbstractStyle $style |
||
689 | */ |
||
690 | public function addRowStyle(Style\AbstractStyle $style) |
||
694 | |||
695 | /** |
||
696 | * @return Style\AbstractStyle[] |
||
697 | */ |
||
698 | public function getRowStyles() |
||
702 | |||
703 | /** |
||
704 | * @return bool |
||
705 | */ |
||
706 | public function hasRowStyles() |
||
710 | |||
711 | /** |
||
712 | * If disabled, the toolbar filter will not be shown to the user. |
||
713 | * |
||
714 | * @param bool $mode |
||
715 | */ |
||
716 | public function setUserFilterDisabled($mode = true) |
||
720 | |||
721 | /** |
||
722 | * @return bool |
||
723 | */ |
||
724 | public function isUserFilterEnabled() |
||
728 | |||
729 | /** |
||
730 | * Set the row click action - identity will be automatically appended! |
||
731 | * |
||
732 | * @param Column\Action\AbstractAction $action |
||
733 | */ |
||
734 | public function setRowClickAction(Column\Action\AbstractAction $action) |
||
738 | |||
739 | public function getRowClickAction() |
||
743 | |||
744 | /** |
||
745 | * @return bool |
||
746 | */ |
||
747 | public function hasRowClickAction() |
||
755 | |||
756 | /** |
||
757 | * Add a mass action. |
||
758 | * |
||
759 | * @param Action\Mass $action |
||
760 | */ |
||
761 | public function addMassAction(Action\Mass $action) |
||
765 | |||
766 | /** |
||
767 | * @return Action\Mass[] |
||
768 | */ |
||
769 | public function getMassActions() |
||
773 | |||
774 | /** |
||
775 | * @return bool |
||
776 | */ |
||
777 | public function hasMassAction() |
||
781 | |||
782 | /** |
||
783 | * Overwrite the render |
||
784 | * F.x. |
||
785 | * if you want to directly render a PDF. |
||
786 | * |
||
787 | * @param string $name |
||
788 | */ |
||
789 | public function setRendererName($name = null) |
||
793 | |||
794 | /** |
||
795 | * Get the current renderer name. |
||
796 | * |
||
797 | * @return string |
||
798 | */ |
||
799 | public function getRendererName() |
||
823 | |||
824 | /** |
||
825 | * Return the current renderer. |
||
826 | * |
||
827 | * @throws \Exception |
||
828 | * |
||
829 | * @return \ZfcDatagrid\Renderer\AbstractRenderer |
||
830 | */ |
||
831 | public function getRenderer() |
||
863 | |||
864 | /** |
||
865 | * @return bool |
||
866 | */ |
||
867 | public function isDataLoaded() |
||
871 | |||
872 | /** |
||
873 | * Load the data. |
||
874 | */ |
||
875 | public function loadData() |
||
990 | |||
991 | /** |
||
992 | * Render the grid. |
||
993 | */ |
||
994 | public function render() |
||
1014 | |||
1015 | /** |
||
1016 | * Is already rendered? |
||
1017 | * |
||
1018 | * @return bool |
||
1019 | */ |
||
1020 | public function isRendered() |
||
1024 | |||
1025 | /** |
||
1026 | * @throws \Exception |
||
1027 | * |
||
1028 | * @return Paginator |
||
1029 | */ |
||
1030 | public function getPaginator() |
||
1038 | |||
1039 | /** |
||
1040 | * @return array |
||
1041 | */ |
||
1042 | private function getPreparedData() |
||
1046 | |||
1047 | /** |
||
1048 | * Set the toolbar view template. |
||
1049 | * |
||
1050 | * @param string $name |
||
1051 | */ |
||
1052 | public function setToolbarTemplate($name) |
||
1056 | |||
1057 | /** |
||
1058 | * Get the toolbar template name |
||
1059 | * Return null if nothing custom set. |
||
1060 | * |
||
1061 | * @return string|null |
||
1062 | */ |
||
1063 | public function getToolbarTemplate() |
||
1067 | |||
1068 | /** |
||
1069 | * Set the toolbar view template variables. |
||
1070 | * |
||
1071 | * @param array $variables |
||
1072 | */ |
||
1073 | public function setToolbarTemplateVariables(array $variables) |
||
1077 | |||
1078 | /** |
||
1079 | * Get the toolbar template variables. |
||
1080 | * |
||
1081 | * @return array |
||
1082 | */ |
||
1083 | public function getToolbarTemplateVariables() |
||
1087 | |||
1088 | /** |
||
1089 | * Set a custom ViewModel...generally NOT necessary! |
||
1090 | * |
||
1091 | * @param ViewModel $viewModel |
||
1092 | * |
||
1093 | * @throws \Exception |
||
1094 | */ |
||
1095 | public function setViewModel(ViewModel $viewModel) |
||
1103 | |||
1104 | /** |
||
1105 | * @return ViewModel |
||
1106 | */ |
||
1107 | public function getViewModel() |
||
1115 | |||
1116 | /** |
||
1117 | * @return \Zend\Stdlib\ResponseInterface|\Zend\Http\Response\Stream|\Zend\View\Model\ViewModel |
||
1118 | */ |
||
1119 | public function getResponse() |
||
1127 | |||
1128 | /** |
||
1129 | * Is this a HTML "init" response? |
||
1130 | * YES: loading the HTML for the grid |
||
1131 | * NO: AJAX loading OR it's an export. |
||
1132 | * |
||
1133 | * @return bool |
||
1134 | */ |
||
1135 | public function isHtmlInitReponse() |
||
1143 | |||
1144 | /** |
||
1145 | * @param Renderer\AbstractRenderer $rendererService |
||
1146 | * |
||
1147 | * @return self |
||
1148 | */ |
||
1149 | public function setRendererService(Renderer\AbstractRenderer $rendererService) |
||
1155 | |||
1156 | /** |
||
1157 | * Set service locator. |
||
1158 | * |
||
1159 | * @param ContainerInterface $serviceLocator |
||
1160 | * |
||
1161 | * @return mixed |
||
1162 | */ |
||
1163 | public function setServiceLocator(ContainerInterface $serviceLocator) |
||
1169 | |||
1170 | /** |
||
1171 | * Get service locator. |
||
1172 | * |
||
1173 | * @return ContainerInterface |
||
1174 | */ |
||
1175 | public function getServiceLocator() |
||
1179 | } |
||
1180 |
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.