Total Complexity | 41 |
Total Lines | 366 |
Duplicated Lines | 0 % |
Changes | 1 | ||
Bugs | 0 | Features | 0 |
Complex classes like DisplayDatatablesAsync 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.
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 DisplayDatatablesAsync, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
14 | class DisplayDatatablesAsync extends DisplayDatatables implements WithRoutesInterface |
||
15 | { |
||
16 | protected $rowClassCallback; |
||
17 | |||
18 | /** |
||
19 | * Register display routes. |
||
20 | * |
||
21 | * @param Router $router |
||
22 | * |
||
23 | * @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException |
||
24 | */ |
||
25 | public static function registerRoutes(Router $router) |
||
26 | { |
||
27 | $routeName = 'admin.display.async'; |
||
28 | if (! $router->has($routeName)) { |
||
29 | $router->get('{adminModel}/async/{adminDisplayName?}', [ |
||
30 | 'as' => $routeName, |
||
31 | 'uses' => 'SleepingOwl\Admin\Http\Controllers\DisplayController@async', |
||
|
|||
32 | ]); |
||
33 | } |
||
34 | |||
35 | $routeName = 'admin.display.async.inlineEdit'; |
||
36 | if (! $router->has($routeName)) { |
||
37 | $router->post('{adminModel}/async/{adminDisplayName?}', [ |
||
38 | 'as' => $routeName, |
||
39 | 'uses' => 'SleepingOwl\Admin\Http\Controllers\AdminController@inlineEdit', |
||
40 | ]); |
||
41 | } |
||
42 | } |
||
43 | |||
44 | protected $payload; |
||
45 | /** |
||
46 | * @var string |
||
47 | */ |
||
48 | protected $name; |
||
49 | |||
50 | /** |
||
51 | * @param string|null $name |
||
52 | */ |
||
53 | protected $distinct; |
||
54 | |||
55 | /** |
||
56 | * @var |
||
57 | */ |
||
58 | protected $displaySearch = false; |
||
59 | |||
60 | /** |
||
61 | * @var |
||
62 | */ |
||
63 | protected $displayLength = false; |
||
64 | |||
65 | /** |
||
66 | * DisplayDatatablesAsync constructor. |
||
67 | * |
||
68 | * @param string|null $name |
||
69 | * @param string|null $distinct |
||
70 | */ |
||
71 | public function __construct($name = null, $distinct = null) |
||
72 | { |
||
73 | parent::__construct(); |
||
74 | |||
75 | $this->setName($name); |
||
76 | $this->setDistinct($distinct); |
||
77 | |||
78 | $this->getColumns()->setView('display.extensions.columns_async'); |
||
79 | } |
||
80 | |||
81 | /** |
||
82 | * Initialize display. |
||
83 | */ |
||
84 | public function initialize() |
||
85 | { |
||
86 | parent::initialize(); |
||
87 | |||
88 | $attributes = Request::all(); |
||
89 | array_unshift($attributes, $this->getName()); |
||
90 | array_unshift($attributes, $this->getModelConfiguration()->getAlias()); |
||
91 | |||
92 | $this->setHtmlAttribute('style', 'width:100%'); |
||
93 | $this->setHtmlAttribute('data-url', route('admin.display.async', $attributes)); |
||
94 | $this->setHtmlAttribute('data-payload', json_encode($this->payload)); |
||
95 | |||
96 | if ($this->getDisplaySearch()) { |
||
97 | $this->setHtmlAttribute('data-display-search', 1); |
||
98 | } |
||
99 | |||
100 | if ($this->getDisplayLength()) { |
||
101 | $this->setHtmlAttribute('data-display-dtlength', 1); |
||
102 | } |
||
103 | } |
||
104 | |||
105 | /** |
||
106 | * @param bool $length |
||
107 | * @return $this |
||
108 | */ |
||
109 | public function setDisplayLength($length) |
||
110 | { |
||
111 | $this->displayLength = $length; |
||
112 | |||
113 | return $this; |
||
114 | } |
||
115 | |||
116 | /** |
||
117 | * @return bool |
||
118 | */ |
||
119 | public function getDisplayLength() |
||
120 | { |
||
121 | return $this->displayLength; |
||
122 | } |
||
123 | |||
124 | /** |
||
125 | * @param $search |
||
126 | * @return $this |
||
127 | */ |
||
128 | public function setDisplaySearch($search) |
||
129 | { |
||
130 | $this->displaySearch = $search; |
||
131 | |||
132 | return $this; |
||
133 | } |
||
134 | |||
135 | /** |
||
136 | * @return bool |
||
137 | */ |
||
138 | public function getDisplaySearch() |
||
139 | { |
||
140 | return $this->displaySearch; |
||
141 | } |
||
142 | |||
143 | /** |
||
144 | * @return string |
||
145 | */ |
||
146 | public function getName() |
||
147 | { |
||
148 | return $this->name; |
||
149 | } |
||
150 | |||
151 | /** |
||
152 | * @param string $name |
||
153 | * |
||
154 | * @return $this |
||
155 | */ |
||
156 | public function setName($name) |
||
157 | { |
||
158 | $this->name = $name; |
||
159 | |||
160 | return $this; |
||
161 | } |
||
162 | |||
163 | /** |
||
164 | * @return mixed |
||
165 | */ |
||
166 | public function getDistinct() |
||
167 | { |
||
168 | return $this->distinct; |
||
169 | } |
||
170 | |||
171 | /** |
||
172 | * @param mixed $distinct |
||
173 | * |
||
174 | * @return $this |
||
175 | */ |
||
176 | public function setDistinct($distinct) |
||
177 | { |
||
178 | $this->distinct = $distinct; |
||
179 | |||
180 | return $this; |
||
181 | } |
||
182 | |||
183 | /** |
||
184 | * Render async request. |
||
185 | * |
||
186 | * @param \Illuminate\Http\Request $request |
||
187 | * |
||
188 | * @return array |
||
189 | */ |
||
190 | public function renderAsync(\Illuminate\Http\Request $request) |
||
191 | { |
||
192 | $query = $this->getRepository()->getQuery(); |
||
193 | $totalCount = $query->count(); |
||
194 | $filteredCount = 0; |
||
195 | |||
196 | if (! is_null($this->distinct)) { |
||
197 | $filteredCount = $query->distinct()->count($this->getDistinct()); |
||
198 | } |
||
199 | |||
200 | $this->modifyQuery($query); |
||
201 | $this->applySearch($query, $request); |
||
202 | |||
203 | if (is_null($this->distinct)) { |
||
204 | $countQuery = clone $query; |
||
205 | $countQuery->getQuery()->orders = null; |
||
206 | $filteredCount = $countQuery->count(); |
||
207 | } |
||
208 | |||
209 | $this->applyOffset($query, $request); |
||
210 | $collection = $query->get(); |
||
211 | |||
212 | return $this->prepareDatatablesStructure($request, $collection, $totalCount, $filteredCount); |
||
213 | } |
||
214 | |||
215 | /** |
||
216 | * Apply offset and limit to the query. |
||
217 | * |
||
218 | * @param \Illuminate\Database\Query\Builder $query |
||
219 | * @param \Illuminate\Http\Request $request |
||
220 | */ |
||
221 | public function applyOffset($query, \Illuminate\Http\Request $request) |
||
222 | { |
||
223 | $offset = $request->input('start', 0); |
||
224 | $limit = $request->input('length', 10); |
||
225 | |||
226 | if ($limit == -1) { |
||
227 | return; |
||
228 | } |
||
229 | |||
230 | $query->offset((int) $offset)->limit((int) $limit); |
||
231 | } |
||
232 | |||
233 | /** |
||
234 | * Apply search to the query. |
||
235 | * |
||
236 | * @param Builder $query |
||
237 | * @param \Illuminate\Http\Request $request |
||
238 | */ |
||
239 | public function applySearch(Builder $query, \Illuminate\Http\Request $request) |
||
240 | { |
||
241 | $search = $request->input('search.value'); |
||
242 | if (empty($search)) { |
||
243 | return; |
||
244 | } |
||
245 | |||
246 | $query->where(function (Builder $query) use ($search) { |
||
247 | $columns = $this->getColumns()->all(); |
||
248 | |||
249 | $_model = $query->getModel(); |
||
250 | |||
251 | foreach ($columns as $column) { |
||
252 | if ($column->isSearchable()) { |
||
253 | if ($column instanceof ColumnInterface) { |
||
254 | if (($metaInstance = $column->getMetaData()) instanceof ColumnMetaInterface) { |
||
255 | if (method_exists($metaInstance, 'onSearch')) { |
||
256 | $metaInstance->onSearch($column, $query, $search); |
||
257 | continue; |
||
258 | } |
||
259 | } |
||
260 | |||
261 | if (is_callable($callback = $column->getSearchCallback())) { |
||
262 | $callback($column, $query, $search); |
||
263 | continue; |
||
264 | } |
||
265 | } |
||
266 | |||
267 | if ($_model->getAttribute($column->getName())) { |
||
268 | continue; |
||
269 | } |
||
270 | |||
271 | $query->orWhere($column->getName(), 'like', '%'.$search.'%'); |
||
272 | } |
||
273 | } |
||
274 | }); |
||
275 | } |
||
276 | |||
277 | /** |
||
278 | * Convert collection to the datatables structure. |
||
279 | * |
||
280 | * @param \Illuminate\Http\Request $request |
||
281 | * @param array|Collection $collection |
||
282 | * @param int $totalCount |
||
283 | * @param int $filteredCount |
||
284 | * |
||
285 | * @return array |
||
286 | */ |
||
287 | protected function prepareDatatablesStructure( |
||
288 | \Illuminate\Http\Request $request, |
||
289 | Collection $collection, |
||
290 | $totalCount, |
||
291 | $filteredCount |
||
292 | ) { |
||
293 | $columns = $this->getColumns(); |
||
294 | |||
295 | $result = []; |
||
296 | $result['draw'] = $request->input('draw', 0); |
||
297 | $result['recordsTotal'] = $totalCount; |
||
298 | $result['recordsFiltered'] = $filteredCount; |
||
299 | $result['data'] = []; |
||
300 | |||
301 | foreach ($collection as $instance) { |
||
302 | $_row = []; |
||
303 | |||
304 | foreach ($columns->all() as $column) { |
||
305 | $column->setModel($instance); |
||
306 | |||
307 | if ($column instanceof Control) { |
||
308 | $column->initialize(); |
||
309 | } |
||
310 | |||
311 | $_row[] = (string) $column; |
||
312 | } |
||
313 | if (is_callable($callback = $this->rowClassCallback)) { |
||
314 | $class = $callback($instance); |
||
315 | if (is_array($class)) { |
||
316 | $class = implode(' ', $class); |
||
317 | } |
||
318 | $_row[] = (string) $class; |
||
319 | } |
||
320 | |||
321 | $result['data'][] = $_row; |
||
322 | } |
||
323 | |||
324 | return $result; |
||
325 | } |
||
326 | |||
327 | /** |
||
328 | * @return \Closure|mixed |
||
329 | */ |
||
330 | public function getRowClassCallback() |
||
331 | { |
||
332 | return $this->rowClassCallback; |
||
333 | } |
||
334 | |||
335 | /** |
||
336 | * @param \Closure $callback |
||
337 | * |
||
338 | * @return $this |
||
339 | */ |
||
340 | public function setRowClassCallback($callback) |
||
341 | { |
||
342 | $this->rowClassCallback = $callback; |
||
343 | |||
344 | return $this; |
||
345 | } |
||
346 | |||
347 | /** |
||
348 | * @return void |
||
349 | */ |
||
350 | public function getCollection() |
||
352 | } |
||
353 | |||
354 | /** |
||
355 | * @param $payload |
||
356 | */ |
||
357 | public function setPayload($payload) |
||
358 | { |
||
359 | $this->payload = $payload; |
||
360 | } |
||
361 | |||
362 | /** |
||
363 | * @return mixed |
||
364 | */ |
||
365 | public function getPayload() |
||
368 | } |
||
369 | |||
370 | /** |
||
371 | * @return array |
||
372 | * @throws \Exception |
||
373 | */ |
||
374 | public function toArray() |
||
375 | { |
||
376 | $params = parent::toArray(); |
||
377 | $params['payload'] = $this->payload; |
||
380 | } |
||
381 | } |
||
382 |
If there is a route defined but the controller class cannot be found there are two options: 1. the controller class needs to be implemented or 2. the route is outdated and can be removed.
If ?FooController? was found and ?BarController? is missing for the following example, either the controller should be implemented or the route should be removed: