Grid::render()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
nc 2
nop 0
dl 0
loc 17
rs 9.7
c 0
b 0
f 0
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 $afterCallback;
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
     * @param string $name
143
     * @return Column|null
144
     */
145
    public function getColumn($name)
146
    {
147
        return $this->columns[$name] ?? null;
148
    }
149
150
    /**
151
     * @return Column[]
152
     */
153
    public function getColumns()
154
    {
155
        return $this->columns;
156
    }
157
158
    /**
159
     * @param Order $order
160
     * @return $this
161
     */
162
    public function setDefaultOrder(Order $order)
163
    {
164
        $this->order = $order;
165
166
        return $this;
167
    }
168
169
    /**
170
     * @return Order
171
     */
172
    public function getOrder()
173
    {
174
        return $this->order;
175
    }
176
177
    /**
178
     * @param int $perPage
179
     * @return $this
180
     */
181
    public function setPerPage($perPage)
182
    {
183
        $this->perPage = $perPage;
184
185
        return $this;
186
    }
187
188
    /**
189
     * @return int
190
     */
191
    public function getPerPage()
192
    {
193
        return $this->perPage;
194
    }
195
196
    /**
197
     * @return string
198
     */
199
    public function getEmptyMessage()
200
    {
201
        return $this->emptyMessage;
202
    }
203
204
    /**
205
     * @param string $emptyMessage
206
     * @return $this
207
     */
208
    public function setEmptyMessage($emptyMessage)
209
    {
210
        $this->emptyMessage = $emptyMessage;
211
212
        return $this;
213
    }
214
215
    /**
216
     * @param RowAction $rowAction
217
     * @return $this
218
     */
219
    public function addRowAction(RowAction $rowAction)
220
    {
221
        $rowAction->setGrid($this);
222
        $this->rowActions[] = $rowAction;
223
224
        return $this;
225
    }
226
227
    /**
228
     * @param bool $flag
229
     * @return $this
230
     */
231
    public function setEnablePagination($flag)
232
    {
233
        $this->enablePagination = (bool) $flag;
234
        $this->setPerPage(null);
235
236
        return $this;
237
    }
238
239
    /**
240
     * @return bool
241
     */
242
    public function isPaginationEnabled()
243
    {
244
        return $this->enablePagination;
245
    }
246
247
    /**
248
     * @param callable $callback
249
     * @deprecated
250
     */
251
    public function each(callable $callback)
252
    {
253
        $this->after($callback);
254
    }
255
256
    /**
257
     * @param callable $callback
258
     * @return $this
259
     */
260
    public function after(callable $callback)
261
    {
262
        $this->afterCallback = $callback;
263
264
        return $this;
265
    }
266
267
    /**
268
     * @param Component $component
269
     * @return $this
270
     */
271
    public function addComponent(Component $component)
272
    {
273
        $component->setGrid($this);
274
        $this->viewData[$component->getName()] = $component->render();
275
276
        return $this;
277
    }
278
279
    /**
280
     * @param array $viewData
281
     * @return $this
282
     */
283
    public function setViewData($viewData)
284
    {
285
        $this->viewData = $viewData;
286
287
        return $this;
288
    }
289
290
    /**
291
     * @return \Illuminate\View\View
292
     */
293
    public function render()
294
    {
295
        $rows = $this->getRows();
296
        $pagination = null;
297
298
        if ($this->enablePagination) {
299
            $pagination = $this->getPaginator($rows)->appends($this->gridHelper->getRequest()->except('page'));
300
        }
301
302
        return $this->gridHelper->getView()->make($this->template, [
303
            'columns'       => $this->columns,
304
            'rows'          => $rows,
305
            'pagination'    => $pagination,
306
            'grid'          => $this,
307
            'is_filterable' => $this->isFilterable()
308
        ], $this->viewData);
309
    }
310
311
    /**
312
     * Is table filterable?
313
     *
314
     * @return bool
315
     */
316
    public function isFilterable()
317
    {
318
        $hasFilters = false;
319
320
        foreach ($this->columns as $column) {
321
            if ($column->isFilterable()) {
322
                $hasFilters = true;
323
                break;
324
            }
325
        }
326
327
        return $hasFilters;
328
    }
329
330
    /**
331
     * @return Rows
332
     */
333
    public function getRows()
