Complex classes like DataTable 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 DataTable, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
19 | class DataTable { |
||
20 | |||
21 | /** @var Request */ |
||
22 | private $_request; |
||
23 | |||
24 | /** @var Builder */ |
||
25 | private $_queryBuilder; |
||
26 | |||
27 | /** @var array */ |
||
28 | private $_headerFormatters = []; |
||
29 | |||
30 | /** @var array */ |
||
31 | private $_components = []; |
||
32 | |||
33 | /** @var string */ |
||
34 | private $_classes; |
||
35 | |||
36 | /** @var array */ |
||
37 | private $_columns = []; |
||
38 | |||
39 | /** @var array */ |
||
40 | private $_relations = []; |
||
41 | |||
42 | /** @var string */ |
||
43 | private $_noDataHtml = '<div>no data</div>'; |
||
44 | |||
45 | /** |
||
46 | * DataTable constructor. |
||
47 | * @param Request $request |
||
48 | */ |
||
49 | 42 | public function __construct(Request $request) |
|
53 | |||
54 | /** |
||
55 | * Set the base model whose data is displayed in the table. |
||
56 | * |
||
57 | * @param string $modelName |
||
58 | * @param array $columns |
||
59 | * @return $this |
||
60 | * @throws \RuntimeException |
||
61 | */ |
||
62 | 41 | public function model(string $modelName, array $columns = []): DataTable |
|
74 | |||
75 | /** |
||
76 | * Returns an array of Column objects which may be bound to a formatter. |
||
77 | * |
||
78 | * @param array $columns |
||
79 | * @return array |
||
80 | */ |
||
81 | 40 | private function _fetchColumns(array $columns): array |
|
96 | |||
97 | /** |
||
98 | * @return Builder |
||
99 | */ |
||
100 | 18 | public function query(): Builder |
|
104 | |||
105 | /** |
||
106 | * Displayed columns |
||
107 | * |
||
108 | * @param array $columns |
||
109 | * @return $this |
||
110 | */ |
||
111 | 2 | public function columns(array $columns): DataTable |
|
117 | |||
118 | /** |
||
119 | * Add a component to the data table. |
||
120 | * For example a "Paginator" or a "Sorter". |
||
121 | * |
||
122 | * @param DataComponent $component |
||
123 | * |
||
124 | * @return $this |
||
125 | */ |
||
126 | 20 | public function addComponent(DataComponent $component): DataTable |
|
133 | |||
134 | /** |
||
135 | * Add a formatter for the column headers. |
||
136 | * |
||
137 | * @param HeaderFormatter $headerFormatter |
||
138 | * @return $this |
||
139 | */ |
||
140 | 8 | public function formatHeaders(HeaderFormatter $headerFormatter): DataTable |
|
146 | |||
147 | /** |
||
148 | * Add a formatter for a column. |
||
149 | * |
||
150 | * @param string $columnName |
||
151 | * @param ColumnFormatter $columnFormatter |
||
152 | * @return DataTable |
||
153 | */ |
||
154 | 2 | public function formatColumn(string $columnName, ColumnFormatter $columnFormatter): DataTable |
|
173 | |||
174 | /** |
||
175 | * Add classes to the table. |
||
176 | * |
||
177 | * @param string $classes |
||
178 | * |
||
179 | * @return $this |
||
180 | */ |
||
181 | 1 | public function classes(string $classes): DataTable |
|
187 | |||
188 | /** |
||
189 | * Add a relation to the table. |
||
190 | * |
||
191 | * @param array $relations |
||
192 | * @return $this |
||
193 | */ |
||
194 | 3 | public function with(array $relations): DataTable |
|
200 | |||
201 | /** |
||
202 | * Set the HTML which should be displayed when the dataset is empty. |
||
203 | * |
||
204 | * @param string $html |
||
205 | * @return DataTable |
||
206 | */ |
||
207 | public function noDataHtml(string $html): DataTable |
||
213 | |||
214 | /** |
||
215 | * Set a view which should be displayed when the dataset is empty. |
||
216 | * |
||
217 | * @param string $viewName |
||
218 | * @return DataTable |
||
219 | */ |
||
220 | public function noDataView(string $viewName): DataTable |
||
226 | |||
227 | /** |
||
228 | * Renders the table. |
||
229 | * |
||
230 | * @return string |
||
231 | * @throws \RuntimeException |
||
232 | */ |
||
233 | 32 | public function render(): string |
|
246 | |||
247 | /** |
||
248 | * Get data which should be displayed in the table. |
||
249 | * |
||
250 | * @return Collection |
||
251 | * |
||
252 | * @throws \RuntimeException |
||
253 | */ |
||
254 | 32 | private function _getData(): Collection |
|
271 | |||
272 | 31 | private function _addRelations() |
|
279 | |||
280 | 28 | private function _initColumns() |
|
287 | |||
288 | /** |
||
289 | * Starts the table. |
||
290 | * |
||
291 | * @return string |
||
292 | */ |
||
293 | 28 | private function _open(): string |
|
297 | |||
298 | /** |
||
299 | * Renders the column headers. |
||
300 | * |
||
301 | * @return string |
||
302 | */ |
||
303 | 28 | private function _renderHeaders(): string |
|
316 | |||
317 | /** |
||
318 | * @return array |
||
319 | */ |
||
320 | 28 | private function _fetchHeaders(): array |
|
331 | |||
332 | /** |
||
333 | * Displays the table body. |
||
334 | * |
||
335 | * @param Collection $data |
||
336 | * |
||
337 | * @return string |
||
338 | */ |
||
339 | 28 | private function _renderBody(Collection $data): string |
|
349 | |||
350 | /** |
||
351 | * Displays a single row. |
||
352 | * |
||
353 | * @param Model $rowModel |
||
354 | * |
||
355 | * @return string |
||
356 | */ |
||
357 | 28 | private function _renderRow(Model $rowModel): string |
|
371 | |||
372 | /** |
||
373 | * Get all the mutated attributes which are needed. |
||
374 | * |
||
375 | * @param Model $model |
||
376 | * @param array $columns |
||
377 | * @return array |
||
378 | */ |
||
379 | 28 | private function _getMutatedAttributes(Model $model, array $columns = []): array |
|
389 | |||
390 | /** |
||
391 | * Get all column names. |
||
392 | * |
||
393 | * @return array |
||
394 | */ |
||
395 | 28 | private function _getColumnNames(): array |
|
405 | |||
406 | /** |
||
407 | * Get only the columns which are attributes from the base model. |
||
408 | * |
||
409 | * @return array |
||
410 | */ |
||
411 | 28 | private function _getColumnsWithoutRelations(): array |
|
422 | |||
423 | /** |
||
424 | * @param Model $model |
||
425 | * @param Column $column |
||
426 | * @return string |
||
427 | */ |
||
428 | 3 | private function _getColumnValueFromRelation(Model $model, Column $column): string |
|
440 | |||
441 | /** |
||
442 | * Closes the table. |
||
443 | * |
||
444 | * @return string |
||
445 | */ |
||
446 | 28 | private function _close(): string |
|
450 | } |
It seems like the method you are trying to call exists only in some of the possible types.
Let’s take a look at an example:
Available Fixes
Add an additional type-check:
Only allow a single type to be passed if the variable comes from a parameter: