Completed
Push — master ( 6ec6b5...364731 )
by Adam
02:30
created

Grid   B

Complexity

Total Complexity 46

Size/Duplication

Total Lines 448
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 15

Importance

Changes 6
Bugs 0 Features 0
Metric Value
c 6
b 0
f 0
dl 0
loc 448
rs 7.4918
wmc 46
lcom 1
cbo 15

30 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 1
A buildGrid() 0 4 1
A getGridHelper() 0 4 1
A setSource() 0 6 1
A addColumn() 0 13 2
A getColumns() 0 4 1
A setDefaultOrder() 0 6 1
A getOrder() 0 4 1
A setPerPage() 0 6 1
A getPerPage() 0 4 1
A getEmptyMessage() 0 4 1
A setEmptyMessage() 0 4 1
A addRowAction() 0 7 1
A setEnablePagination() 0 7 1
A isPaginationEnabled() 0 4 1
A each() 0 4 1
A addComponent() 0 7 1
A setViewData() 0 6 1
A render() 0 17 2
A isFilterable() 0 13 3
C getRows() 0 50 9
A getPaginator() 0 6 1
A execute() 0 10 2
A resolveCurrentPage() 0 4 1
A resolveCurrentPath() 0 4 1
A getValidatorRules() 0 15 3
A makeDefaultOrder() 0 6 2
A makeColumn() 0 6 1
A setupColumnOptions() 0 6 1
A __toString() 0 4 1

How to fix   Complexity   

Complex Class

Complex classes like Grid 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 Grid, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace Boduch\Grid;
4
5
use Boduch\Grid\Components\Component;
6
use Boduch\Grid\Components\RowAction;
7
use Boduch\Grid\Source\SourceInterface;
8
use Illuminate\Pagination\LengthAwarePaginator;
9
use Illuminate\Pagination\Paginator;
10
11
class Grid
12
{
13
    /**
14
     * @var string
15
     */
16
    protected $template = 'laravel-grid::grid';
17
18
    /**
19
     * @var GridHelper
20
     */
21
    protected $gridHelper;
22
23
    /**
24
     * @var SourceInterface
25
     */
26
    protected $source;
27
28
    /**
29
     * @var Column[]
30
     */
31
    protected $columns = [];
32
33
    /**
34
     * @var int
35
     */
36
    protected $perPage = 15;
37
38
    /**
39
     * @var string
40
     */
41
    protected $emptyMessage = 'Brak danych do wyświetlenia.';
42
43
    /**
44
     * @var Rows
45
     */
46
    protected $rows;
47
48
    /**
49
     * Total number of records.
50
     *
51
     * @var int
52
     */
53
    protected $total = 0;
54
55
    /**
56
     * @var RowAction[]
57
     */
58
    protected $rowActions = [];
59
60
    /**
61
     * @var array
62
     */
63
    protected $defaultOrder = [
64
        'column' => 'id',
65
        'direction' => 'desc'
66
    ];
67
68
    /**
69
     * @var Order
70
     */
71
    protected $order;
72
73
    /**
74
     * @var bool
75
     */
76
    protected $enablePagination = true;
77
78
    /**
79
     * @var callable
80
     */
81
    protected $eachCallback;
82
83
    /**
84
     * @var array
85
     */
86
    protected $viewData = [];
87
88
    /**
89
     * @param GridHelper $gridHelper
90
     */
91
    public function __construct(GridHelper $gridHelper)
92
    {
93
        $this->gridHelper = $gridHelper;
94
95
        $this->makeDefaultOrder();
96
    }
97
98
    public function buildGrid()
99
    {
100
        //
101
    }
102
103
    /**
104
     * @return GridHelper
105
     */
106
    public function getGridHelper()
107
    {
108
        return $this->gridHelper;
109
    }
110
111
    /**
112
     * @param SourceInterface $source
113
     * @return $this
114
     */
115
    public function setSource(SourceInterface $source)
116
    {
117
        $this->source = $source;
118
119
        return $this;
120
    }
121
122
    /**
123
     * @param string $name
124
     * @param array $options
125
     * @return $this
126
     */
127
    public function addColumn($name, array $options = [])
128
    {
129
        if ($name instanceof Column) {
130
            $column = $name;
131
        } else {
132
            $column = $this->makeColumn($name, $options);
133
        }
134
135
        $column->setGrid($this);
136
        $this->columns[$column->getName()] = $column;
137
138
        return $this;
139
    }
140
141
    /**
142
     * @return Column[]
143
     */
144
    public function getColumns()
145
    {
146
        return $this->columns;
147
    }
148
149
    /**
150
     * @param Order $order
151
     * @return $this
152
     */
153
    public function setDefaultOrder(Order $order)
154
    {
155
        $this->order = $order;
156
157
        return $this;
158
    }
159
160
    /**
161
     * @return Order
162
     */
163
    public function getOrder()
164
    {
165
        return $this->order;
166
    }
167
168
    /**
169
     * @param int $perPage
170
     * @return $this
171
     */
172
    public function setPerPage($perPage)
173
    {
174
        $this->perPage = $perPage;
175
176
        return $this;
177
    }
178
179
    /**
180
     * @return int
181
     */
182
    public function getPerPage()
183
    {
184
        return $this->perPage;
185
    }
186
187
    /**
188
     * @return string
189
     */
190
    public function getEmptyMessage()
191
    {
192
        return $this->emptyMessage;
193
    }
194
195
    /**
196
     * @param string $emptyMessage
197
     */
198
    public function setEmptyMessage($emptyMessage)
199
    {
200
        $this->emptyMessage = $emptyMessage;
201
    }
202
203
    /**
204
     * @param RowAction $rowAction
205
     * @return $this
206
     */
207
    public function addRowAction(RowAction $rowAction)
208
    {
209
        $rowAction->setGrid($this);
210
        $this->rowActions[] = $rowAction;
211
212
        return $this;
213
    }
214
215
    /**
216
     * @param bool $flag
217
     * @return $this
218
     */
219
    public function setEnablePagination($flag)
220
    {
221
        $this->enablePagination = (bool) $flag;
222
        $this->setPerPage(null);
223
224
        return $this;
225
    }
226
227
    /**
228
     * @return bool
229
     */
230
    public function isPaginationEnabled()
231
    {
232
        return $this->enablePagination;
233
    }
234
235
    /**
236
     * @param callable $callback
237
     */
238
    public function each(callable $callback)
239
    {
240
        $this->eachCallback = $callback;
241
    }
242
243
    /**
244
     * @param Component $component
245
     * @return $this
246
     */
247
    public function addComponent(Component $component)
248
    {
249
        $component->setGrid($this);
250
        $this->viewData[$component->getName()] = $component->render();
251
252
        return $this;
253
    }
254
255
    /**
256
     * @param array $viewData
257
     * @return $this
258
     */
259
    public function setViewData($viewData)
260
    {
261
        $this->viewData = $viewData;
262
263
        return $this;
264
    }
265
266
    /**
267
     * @return \Illuminate\View\View;
0 ignored issues
show
Documentation introduced by
The doc-type \Illuminate\View\View; could not be parsed: Expected "|" or "end of type", but got ";" at position 21. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
268
     */
269
    public function render()
270
    {
271
        $rows = $this->getRows();
272
        $pagination = null;
273
274
        if ($this->enablePagination) {
275
            $pagination = $this->getPaginator($rows)->appends($this->gridHelper->getRequest()->except('page'));
276
        }
277
278
        return $this->gridHelper->getView()->make($this->template, [
279
            'columns'       => $this->columns,
280
            'rows'          => $rows,
281
            'pagination'    => $pagination,
282
            'grid'          => $this,
283
            'is_filterable' => $this->isFilterable()
284
        ], $this->viewData);
285
    }
286
287
    /**
288
     * Is table filterable?
289
     *
290
     * @return bool
291
     */
292
    public function isFilterable()
293
    {
294
        $hasFilters = false;
295
296
        foreach ($this->columns as $column) {
297
            if ($column->isFilterable()) {
298
                $hasFilters = true;
299
                break;
300
            }
301
        }
302
303
        return $hasFilters;
304
    }
305
306
    /**
307
     * @return Rows
308
     */
309
    public function getRows()
310
    {
311
        if (empty($this->source)) {
312
            throw new \InvalidArgumentException('You MUST set the data grid source by calling setSource() method.');
313
        }
314
315
        if (!empty($this->rows)) {
316
            return $this->rows;
317
        }
318
319
        if ($this->gridHelper->getRequest()->has('column') && !empty($this->defaultOrder)) {
320
            $this->order = new Order(
321
                $this->gridHelper->getRequest()->get('column', $this->defaultOrder['column']),
322
                $this->gridHelper->getRequest()->get('direction', $this->defaultOrder['direction'])
323
            );
324
325
            $validator = $this->gridHelper->getValidatorInstance($this->getValidatorRules());
326
327
            if ($validator->fails()) {
328
                $this->makeDefaultOrder();
329
            }
330
        }
331
332
        $data = $this->execute();
333
        $this->rows = new Rows();
334
335
        // special column for action buttons
336
        $actions = new Column(['name' => '__actions__']);
337
        $actions->setGrid($this);
338
339
        foreach ($data as $mixed) {
340
            $row = new Row($mixed);
341
            $row->setGrid($this);
342
343
            foreach ($this->columns as $column) {
344
                $row->addCell(new Cell($column, $mixed));
345
            }
346
347
            $row->addCell((new Action($actions, $mixed))->setRowActions($this->rowActions));
348
349
            if ($this->eachCallback) {
350
                $this->eachCallback->call($this, $row);
351
            }
352
            $this->rows->addRow($row);
353
        }
354
355
        $this->columns[] = $actions;
356
357
        return $this->rows;
358
    }
359
360
    /**
361
     * @param Rows $rows
362
     * @return LengthAwarePaginator
363
     */
364
    protected function getPaginator(Rows $rows)
365
    {
366
        return new LengthAwarePaginator($rows, $this->total, $this->perPage, $this->resolveCurrentPage(), [
367
            'path' => $this->resolveCurrentPath(),
368
        ]);
369
    }
370
371
    /**
372
     * @return mixed
373
     */
374
    protected function execute()
375
    {
376
        $this->source->applyFilters($this->columns, $this->gridHelper->getRequest());
377
378
        if ($this->enablePagination) {
379
            $this->total = $this->source->total();
380
        }
381
382
        return $this->source->execute($this->perPage, $this->resolveCurrentPage(), $this->order);
383
    }
384
385
    /**
386
     * @return int
387
     */
388
    protected function resolveCurrentPage()
389
    {
390
        return Paginator::resolveCurrentPage();
391
    }
392
393
    /**
394
     * @return string
395
     */
396
    protected function resolveCurrentPath()
397
    {
398
        return Paginator::resolveCurrentPath();
399
    }
400
401
    /**
402
     * @return array
403
     */
404
    protected function getValidatorRules()
405
    {
406
        $allowed = [];
407
408
        foreach ($this->columns as $column) {
409
            if ($column->isSortable()) {
410
                $allowed[] = $column->getName();
411
            }
412
        }
413
414
        return [
415
            'column' => 'sometimes|in:' . implode(',', $allowed),
416
            'direction' => 'sometimes|in:asc,desc'
417
        ];
418
    }
419
420
    protected function makeDefaultOrder()
421
    {
422
        $this->order = $this->defaultOrder
423
            ? new Order($this->defaultOrder['column'], $this->defaultOrder['direction'])
424
            : new Order();
425
    }
426
427
    /**
428
     * @param string $name
429
     * @param array $options
430
     * @return Column
431
     */
432
    protected function makeColumn($name, array $options = [])
433
    {
434
        $options = $this->setupColumnOptions($name, $options);
435
436
        return new Column($options);
437
    }
438
439
    /**
440
     * @param string $name
441
     * @param array $options
442
     * @return array
443
     */
444
    protected function setupColumnOptions($name, array $options)
445
    {
446
        $default = ['name' => $name];
447
448
        return array_merge($default, $options);
449
    }
450
451
    /**
452
     * @return string
453
     */
454
    public function __toString()
455
    {
456
        return (string) $this->render();
457
    }
458
}
459