334
    {
335
        if (empty($this->source)) {
336
            throw new \InvalidArgumentException('You MUST set the data grid source by calling setSource() method.');
337
        }
338
339
        if (!empty($this->rows)) {
340
            return $this->rows;
341
        }
342
343
        if ($this->gridHelper->getRequest()->has('column') && !empty($this->defaultOrder)) {
344
            $this->order = new Order(
345
                $this->gridHelper->getRequest()->get('column', $this->defaultOrder['column']),
346
                $this->gridHelper->getRequest()->get('direction', $this->defaultOrder['direction'])
347
            );
348
349
            $validator = $this->gridHelper->getValidatorInstance($this->getValidatorRules());
350
351
            if ($validator->fails()) {
352
                $this->makeDefaultOrder();
353
            }
354
        }
355
356
        $data = $this->execute();
357
        $this->rows = new Rows();
358
359
        // special column for action buttons
360
        $actions = new Column(['name' => '__actions__']);
361
        $actions->setGrid($this);
362
363
        foreach ($data as $mixed) {
364
            $row = new Row($mixed);
365
            $row->setGrid($this);
366
367
            foreach ($this->columns as $column) {
368
                $row->addCell(new Cell($column, $mixed));
369
            }
370
371
            $row->addCell((new Action($actions, $mixed))->setRowActions($this->rowActions));
372
            $this->rows->addRow($row);
373
        }
374
375
        $this->columns[] = $actions;
376
377
        // finally call callback on every row so we can modify rows, cells, attributes etc...
378
        if ($this->afterCallback) {
379
            foreach ($this->rows as $row) {
380
                $this->afterCallback->call($this, $row);
381
            }
382
        }
383
384
        return $this->rows;
385
    }
386
387
    /**
388
     * @param Rows $rows
389
     * @return LengthAwarePaginator
390
     */
391
    protected function getPaginator(Rows $rows)
392
    {
393
        return new LengthAwarePaginator($rows, $this->total, $this->perPage, $this->resolveCurrentPage(), [
394
            'path' => $this->resolveCurrentPath(),
395
        ]);
396
    }
397
398
    /**
399
     * @return mixed
400
     */
401
    protected function execute()
402
    {
403
        // apply filters first
404
        $this->source->applyFilters($this->columns);
405
406
        // calculate total rows to build pagination
407
        if ($this->enablePagination) {
408
            $this->total = $this->source->total();
409
        }
410
411
        return $this->source->execute($this->perPage, $this->resolveCurrentPage(), $this->order);
412
    }
413
414
    /**
415
     * @return int
416
     */
417
    protected function resolveCurrentPage()
418
    {
419
        return Paginator::resolveCurrentPage();
420
    }
421
422
    /**
423
     * @return string
424
     */
425
    protected function resolveCurrentPath()
426
    {
427
        return Paginator::resolveCurrentPath();
428
    }
429
430
    /**
431
     * @return array
432
     */
433
    protected function getValidatorRules()
434
    {
435
        $allowed = [];
436
437
        foreach ($this->columns as $column) {
438
            if ($column->isSortable()) {
439
                $allowed[] = $column->getName();
440
            }
441
        }
442
443
        return [
444
            'column' => 'sometimes|in:' . implode(',', $allowed),
445
            'direction' => 'sometimes|in:asc,desc'
446
        ];
447
    }
448
449
    protected function makeDefaultOrder()
450
    {
451
        $this->order = $this->defaultOrder
452
            ? new Order($this->defaultOrder['column'], $this->defaultOrder['direction'])
453
            : new Order();
454
    }
455
456
    /**
457
     * @param string $name
458
     * @param array $options
459
     * @return Column
460
     */
461
    protected function makeColumn($name, array $options = [])
462
    {
463
        $options = $this->setupColumnOptions($name, $options);
464
465
        if (empty($options['title'])) {
466
            $options['title'] = title_case(str_replace('_', ' ', $name));
467
        }
468
469
        return new Column($options);
470
    }
471
472
    /**
473
     * @param string $name
474
     * @param array $options
475
     * @return array
476
     */
477
    protected function setupColumnOptions($name, array $options)
478
    {
479
        $default = ['name' => $name];
480
481
        return array_merge($default, $options);
482
    }
483
484
    /**
485
     * @return string
486
     */
487
    public function __toString()
488
    {
489
        return (string) $this->render();
490
    }
491
}
492