Completed
Pull Request — master (#3089)
by Robin
02:20
created

Grid::setActions()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 1
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Encore\Admin;
4
5
use Closure;
6
use Encore\Admin\Exception\Handler;
7
use Encore\Admin\Grid\Column;
8
use Encore\Admin\Grid\Displayers;
9
use Encore\Admin\Grid\Exporter;
10
use Encore\Admin\Grid\Exporters\AbstractExporter;
11
use Encore\Admin\Grid\Filter;
12
use Encore\Admin\Grid\HasElementNames;
13
use Encore\Admin\Grid\Model;
14
use Encore\Admin\Grid\Row;
15
use Encore\Admin\Grid\Tools;
16
use Illuminate\Database\Eloquent\Model as Eloquent;
17
use Illuminate\Database\Eloquent\Relations;
18
use Illuminate\Support\Collection;
19
use Illuminate\Support\Facades\Input;
20
use Jenssegers\Mongodb\Eloquent\Model as MongodbModel;
21
22
class Grid
23
{
24
    use HasElementNames;
25
26
    /**
27
     * The grid data model instance.
28
     *
29
     * @var \Encore\Admin\Grid\Model
30
     */
31
    protected $model;
32
33
    /**
34
     * Collection of all grid columns.
35
     *
36
     * @var \Illuminate\Support\Collection
37
     */
38
    protected $columns;
39
40
    /**
41
     * Collection of all data rows.
42
     *
43
     * @var \Illuminate\Support\Collection
44
     */
45
    protected $rows;
46
47
    /**
48
     * Class of the grid action column.
49
     *
50
     * @var Encore\Admin\Grid\Displayers\Actions
51
     */
52
    protected static $actionsClass = Displayers\Actions::class;
53
54
    /**
55
     * Rows callable fucntion.
56
     *
57
     * @var \Closure
58
     */
59
    protected $rowsCallback;
60
61
    /**
62
     * All column names of the grid.
63
     *
64
     * @var array
65
     */
66
    public $columnNames = [];
67
68
    /**
69
     * Grid builder.
70
     *
71
     * @var \Closure
72
     */
73
    protected $builder;
74
75
    /**
76
     * Mark if the grid is builded.
77
     *
78
     * @var bool
79
     */
80
    protected $builded = false;
81
82
    /**
83
     * All variables in grid view.
84
     *
85
     * @var array
86
     */
87
    protected $variables = [];
88
89
    /**
90
     * The grid Filter.
91
     *
92
     * @var \Encore\Admin\Grid\Filter
93
     */
94
    protected $filter;
95
96
    /**
97
     * Resource path of the grid.
98
     *
99
     * @var
100
     */
101
    protected $resourcePath;
102
103
    /**
104
     * Default primary key name.
105
     *
106
     * @var string
107
     */
108
    protected $keyName = 'id';
109
110
    /**
111
     * Export driver.
112
     *
113
     * @var string
114
     */
115
    protected $exporter;
116
117
    /**
118
     * View for grid to render.
119
     *
120
     * @var string
121
     */
122
    protected $view = 'admin::grid.table';
123
124
    /**
125
     * Per-page options.
126
     *
127
     * @var array
128
     */
129
    public $perPages = [10, 20, 30, 50, 100];
130
131
    /**
132
     * Default items count per-page.
133
     *
134
     * @var int
135
     */
136
    public $perPage = 20;
137
138
    /**
139
     * Header tools.
140
     *
141
     * @var Tools
142
     */
143
    public $tools;
144
145
    /**
146
     * Callback for grid actions.
147
     *
148
     * @var Closure
149
     */
150
    protected $actionsCallback;
151
152
    /**
153
     * Options for grid.
154
     *
155
     * @var array
156
     */
157
    protected $options = [
158
        'show_pagination'   => true,
159
        'show_tools'        => true,
160
        'show_filter'       => true,
161
        'show_exporter'     => true,
162
        'show_actions'      => true,
163
        'show_row_selector' => true,
164
        'show_create_btn'   => true,
165
    ];
166
167
    /**
168
     * @var Closure
169
     */
170
    protected $header;
171
172
    /**
173
     * @var Closure
174
     */
175
    protected $footer;
176
177
    /**
178
     * @var Closure
179
     */
180
    protected static $initCallback;
181
182
    /**
183
     * Create a new grid instance.
184
     *
185
     * @param Eloquent $model
186
     * @param Closure  $builder
187
     */
188
    public function __construct(Eloquent $model, Closure $builder = null)
189
    {
190
        $this->keyName = $model->getKeyName();
191
        $this->model = new Model($model);
192
        $this->columns = new Collection();
193
        $this->rows = new Collection();
194
        $this->builder = $builder;
195
196
        $this->model()->setGrid($this);
197
198
        $this->setupTools();
199
        $this->setupFilter();
200
201
        $this->handleExportRequest();
202
203
        if (static::$initCallback instanceof Closure) {
204
            call_user_func(static::$initCallback, $this);
205
        }
206
    }
207
208
    /**
209
     * Initialize with user pre-defined default disables and exporter, etc.
210
     *
211
     * @param Closure $callback
212
     */
213
    public static function init(Closure $callback = null)
214
    {
215
        static::$initCallback = $callback;
216
    }
217
218
    /**
219
     * Setup grid tools.
220
     */
221
    public function setupTools()
222
    {
223
        $this->tools = new Tools($this);
224
    }
225
226
    /**
227
     * Setup grid actions column class.
228
     *
229
     * @return void
230
     */
231
    public static function setActions($class)
232
    {
233
        self::$actionsClass = $class;
234
    }
235
236
    /**
237
     * Setup grid filter.
238
     *
239
     * @return void
240
     */
241
    protected function setupFilter()
242
    {
243
        $this->filter = new Filter($this->model());
244
    }
245
246
    /**
247
     * Handle export request.
248
     *
249
     * @param bool $forceExport
250
     */
251
    protected function handleExportRequest($forceExport = false)
252
    {
253
        if (!$scope = request(Exporter::$queryName)) {
254
            return;
255
        }
256
257
        // clear output buffer.
258
        if (ob_get_length()) {
259
            ob_end_clean();
260
        }
261
262
        $this->model()->usePaginate(false);
263
264
        if ($this->builder) {
265
            call_user_func($this->builder, $this);
266
267
            $this->getExporter($scope)->export();
268
        }
269
270
        if ($forceExport) {
271
            $this->getExporter($scope)->export();
272
        }
273
    }
274
275
    /**
276
     * @param string $scope
277
     *
278
     * @return AbstractExporter
279
     */
280
    protected function getExporter($scope)
281
    {
282
        return (new Exporter($this))->resolve($this->exporter)->withScope($scope);
283
    }
284
285
    /**
286
     * Get or set option for grid.
287
     *
288
     * @param string $key
289
     * @param mixed  $value
290
     *
291
     * @return $this|mixed
292
     */
293
    public function option($key, $value = null)
294
    {
295
        if (is_null($value)) {
296
            return $this->options[$key];
297
        }
298
299
        $this->options[$key] = $value;
300
301
        return $this;
302
    }
303
304
    /**
305
     * Get primary key name of model.
306
     *
307
     * @return string
308
     */
309
    public function getKeyName()
310
    {
311
        return $this->keyName ?: 'id';
312
    }
313
314
    /**
315
     * Add column to Grid.
316
     *
317
     * @param string $name
318
     * @param string $label
319
     *
320
     * @return Column
321
     */
322
    public function column($name, $label = '')
323
    {
324
        $relationName = $relationColumn = '';
325
326
        if (strpos($name, '.') !== false) {
327
            list($relationName, $relationColumn) = explode('.', $name);
328
329
            $relation = $this->model()->eloquent()->$relationName();
330
331
            $label = empty($label) ? ucfirst($relationColumn) : $label;
332
333
            $name = snake_case($relationName).'.'.$relationColumn;
334
        }
335
336
        $column = $this->addColumn($name, $label);
337
338
        if (isset($relation) && $relation instanceof Relations\Relation) {
339
            $this->model()->with($relationName);
340
            $column->setRelation($relationName, $relationColumn);
341
        }
342
343
        return $column;
344
    }
345
346
    /**
347
     * Batch add column to grid.
348
     *
349
     * @example
350
     * 1.$grid->columns(['name' => 'Name', 'email' => 'Email' ...]);
351
     * 2.$grid->columns('name', 'email' ...)
352
     *
353
     * @param array $columns
354
     *
355
     * @return Collection|null
356
     */
357
    public function columns($columns = [])
358
    {
359
        if (func_num_args() == 0) {
360
            return $this->columns;
361
        }
362
363
        if (func_num_args() == 1 && is_array($columns)) {
364
            foreach ($columns as $column => $label) {
365
                $this->column($column, $label);
366
            }
367
368
            return;
369
        }
370
371
        foreach (func_get_args() as $column) {
372
            $this->column($column);
373
        }
374
    }
375
376
    /**
377
     * Get all visible column instances.
378
     *
379
     * @return Collection|static
380
     */
381 View Code Duplication
    public function visibleColumns()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
382
    {
383
        $visible = array_filter(explode(',', request(Tools\ColumnSelector::SELECT_COLUMN_NAME)));
384
385
        if (empty($visible)) {
386
            return $this->columns;
387
        }
388
389
        array_push($visible, '__row_selector__', '__actions__');
390
391
        return $this->columns->filter(function (Column $column) use ($visible) {
392
            return in_array($column->getName(), $visible);
393
        });
394
    }
395
396
    /**
397
     * Get all visible column names.
398
     *
399
     * @return array|static
400
     */
401 View Code Duplication
    public function visibleColumnNames()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
402
    {
403
        $visible = array_filter(explode(',', request(Tools\ColumnSelector::SELECT_COLUMN_NAME)));
404
405
        if (empty($visible)) {
406
            return $this->columnNames;
407
        }
408
409
        array_push($visible, '__row_selector__', '__actions__');
410
411
        return collect($this->columnNames)->filter(function ($column) use ($visible) {
412
            return in_array($column, $visible);
413
        });
414
    }
415
416
    /**
417
     * Add column to grid.
418
     *
419
     * @param string $column
420
     * @param string $label
421
     *
422
     * @return Column
423
     */
424 View Code Duplication
    protected function addColumn($column = '', $label = '')
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
425
    {
426
        $column = new Column($column, $label);
427
        $column->setGrid($this);
428
429
        return tap($column, function ($value) {
430
            $this->columns->push($value);
431
        });
432
    }
433
434
    /**
435
     * Prepend column to grid.
436
     *
437
     * @param string $column
438
     * @param string $label
439
     *
440
     * @return Column
441
     */
442 View Code Duplication
    protected function prependColumn($column = '', $label = '')
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
443
    {
444
        $column = new Column($column, $label);
445
        $column->setGrid($this);
446
447
        return tap($column, function ($value) {
448
            $this->columns->prepend($value);
449
        });
450
    }
451
452
    /**
453
     * Get Grid model.
454
     *
455
     * @return Model
456
     */
457
    public function model()
458
    {
459
        return $this->model;
460
    }
461
462
    /**
463
     * Paginate the grid.
464
     *
465
     * @param int $perPage
466
     *
467
     * @return void
468
     */
469
    public function paginate($perPage = 20)
470
    {
471
        $this->perPage = $perPage;
472
473
        $this->model()->paginate($perPage);
0 ignored issues
show
Bug introduced by
The method paginate() does not exist on Encore\Admin\Grid\Model. Did you maybe mean usePaginate()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
474
    }
475
476
    /**
477
     * Get the grid paginator.
478
     *
479
     * @return mixed
480
     */
481
    public function paginator()
482
    {
483
        return new Tools\Paginator($this);
484
    }
485
486
    /**
487
     * Disable grid pagination.
488
     *
489
     * @return $this
490
     */
491
    public function disablePagination(bool $disable = true)
492
    {
493
        $this->model->usePaginate(!$disable);
494
495
        return $this->option('show_pagination', !$disable);
496
    }
497
498
    /**
499
     * If this grid use pagination.
500
     *
501
     * @return bool
502
     */
503
    public function showPagination()
504
    {
505
        return $this->option('show_pagination');
506
    }
507
508
    /**
509
     * Set per-page options.
510
     *
511
     * @param array $perPages
512
     */
513
    public function perPages(array $perPages)
514
    {
515
        $this->perPages = $perPages;
516
    }
517
518
    /**
519
     * Disable all actions.
520
     *
521
     * @return $this
522
     */
523
    public function disableActions(bool $disable = true)
524
    {
525
        return $this->option('show_actions', !$disable);
526
    }
527
528
    /**
529
     * Set grid action callback.
530
     *
531
     * @param Closure $callback
532
     *
533
     * @return $this
534
     */
535
    public function actions(Closure $callback)
536
    {
537
        $this->actionsCallback = $callback;
538
539
        return $this;
540
    }
541
542
    /**
543
     * Add `actions` column for grid.
544
     *
545
     * @return void
546
     */
547
    protected function appendActionsColumn()
548
    {
549
        if (!$this->option('show_actions')) {
550
            return;
551
        }
552
553
        $this->addColumn('__actions__', trans('admin.action'))
554
            ->displayUsing(self::$actionsClass, [$this->actionsCallback]);
555
    }
556
557
    /**
558
     * Disable row selector.
559
     *
560
     * @return Grid|mixed
561
     */
562
    public function disableRowSelector(bool $disable = true)
563
    {
564
        $this->tools->disableBatchActions($disable);
565
566
        return $this->option('show_row_selector', !$disable);
567
    }
568
569
    /**
570
     * Prepend checkbox column for grid.
571
     *
572
     * @return void
573
     */
574
    protected function prependRowSelectorColumn()
575
    {
576
        if (!$this->option('show_row_selector')) {
577
            return;
578
        }
579
580
        $this->prependColumn(Column::SELECT_COLUMN_NAME, ' ')
581
            ->displayUsing(Displayers\RowSelector::class);
582
    }
583
584
    /**
585
     * Build the grid.
586
     *
587
     * @return void
588
     */
589
    public function build()
590
    {
591
        if ($this->builded) {
592
            return;
593
        }
594
595
        $collection = $this->processFilter(false);
596
597
        $data = $collection->toArray();
598
599
        $this->prependRowSelectorColumn();
600
        $this->appendActionsColumn();
601
602
        Column::setOriginalGridModels($collection);
603
604
        $this->columns->map(function (Column $column) use (&$data) {
605
            $data = $column->fill($data);
606
607
            $this->columnNames[] = $column->getName();
608
        });
609
610
        $this->buildRows($data);
611
612
        $this->builded = true;
613
    }
614
615
    /**
616
     * Disable header tools.
617
     *
618
     * @return $this
619
     */
620
    public function disableTools(bool $disable = true)
621
    {
622
        return $this->option('show_tools', !$disable);
623
    }
624
625
    /**
626
     * Disable grid filter.
627
     *
628
     * @return $this
629
     */
630
    public function disableFilter(bool $disable = true)
631
    {
632
        $this->tools->disableFilterButton($disable);
633
634
        return $this->option('show_filter', !$disable);
635
    }
636
637
    /**
638
     * Get filter of Grid.
639
     *
640
     * @return Filter
641
     */
642
    public function getFilter()
643
    {
644
        return $this->filter;
645
    }
646
647
    /**
648
     * Process the grid filter.
649
     *
650
     * @param bool $toArray
651
     *
652
     * @return array|Collection|mixed
653
     */
654
    public function processFilter($toArray = true)
655
    {
656
        if ($this->builder) {
657
            call_user_func($this->builder, $this);
658
        }
659
660
        return $this->filter->execute($toArray);
661
    }
662
663
    /**
664
     * Set the grid filter.
665
     *
666
     * @param Closure $callback
667
     */
668
    public function filter(Closure $callback)
669
    {
670
        call_user_func($callback, $this->filter);
671
    }
672
673
    /**
674
     * Render the grid filter.
675
     *
676
     * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View|string
677
     */
678
    public function renderFilter()
679
    {
680
        if (!$this->option('show_filter')) {
681
            return '';
682
        }
683
684
        return $this->filter->render();
685
    }
686
687
    /**
688
     * Expand filter.
689
     *
690
     * @return $this
691
     */
692
    public function expandFilter()
693
    {
694
        $this->filter->expand();
695
696
        return $this;
697
    }
698
699
    /**
700
     * Build the grid rows.
701
     *
702
     * @param array $data
703
     *
704
     * @return void
705
     */
706
    protected function buildRows(array $data)
707
    {
708
        $this->rows = collect($data)->map(function ($model, $number) {
709
            return new Row($number, $model);
710
        });
711
712
        if ($this->rowsCallback) {
713
            $this->rows->map($this->rowsCallback);
714
        }
715
    }
716
717
    /**
718
     * Set grid row callback function.
719
     *
720
     * @param Closure $callable
721
     *
722
     * @return Collection|null
723
     */
724
    public function rows(Closure $callable = null)
725
    {
726
        if (is_null($callable)) {
727
            return $this->rows;
728
        }
729
730
        $this->rowsCallback = $callable;
731
    }
732
733
    /**
734
     * Setup grid tools.
735
     *
736
     * @param Closure $callback
737
     *
738
     * @return void
739
     */
740
    public function tools(Closure $callback)
741
    {
742
        call_user_func($callback, $this->tools);
743
    }
744
745
    /**
746
     * Render custom tools.
747
     *
748
     * @return string
749
     */
750
    public function renderHeaderTools()
751
    {
752
        return $this->tools->render();
753
    }
754
755
    /**
756
     * Set exporter driver for Grid to export.
757
     *
758
     * @param $exporter
759
     *
760
     * @return $this
761
     */
762
    public function exporter($exporter)
763
    {
764
        $this->exporter = $exporter;
765
766
        return $this;
767
    }
768
769
    /**
770
     * Get the export url.
771
     *
772
     * @param int  $scope
773
     * @param null $args
774
     *
775
     * @return string
776
     */
777
    public function getExportUrl($scope = 1, $args = null)
778
    {
779
        $input = array_merge(Input::all(), Exporter::formatExportQuery($scope, $args));
780
781
        if ($constraints = $this->model()->getConstraints()) {
782
            $input = array_merge($input, $constraints);
783
        }
784
785
        return $this->resource().'?'.http_build_query($input);
786
    }
787
788
    /**
789
     * Get create url.
790
     *
791
     * @return string
792
     */
793
    public function getCreateUrl()
794
    {
795
        $queryString = '';
796
797
        if ($constraints = $this->model()->getConstraints()) {
798
            $queryString = http_build_query($constraints);
799
        }
800
801
        return sprintf(
802
            '%s/create%s',
803
            $this->resource(),
804
            $queryString ? ('?'.$queryString) : ''
805
        );
806
    }
807
808
    /**
809
     * If grid show header tools.
810
     *
811
     * @return bool
812
     */
813
    public function showTools()
814
    {
815
        return $this->option('show_tools');
816
    }
817
818
    /**
819
     * If grid show export btn.
820
     *
821
     * @return bool
822
     */
823
    public function showExportBtn()
824
    {
825
        return $this->option('show_exporter');
826
    }
827
828
    /**
829
     * Disable export.
830
     *
831
     * @return $this
832
     */
833
    public function disableExport(bool $disable = true)
834
    {
835
        return $this->option('show_exporter', !$disable);
836
    }
837
838
    /**
839
     * Render export button.
840
     *
841
     * @return string
842
     */
843
    public function renderExportButton()
844
    {
845
        return (new Tools\ExportButton($this))->render();
846
    }
847
848
    /**
849
     * Alias for method `disableCreateButton`.
850
     *
851
     * @return $this
852
     *
853
     * @deprecated
854
     */
855
    public function disableCreation()
856
    {
857
        return $this->disableCreateButton();
858
    }
859
860
    /**
861
     * Remove create button on grid.
862
     *
863
     * @return $this
864
     */
865
    public function disableCreateButton(bool $disable = true)
866
    {
867
        return $this->option('show_create_btn', !$disable);
868
    }
869
870
    /**
871
     * If allow creation.
872
     *
873
     * @return bool
874
     */
875
    public function showCreateBtn()
876
    {
877
        return $this->option('show_create_btn');
878
    }
879
880
    /**
881
     * Render create button for grid.
882
     *
883
     * @return string
884
     */
885
    public function renderCreateButton()
886
    {
887
        return (new Tools\CreateButton($this))->render();
888
    }
889
890
    /**
891
     * @return string
892
     */
893
    public function renderColumnSelector()
894
    {
895
        return (new Grid\Tools\ColumnSelector($this))->render();
896
    }
897
898
    /**
899
     * Set grid header.
900
     *
901
     * @param Closure|null $closure
902
     *
903
     * @return $this|Closure
904
     */
905
    public function header(Closure $closure = null)
906
    {
907
        if (!$closure) {
908
            return $this->header;
909
        }
910
911
        $this->header = $closure;
912
913
        return $this;
914
    }
915
916
    /**
917
     * Render grid header.
918
     *
919
     * @return Tools\Header|string
920
     */
921
    public function renderHeader()
922
    {
923
        if (!$this->header) {
924
            return '';
925
        }
926
927
        return (new Tools\Header($this))->render();
928
    }
929
930
    /**
931
     * Set grid footer.
932
     *
933
     * @param Closure|null $closure
934
     *
935
     * @return $this|Closure
936
     */
937
    public function footer(Closure $closure = null)
938
    {
939
        if (!$closure) {
940
            return $this->footer;
941
        }
942
943
        $this->footer = $closure;
944
945
        return $this;
946
    }
947
948
    /**
949
     * Render grid footer.
950
     *
951
     * @return Tools\Footer|string
952
     */
953
    public function renderFooter()
954
    {
955
        if (!$this->footer) {
956
            return '';
957
        }
958
959
        return (new Tools\Footer($this))->render();
960
    }
961
962
    /**
963
     * Get current resource uri.
964
     *
965
     * @param string $path
966
     *
967
     * @return string
968
     */
969
    public function resource($path = null)
970
    {
971
        if (!empty($path)) {
972
            $this->resourcePath = $path;
973
974
            return $this;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this; (Encore\Admin\Grid) is incompatible with the return type documented by Encore\Admin\Grid::resource of type string.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
975
        }
976
977
        if (!empty($this->resourcePath)) {
978
            return $this->resourcePath;
979
        }
980
981
        return app('request')->getPathInfo();
982
    }
983
984
    /**
985
     * Handle get mutator column for grid.
986
     *
987
     * @param string $method
988
     * @param string $label
989
     *
990
     * @return bool|Column
991
     */
992
    protected function handleGetMutatorColumn($method, $label)
993
    {
994
        if ($this->model()->eloquent()->hasGetMutator($method)) {
995
            return $this->addColumn($method, $label);
996
        }
997
998
        return false;
999
    }
1000
1001
    /**
1002
     * Handle relation column for grid.
1003
     *
1004
     * @param string $method
1005
     * @param string $label
1006
     *
1007
     * @return bool|Column
1008
     */
1009
    protected function handleRelationColumn($method, $label)
1010
    {
1011
        $model = $this->model()->eloquent();
1012
1013
        if (!method_exists($model, $method)) {
1014
            return false;
1015
        }
1016
1017
        if (!($relation = $model->$method()) instanceof Relations\Relation) {
1018
            return false;
1019
        }
1020
1021
        if (
1022
            $relation instanceof Relations\HasOne ||
1023
            $relation instanceof Relations\BelongsTo ||
1024
            $relation instanceof Relations\MorphOne
1025
        ) {
1026
            $this->model()->with($method);
1027
1028
            return $this->addColumn($method, $label)->setRelation(snake_case($method));
1029
        }
1030
1031
        if (
1032
            $relation instanceof Relations\HasMany
1033
            || $relation instanceof Relations\BelongsToMany
1034
            || $relation instanceof Relations\MorphToMany
1035
        ) {
1036
            $this->model()->with($method);
1037
1038
            return $this->addColumn(snake_case($method), $label);
1039
        }
1040
1041
        return false;
1042
    }
1043
1044
    /**
1045
     * Dynamically add columns to the grid view.
1046
     *
1047
     * @param $method
1048
     * @param $arguments
1049
     *
1050
     * @return Column
1051
     */
1052
    public function __call($method, $arguments)
1053
    {
1054
        $label = isset($arguments[0]) ? $arguments[0] : ucfirst($method);
1055
1056
        if ($this->model()->eloquent() instanceof MongodbModel) {
0 ignored issues
show
Bug introduced by
The class Jenssegers\Mongodb\Eloquent\Model does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
1057
            return $this->addColumn($method, $label);
1058
        }
1059
1060
        if ($column = $this->handleGetMutatorColumn($method, $label)) {
1061
            return $column;
1062
        }
1063
1064
        if ($column = $this->handleRelationColumn($method, $label)) {
1065
            return $column;
1066
        }
1067
1068
        return $this->addColumn($method, $label);
1069
    }
1070
1071
    /**
1072
     * Register column displayers.
1073
     *
1074
     * @return void.
0 ignored issues
show
Documentation introduced by
The doc-type void. could not be parsed: Unknown type name "void." at position 0. (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...
1075
     */
1076
    public static function registerColumnDisplayer()
1077
    {
1078
        $map = [
1079
            'editable'    => Displayers\Editable::class,
1080
            'switch'      => Displayers\SwitchDisplay::class,
1081
            'switchGroup' => Displayers\SwitchGroup::class,
1082
            'select'      => Displayers\Select::class,
1083
            'image'       => Displayers\Image::class,
1084
            'label'       => Displayers\Label::class,
1085
            'button'      => Displayers\Button::class,
1086
            'link'        => Displayers\Link::class,
1087
            'badge'       => Displayers\Badge::class,
1088
            'progressBar' => Displayers\ProgressBar::class,
1089
            'radio'       => Displayers\Radio::class,
1090
            'checkbox'    => Displayers\Checkbox::class,
1091
            'orderable'   => Displayers\Orderable::class,
1092
            'table'       => Displayers\Table::class,
1093
            'expand'      => Displayers\Expand::class,
1094
            'modal'       => Displayers\Modal::class,
1095
        ];
1096
1097
        foreach ($map as $abstract => $class) {
1098
            Column::extend($abstract, $class);
1099
        }
1100
    }
1101
1102
    /**
1103
     * Add variables to grid view.
1104
     *
1105
     * @param array $variables
1106
     *
1107
     * @return $this
1108
     */
1109
    public function with($variables = [])
1110
    {
1111
        $this->variables = $variables;
1112
1113
        return $this;
1114
    }
1115
1116
    /**
1117
     * Get all variables will used in grid view.
1118
     *
1119
     * @return array
1120
     */
1121
    protected function variables()
1122
    {
1123
        $this->variables['grid'] = $this;
1124
1125
        return $this->variables;
1126
    }
1127
1128
    /**
1129
     * Set a view to render.
1130
     *
1131
     * @param string $view
1132
     * @param array  $variables
1133
     */
1134
    public function setView($view, $variables = [])
1135
    {
1136
        if (!empty($variables)) {
1137
            $this->with($variables);
1138
        }
1139
1140
        $this->view = $view;
1141
    }
1142
1143
    /**
1144
     * Set grid title.
1145
     *
1146
     * @param string $title
1147
     *
1148
     * @return $this
1149
     */
1150
    public function setTitle($title)
1151
    {
1152
        $this->variables['title'] = $title;
1153
1154
        return $this;
1155
    }
1156
1157
    /**
1158
     * Set relation for grid.
1159
     *
1160
     * @param Relations\Relation $relation
1161
     *
1162
     * @return $this
1163
     */
1164
    public function setRelation(Relations\Relation $relation)
1165
    {
1166
        $this->model()->setRelation($relation);
1167
1168
        return $this;
1169
    }
1170
1171
    /**
1172
     * Set resource path for grid.
1173
     *
1174
     * @param string $path
1175
     *
1176
     * @return $this
1177
     */
1178
    public function setResource($path)
1179
    {
1180
        $this->resourcePath = $path;
1181
1182
        return $this;
1183
    }
1184
1185
    /**
1186
     * Get the string contents of the grid view.
1187
     *
1188
     * @return string
1189
     */
1190
    public function render()
1191
    {
1192
        $this->handleExportRequest(true);
1193
1194
        try {
1195
            $this->build();
1196
        } catch (\Exception $e) {
1197
            return Handler::renderException($e);
1198
        }
1199
1200
        return view($this->view, $this->variables())->render();
0 ignored issues
show
Bug introduced by
The method render does only exist in Illuminate\View\View, but not in Illuminate\Contracts\View\Factory.

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:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
1201
    }
1202
}
1203