Total Complexity | 40 |
Total Lines | 392 |
Duplicated Lines | 0 % |
Changes | 4 | ||
Bugs | 0 | Features | 0 |
Complex classes like DashboardView 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 DashboardView, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
17 | class DashboardView extends ModuleView |
||
18 | { |
||
19 | protected $label = 'Dashboard'; |
||
20 | |||
21 | protected $dashboard; |
||
22 | protected $columns; |
||
23 | protected $admin = false; |
||
24 | protected $locked = false; |
||
25 | |||
26 | public function body() |
||
27 | { |
||
28 | if (! $this->isSingleDashboard()) { |
||
29 | $this->location($this->dashboard()['name']); |
||
30 | } |
||
31 | |||
32 | // initiate the dashboard first |
||
33 | $this->dashboard(); |
||
34 | |||
35 | $this->addMenu(); |
||
36 | |||
37 | $this->showDashboard(); |
||
38 | } |
||
39 | |||
40 | public function showDashboard() |
||
41 | { |
||
42 | $dashboard = $this->dashboard(); |
||
43 | |||
44 | $this->requireJS('sortable.jquery-ui.js'); |
||
45 | |||
46 | $applets = $dashboard->ref('applets')->setOrder(['column', 'row']); |
||
47 | |||
48 | $columns = $this->add(['Columns', 'id' => 'dashboard', 'ui' => 'three stackable grid' . ($this->isLocked()? ' locked': '')]); |
||
49 | |||
50 | foreach ([1, 2, 3] as $columnId) { |
||
51 | $columnApplets = clone $applets; |
||
52 | |||
53 | /** @scrutinizer ignore-call */ |
||
54 | $col = $columns->addColumn([ |
||
55 | '', |
||
56 | 'ui' => 'sortable', |
||
57 | 'attr' => [ |
||
58 | 'dashboard-id' => $dashboard->id, |
||
59 | 'column-id' => $columnId |
||
60 | ] |
||
61 | ]); |
||
62 | |||
63 | foreach ($columnApplets->addCondition('column', $columnId) as $applet) { |
||
64 | $col->add([ |
||
65 | new Applet(), |
||
66 | 'appletId' => $applet['id'], |
||
67 | 'jointClass' => $applet['class'], |
||
68 | 'options' => $applet['options'], |
||
69 | 'locked' => $this->isLocked() |
||
70 | ]); |
||
71 | } |
||
72 | } |
||
73 | |||
74 | if (! $this->isLocked()) { |
||
75 | $columns->js(true)->find('.sortable')->sortable([ |
||
76 | 'cursor' => 'move', |
||
77 | 'handle' => '.panel-sortable-handle', |
||
78 | 'connectWith' => '.sortable', |
||
79 | 'items' => '.applet', |
||
80 | ]); |
||
81 | |||
82 | $columns->js(true)->find('.column.sortable')->on('sortupdate', new jsFunction([ |
||
83 | $columns->add('jsCallback')->set([$this, 'saveColumn'], [ |
||
84 | new jsExpression(' |
||
85 | { |
||
86 | column: $(this).attr("column-id"), |
||
87 | applets: $(this).sortable( "toArray", { attribute: "applet-id" }) |
||
88 | }') |
||
89 | ]) |
||
90 | ])); |
||
91 | |||
92 | $columns->js(true)->find('.applet-close')->click(new jsFunction(['e'], [new jsExpression('if (confirm("' . __('Delete this applet?') . '")) {$(e.target).closest(".applet").fadeOut(400, function(){var col = $(this).closest(".column.sortable");this.remove();col.trigger("sortupdate");})}')])); |
||
93 | } |
||
94 | |||
95 | $this->columns = $columns; |
||
96 | |||
97 | $this->requireCSS(); |
||
98 | } |
||
99 | |||
100 | public function editDashboard() |
||
101 | { |
||
102 | $dashboard = $this->dashboard(); |
||
103 | |||
104 | $this->location([$dashboard['name'], __('Find Applets')]); |
||
105 | |||
106 | $this->showDashboard(); |
||
107 | |||
108 | ActionBar::addItemButton('back'); |
||
109 | |||
110 | $adminColumn = $this->columns->addColumn(); |
||
111 | |||
112 | $search = $adminColumn->add(new Input([ |
||
113 | 'placeholder' => __('Search applets'), |
||
114 | 'icon' => 'search' |
||
115 | ]))->setStyle(['width' => '100%']); |
||
116 | |||
117 | $search->js(true)->on('keyup', new jsFunction(['e'], [ |
||
118 | new jsExpression(' |
||
119 | var str = $(e.target).val().toLowerCase(); |
||
120 | |||
121 | $("#dashboard_applets_new").children(".applet").each(function(i, nodeObj) { |
||
122 | var node = $(nodeObj); |
||
123 | |||
124 | node.toggle(node.attr("searchkey").indexOf(str) != -1); |
||
125 | }); |
||
126 | ') |
||
127 | ])); |
||
128 | |||
129 | $col = $adminColumn->add([ |
||
130 | 'View', |
||
131 | 'id' => 'dashboard_applets_new', |
||
132 | 'ui' => 'admin sortable', |
||
133 | 'attr' => [ |
||
134 | 'dashboard-id' => $dashboard->id, |
||
135 | 'column-id' => 'admin' |
||
136 | ] |
||
137 | ]); |
||
138 | |||
139 | foreach ( AppletJoint::collect() as $applet ) { |
||
140 | $col->add([ |
||
141 | new Applet(), |
||
142 | 'appletId' => 'new_' . str_ireplace('\\', '-', get_class($applet)), |
||
143 | 'jointClass' => $applet, |
||
144 | 'admin' => 1, |
||
145 | ]); |
||
146 | } |
||
147 | } |
||
148 | |||
149 | public function addMenu() |
||
196 | ]); |
||
197 | } |
||
198 | |||
199 | public function addDashboard($view) |
||
235 | ]; |
||
236 | }); |
||
237 | } |
||
238 | |||
239 | public function renameDashboard($view) |
||
253 | ]; |
||
254 | }); |
||
255 | } |
||
256 | |||
257 | public function deleteDashboard($jsCallback, $dashboardId) |
||
267 | } |
||
268 | |||
269 | public function reorderDashboards($view) |
||
270 | { |
||
271 | $grid = $view->add(['Grid', 'paginator' => false, 'menu' => false]); |
||
272 | |||
273 | $grid->setModel($this->userDashboards()->setOrder('position')); |
||
274 | |||
275 | $grid->addDragHandler()->onReorder(function ($order) use ($grid) { |
||
276 | foreach ($this->userDashboards() as $dashboard) { |
||
277 | $dashboard->save(['position' => array_search($dashboard->id, $order)]); |
||
278 | } |
||
279 | |||
280 | return [ |
||
281 | new jsReload($grid), |
||
282 | $this->notifySuccess(__('Dashboards reordered!')) |
||
283 | ]; |
||
284 | }); |
||
285 | |||
286 | $view->add(['View', 'ui' => 'buttons'])->add(['Button', __('Done'), 'primary'])->on('click', new jsExpression('location.reload()')); |
||
287 | } |
||
288 | |||
289 | public function saveColumn($jsCallback, $columnHash) |
||
290 | { |
||
291 | $applets = $columnHash['applets']?? []; |
||
292 | |||
293 | if ($new = preg_grep('/^new_/', $applets)) { |
||
294 | $new = reset($new); |
||
295 | |||
296 | $row = array_search($new, $applets); |
||
297 | |||
298 | $applets[$row] = $this->dashboard()->ref('applets')->insert([ |
||
299 | 'class' => str_ireplace('-', '\\', preg_replace('/^new_/', '', $new)), |
||
300 | 'column' => $columnHash['column'], |
||
301 | 'row' => $row |
||
302 | ]); |
||
303 | } |
||
304 | |||
305 | foreach ($this->dashboard()->ref('applets')->withID($applets) as $applet) { |
||
306 | $applet->save([ |
||
307 | 'column' => $columnHash['column'], |
||
308 | 'row' => array_search($applet->id, $applets) |
||
309 | ]); |
||
310 | } |
||
311 | |||
312 | $removed = $this->dashboard()->ref('applets')->addCondition('column', $columnHash['column']); |
||
313 | |||
314 | if ($applets) { |
||
315 | $removed->addCondition('id', 'not', $applets); |
||
316 | } |
||
317 | |||
318 | $this->dashboard()->ref('applets')->addCondition('column', 0)->action('delete')->execute(); |
||
319 | |||
320 | $removed->action('update')->set('column', 0)->execute(); |
||
321 | } |
||
322 | |||
323 | public function showSettings($appletId) |
||
324 | { |
||
325 | $applet = $this->dashboard()->ref('applets')->load($appletId); |
||
326 | |||
327 | $joint = new $applet['class'](); |
||
328 | |||
329 | $this->location([__('Edit Applet Settings'), $joint->caption()]); |
||
330 | |||
331 | $form = $this->add(new Form()); |
||
332 | $form->addElements($joint->elements()); |
||
333 | $form->confirmLeave(); |
||
334 | |||
335 | $form->model->set($applet['options']); |
||
336 | |||
337 | $form->validate(function(Form $form) use ($applet) { |
||
338 | $applet->save(['options' => $form->model->get()]); |
||
339 | |||
340 | return $form->notifySuccess(__('Settings saved!')); |
||
341 | }); |
||
342 | |||
343 | ActionBar::addItemButton('back'); |
||
344 | |||
345 | ActionBar::addItemButton('save')->on('click', $form->submit()); |
||
346 | } |
||
347 | |||
348 | public function lock() |
||
349 | { |
||
350 | $this->locked = true; |
||
351 | |||
352 | return $this; |
||
353 | } |
||
354 | |||
355 | public function isLocked() |
||
356 | { |
||
357 | return $this->locked || ! Auth::user()->can('edit dashboard'); |
||
358 | } |
||
359 | |||
360 | protected function isSingleDashboard() |
||
361 | { |
||
362 | return $this->userDashboards()->action('count')->getOne() <= 1; |
||
363 | } |
||
364 | |||
365 | /** |
||
366 | * @return Dashboard |
||
367 | * |
||
368 | * @throws \Symfony\Component\HttpKernel\Exception\HttpException |
||
369 | * @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException |
||
370 | */ |
||
371 | protected function dashboard() |
||
372 | { |
||
373 | if (! is_object($this->dashboard)) { |
||
374 | $this->dashboard = $this->dashboard? Dashboard::create()->tryLoad($this->dashboard): $this->defaultUserDashboard(); |
||
375 | } |
||
376 | |||
377 | return $this->dashboard?: abort(404); |
||
378 | } |
||
379 | |||
380 | protected function defaultUserDashboard() |
||
381 | { |
||
382 | $userDashboard = $this->userDashboards()->setOrder('position')->tryLoadAny(); |
||
383 | |||
384 | if (! $userDashboard->loaded()) { |
||
385 | $this->lock(); |
||
386 | |||
387 | $userDashboard = $this->defaultSystemDashboard(); |
||
388 | } |
||
389 | |||
390 | return $userDashboard; |
||
391 | } |
||
392 | |||
393 | protected function defaultSystemDashboard() |
||
396 | } |
||
397 | |||
398 | protected function userDashboards($userId = null) |
||
399 | { |
||
400 | return Dashboard::create()->addCondition('user_id', $userId ?? $this->userId()); |
||
401 | } |
||
402 | |||
403 | /** |
||
404 | * @return number |
||
405 | */ |
||
406 | protected function userId() |
||
409 | } |
||
410 | } |
||
411 |
The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g.
excluded_paths: ["lib/*"]
, you can move it to the dependency path list as follows:For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths