Completed
Pull Request — master (#2254)
by
unknown
11:30
created

Grid::__call()   B

Complexity

Conditions 6
Paths 10

Size

Total Lines 22

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
nc 10
nop 2
dl 0
loc 22
rs 8.9457
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\Actions;
9
use Encore\Admin\Grid\Displayers\RowSelector;
10
use Encore\Admin\Grid\Exporter;
11
use Encore\Admin\Grid\Filter;
12
use Encore\Admin\Grid\Model;
13
use Encore\Admin\Grid\Row;
14
use Encore\Admin\Grid\Tools;
15
use Illuminate\Database\Eloquent\Model as Eloquent;
16
use Illuminate\Database\Eloquent\Relations\BelongsTo;
17
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
18
use Illuminate\Database\Eloquent\Relations\HasMany;
19
use Illuminate\Database\Eloquent\Relations\HasOne;
20
use Illuminate\Database\Eloquent\Relations\MorphToMany;
21
use Illuminate\Database\Eloquent\Relations\Relation;
22
use Illuminate\Support\Collection;
23
use Illuminate\Support\Facades\Input;
24
use Illuminate\Support\Facades\Schema;
25
use Jenssegers\Mongodb\Eloquent\Model as MongodbModel;
26
27
class Grid
28
{
29
    /**
30
     * The grid data model instance.
31
     *
32
     * @var \Encore\Admin\Grid\Model
33
     */
34
    protected $model;
35
36
    /**
37
     * Collection of all grid columns.
38
     *
39
     * @var \Illuminate\Support\Collection
40
     */
41
    protected $columns;
42
43
    /**
44
     * Collection of table columns.
45
     *
46
     * @var \Illuminate\Support\Collection
47
     */
48
    protected $dbColumns;
49
50
    /**
51
     * Collection of all data rows.
52
     *
53
     * @var \Illuminate\Support\Collection
54
     */
55
    protected $rows;
56
57
    /**
58
     * Rows callable fucntion.
59
     *
60
     * @var \Closure
61
     */
62
    protected $rowsCallback;
63
64
    /**
65
     * All column names of the grid.
66
     *
67
     * @var array
68
     */
69
    public $columnNames = [];
70
71
    /**
72
     * Grid builder.
73
     *
74
     * @var \Closure
75
     */
76
    protected $builder;
77
78
    /**
79
     * Mark if the grid is builded.
80
     *
81
     * @var bool
82
     */
83
    protected $builded = false;
84
85
    /**
86
     * All variables in grid view.
87
     *
88
     * @var array
89
     */
90
    protected $variables = [];
91
92
    /**
93
     * The grid Filter.
94
     *
95
     * @var \Encore\Admin\Grid\Filter
96
     */
97
    protected $filter;
98
99
    /**
100
     * Resource path of the grid.
101
     *
102
     * @var
103
     */
104
    protected $resourcePath;
105
106
    /**
107
     * Default primary key name.
108
     *
109
     * @var string
110
     */
111
    protected $keyName = 'id';
112
113
    /**
114
     * Export driver.
115
     *
116
     * @var string
117
     */
118
    protected $exporter;
119
120
    /**
121
     * View for grid to render.
122
     *
123
     * @var string
124
     */
125
    protected $view = 'admin::grid.table';
126
127
    /**
128
     * Per-page options.
129
     *
130
     * @var array
131
     */
132
    public $perPages = [10, 20, 30, 50, 100];
133
134
    /**
135
     * Default items count per-page.
136
     *
137
     * @var int
138
     */
139
    public $perPage = 20;
140
141
    /**
142
     * Header tools.
143
     *
144
     * @var Tools
145
     */
146
    public $tools;
147
148
    /**
149
     * Callback for grid actions.
150
     *
151
     * @var Closure
152
     */
153
    protected $actionsCallback;
154
155
    /**
156
     * Options for grid.
157
     *
158
     * @var array
159
     */
160
    protected $options = [
161
        'usePagination'  => true,
162
        'useFilter'      => true,
163
        'useExporter'    => true,
164
        'useActions'     => true,
165
        'useRowSelector' => true,
166
        'allowCreate'    => true,
167
    ];
168
169
    /**
170
     * @var Tools\Footer
171
     */
172
    protected $footer;
173
174
    /**
175
     * Create a new grid instance.
176
     *
177
     * @param Eloquent $model
178
     * @param Closure  $builder
179
     */
180
    public function __construct(Eloquent $model, Closure $builder)
181
    {
182
        $this->keyName = $model->getKeyName();
183
        $this->model = new Model($model);
184
        $this->columns = new Collection();
185
        $this->rows = new Collection();
186
        $this->builder = $builder;
187
188
        $this->setupTools();
189
        $this->setupFilter();
190
        $this->setupExporter();
191
    }
192
193
    /**
194
     * Setup grid tools.
195
     */
196
    public function setupTools()
197
    {
198
        $this->tools = new Tools($this);
199
    }
200
201
    /**
202
     * Setup grid filter.
203
     *
204
     * @return void
205
     */
206
    protected function setupFilter()
207
    {
208
        $this->filter = new Filter($this->model());
209
    }
210
211
    /**
212
     * Setup grid exporter.
213
     *
214
     * @return void
215
     */
216
    protected function setupExporter()
217
    {
218
        if ($scope = Input::get(Exporter::$queryName)) {
219
            $this->model()->usePaginate(false);
220
221
            call_user_func($this->builder, $this);
222
223
            (new Exporter($this))->resolve($this->exporter)->withScope($scope)->export();
224
        }
225
    }
226
227
    /**
228
     * Get or set option for grid.
229
     *
230
     * @param string $key
231
     * @param mixed  $value
232
     *
233
     * @return $this|mixed
234
     */
235
    public function option($key, $value = null)
236
    {
237
        if (is_null($value)) {
238
            return $this->options[$key];
239
        }
240
241
        $this->options[$key] = $value;
242
243
        return $this;
244
    }
245
246
    /**
247
     * Get primary key name of model.
248
     *
249
     * @return string
250
     */
251
    public function getKeyName()
252
    {
253
        return $this->keyName ?: 'id';
254
    }
255
256
    /**
257
     * Add column to Grid.
258
     *
259
     * @param string $name
260
     * @param string $label
261
     *
262
     * @return Column
263
     */
264
    public function column($name, $label = '')
265
    {
266
        $relationName = $relationColumn = '';
267
268
        if (strpos($name, '.') !== false) {
269
            list($relationName, $relationColumn) = explode('.', $name);
270
271
            $relation = $this->model()->eloquent()->$relationName();
272
273
            $label = empty($label) ? ucfirst($relationColumn) : $label;
274
275
            $name = snake_case($relationName).'.'.$relationColumn;
276
        }
277
278
        $column = $this->addColumn($name, $label);
279
280
        if (isset($relation) && $relation instanceof Relation) {
281
            $this->model()->with($relationName);
0 ignored issues
show
Documentation Bug introduced by
The method with does not exist on object<Encore\Admin\Grid\Model>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
282
            $column->setRelation($relationName, $relationColumn);
283
        }
284
285
        return $column;
286
    }
287
288
    /**
289
     * Batch add column to grid.
290
     *
291
     * @example
292
     * 1.$grid->columns(['name' => 'Name', 'email' => 'Email' ...]);
293
     * 2.$grid->columns('name', 'email' ...)
294
     *
295
     * @param array $columns
296
     *
297
     * @return Collection|null
298
     */
299
    public function columns($columns = [])
300
    {
301
        if (func_num_args() == 0) {
302
            return $this->columns;
303
        }
304
305
        if (func_num_args() == 1 && is_array($columns)) {
306
            foreach ($columns as $column => $label) {
307
                $this->column($column, $label);
308
            }
309
310
            return;
311
        }
312
313
        foreach (func_get_args() as $column) {
314
            $this->column($column);
315
        }
316
    }
317
318
    /**
319
     * Add column to grid.
320
     *
321
     * @param string $column
322
     * @param string $label
323
     *
324
     * @return Column
325
     */
326
    protected function addColumn($column = '', $label = '')
327
    {
328
        $column = new Column($column, $label);
329
        $column->setGrid($this);
330
331
        return $this->columns[] = $column;
332
    }
333
334
    /**
335
     * Get Grid model.
336
     *
337
     * @return Model
338
     */
339
    public function model()
340
    {
341
        return $this->model;
342
    }
343
344
    /**
345
     * Paginate the grid.
346
     *
347
     * @param int $perPage
348
     *
349
     * @return void
350
     */
351
    public function paginate($perPage = 20)
352
    {
353
        $this->perPage = $perPage;
354
355
        $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...
356
    }
357
358
    /**
359
     * Get the grid paginator.
360
     *
361
     * @return mixed
362
     */
363
    public function paginator()
364
    {
365
        return new Tools\Paginator($this);
366
    }
367
368
    /**
369
     * Disable grid pagination.
370
     *
371
     * @return $this
372
     */
373
    public function disablePagination()
374
    {
375
        $this->model->usePaginate(false);
376
377
        $this->option('usePagination', false);
378
379
        return $this;
380
    }
381
382
    /**
383
     * If this grid use pagination.
384
     *
385
     * @return bool
386
     */
387
    public function usePagination()
388
    {
389
        return $this->option('usePagination');
390
    }
391
392
    /**
393
     * Set per-page options.
394
     *
395
     * @param array $perPages
396
     */
397
    public function perPages(array $perPages)
398
    {
399
        $this->perPages = $perPages;
400
    }
401
402
    /**
403
     * Disable all actions.
404
     *
405
     * @return $this
406
     */
407
    public function disableActions()
408
    {
409
        return $this->option('useActions', false);
410
    }
411
412
    /**
413
     * Set grid action callback.
414
     *
415
     * @param Closure $callback
416
     *
417
     * @return $this
418
     */
419
    public function actions(Closure $callback)
420
    {
421
        $this->actionsCallback = $callback;
422
423
        return $this;
424
    }
425
426
    /**
427
     * Add `actions` column for grid.
428
     *
429
     * @return void
430
     */
431
    protected function appendActionsColumn()
432
    {
433
        if (!$this->option('useActions')) {
434
            return;
435
        }
436
437
        $grid = $this;
438
        $callback = $this->actionsCallback;
439
        $column = $this->addColumn('__actions__', trans('admin.action'));
440
441
        $column->display(function ($value) use ($grid, $column, $callback) {
442
            $actions = new Actions($value, $grid, $column, $this);
0 ignored issues
show
Documentation introduced by
$this is of type this<Encore\Admin\Grid>, but the function expects a object<stdClass>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
443
444
            return $actions->display($callback);
445
        });
446
    }
447
448
    /**
449
     * Disable row selector.
450
     *
451
     * @return Grid|mixed
452
     */
453
    public function disableRowSelector()
454
    {
455
        $this->tools(function ($tools) {
456
            /* @var Grid\Tools $tools */
457
            $tools->disableBatchActions();
458
        });
459
460
        return $this->option('useRowSelector', false);
461
    }
462
463
    /**
464
     * Prepend checkbox column for grid.
465
     *
466
     * @return void
467
     */
468
    protected function prependRowSelectorColumn()
469
    {
470
        if (!$this->option('useRowSelector')) {
471
            return;
472
        }
473
474
        $grid = $this;
475
476
        $column = new Column(Column::SELECT_COLUMN_NAME, ' ');
477
        $column->setGrid($this);
478
479
        $column->display(function ($value) use ($grid, $column) {
480
            $actions = new RowSelector($value, $grid, $column, $this);
0 ignored issues
show
Documentation introduced by
$this is of type this<Encore\Admin\Grid>, but the function expects a object<stdClass>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
481
482
            return $actions->display();
483
        });
484
485
        $this->columns->prepend($column);
486
    }
487
488
    /**
489
     * Build the grid.
490
     *
491
     * @return void
492
     */
493
    public function build()
494
    {
495
        if ($this->builded) {
496
            return;
497
        }
498
499
        $data = $this->processFilter();
500
501
        $this->prependRowSelectorColumn();
502
        $this->appendActionsColumn();
503
504
        Column::setOriginalGridData($data);
505
506
        $this->columns->map(function (Column $column) use (&$data) {
507
            $data = $column->fill($data);
508
509
            $this->columnNames[] = $column->getName();
510
        });
511
512
        $this->buildRows($data);
513
514
        $this->builded = true;
515
    }
516
517
    /**
518
     * Disable grid filter.
519
     *
520
     * @return $this
521
     */
522
    public function disableFilter()
523
    {
524
        $this->option('useFilter', false);
525
526
        return $this;
527
    }
528
529
    /**
530
     * Get filter of Grid.
531
     *
532
     * @return Filter
533
     */
534
    public function getFilter()
535
    {
536
        return $this->filter;
537
    }
538
539
    /**
540
     * Process the grid filter.
541
     *
542
     * @return array
543
     */
544
    public function processFilter()
545
    {
546
        call_user_func($this->builder, $this);
547
548
        return $this->filter->execute();
549
    }
550
551
    /**
552
     * Set the grid filter.
553
     *
554
     * @param Closure $callback
555
     */
556
    public function filter(Closure $callback)
557
    {
558
        call_user_func($callback, $this->filter);
559
    }
560
561
    /**
562
     * Render the grid filter.
563
     *
564
     * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View|string
565
     */
566
    public function renderFilter()
567
    {
568
        if (!$this->option('useFilter')) {
569
            return '';
570
        }
571
572
        return $this->filter->render();
573
    }
574
575
    /**
576
     * Build the grid rows.
577
     *
578
     * @param array $data
579
     *
580
     * @return void
581
     */
582
    protected function buildRows(array $data)
583
    {
584
        $this->rows = collect($data)->map(function ($model, $number) {
585
            return new Row($number, $model);
586
        });
587
588
        if ($this->rowsCallback) {
589
            $this->rows->map($this->rowsCallback);
590
        }
591
    }
592
593
    /**
594
     * Set grid row callback function.
595
     *
596
     * @param Closure $callable
597
     *
598
     * @return Collection|null
599
     */
600
    public function rows(Closure $callable = null)
601
    {
602
        if (is_null($callable)) {
603
            return $this->rows;
604
        }
605
606
        $this->rowsCallback = $callable;
607
    }
608
609
    /**
610
     * Setup grid tools.
611
     *
612
     * @param Closure $callback
613
     *
614
     * @return void
615
     */
616
    public function tools(Closure $callback)
617
    {
618
        call_user_func($callback, $this->tools);
619
    }
620
621
    /**
622
     * Render custom tools.
623
     *
624
     * @return string
625
     */
626
    public function renderHeaderTools()
627
    {
628
        return $this->tools->render();
629
    }
630
631
    /**
632
     * Set exporter driver for Grid to export.
633
     *
634
     * @param $exporter
635
     *
636
     * @return $this
637
     */
638
    public function exporter($exporter)
639
    {
640
        $this->exporter = $exporter;
641
642
        return $this;
643
    }
644
645
    /**
646
     * Get the export url.
647
     *
648
     * @param int  $scope
649
     * @param null $args
650
     *
651
     * @return string
652
     */
653
    public function exportUrl($scope = 1, $args = null)
654
    {
655
        $input = array_merge(Input::all(), Exporter::formatExportQuery($scope, $args));
656
657
        return url($this->resource().'?'.http_build_query($input));
658
    }
659
660
    /**
661
     * If grid allows export.s.
662
     *
663
     * @return bool
664
     */
665
    public function allowExport()
666
    {
667
        return $this->option('useExporter');
668
    }
669
670
    /**
671
     * Disable export.
672
     *
673
     * @return $this
674
     */
675
    public function disableExport()
676
    {
677
        return $this->option('useExporter', false);
678
    }
679
680
    /**
681
     * Render export button.
682
     *
683
     * @return Tools\ExportButton
684
     */
685
    public function renderExportButton()
686
    {
687
        return new Tools\ExportButton($this);
688
    }
689
690
    /**
691
     * Alias for method `disableCreateButton`.
692
     *
693
     * @return $this
694
     *
695
     * @deprecated
696
     */
697
    public function disableCreation()
698
    {
699
        return $this->disableCreateButton();
700
    }
701
702
    /**
703
     * Remove create button on grid.
704
     *
705
     * @return $this
706
     */
707
    public function disableCreateButton()
708
    {
709
        return $this->option('allowCreate', false);
710
    }
711
712
    /**
713
     * If allow creation.
714
     *
715
     * @return bool
716
     */
717
    public function allowCreation()
718
    {
719
        return $this->option('allowCreate');
720
    }
721
722
    /**
723
     * Render create button for grid.
724
     *
725
     * @return Tools\CreateButton
726
     */
727
    public function renderCreateButton()
728
    {
729
        return new Tools\CreateButton($this);
730
    }
731
732
    /**
733
     * Set grid footer.
734
     *
735
     * @param Closure|null $closure
736
     *
737
     * @return $this|Tools\Footer
738
     */
739
    public function footer(Closure $closure = null)
740
    {
741
        if (!$closure) {
742
            return $this->footer;
743
        }
744
745
        $this->footer = $closure;
0 ignored issues
show
Documentation Bug introduced by
It seems like $closure of type object<Closure> is incompatible with the declared type object<Encore\Admin\Grid\Tools\Footer> of property $footer.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
746
747
        return $this;
748
    }
749
750
    /**
751
     * Render grid footer.
752
     *
753
     * @return Tools\Footer|string
754
     */
755
    public function renderFooter()
756
    {
757
        if (!$this->footer) {
758
            return '';
759
        }
760
761
        return new Tools\Footer($this);
762
    }
763
764
    /**
765
     * Get current resource uri.
766
     *
767
     * @param string $path
768
     *
769
     * @return string
770
     */
771
    public function resource($path = null)
772
    {
773
        if (!empty($path)) {
774
            $this->resourcePath = $path;
775
776
            return $this;
777
        }
778
779
        if (!empty($this->resourcePath)) {
780
            return $this->resourcePath;
781
        }
782
783
        return app('request')->getPathInfo();
784
    }
785
786
    /**
787
     * Get the table columns for grid.
788
     *
789
     * @return void
790
     */
791
    protected function setDbColumns()
792
    {
793
        $connection = $this->model()->eloquent()->getConnectionName();
794
795
        $this->dbColumns = collect(Schema::connection($connection)->getColumnListing($this->model()->getTable()));
796
    }
797
798
    /**
799
     * Handle table column for grid.
800
     *
801
     * @param string $method
802
     * @param string $label
803
     *
804
     * @return bool|Column
805
     */
806
    protected function handleTableColumn($method, $label)
807
    {
808
        if (empty($this->dbColumns)) {
809
            $this->setDbColumns();
810
        }
811
812
        if ($this->dbColumns->has($method)) {
813
            return $this->addColumn($method, $label);
814
        }
815
816
        return false;
817
    }
818
819
    /**
820
     * Handle get mutator column for grid.
821
     *
822
     * @param string $method
823
     * @param string $label
824
     *
825
     * @return bool|Column
826
     */
827
    protected function handleGetMutatorColumn($method, $label)
828
    {
829
        if ($this->model()->eloquent()->hasGetMutator($method)) {
830
            return $this->addColumn($method, $label);
831
        }
832
833
        return false;
834
    }
835
836
    /**
837
     * Handle relation column for grid.
838
     *
839
     * @param string $method
840
     * @param string $label
841
     *
842
     * @return bool|Column
843
     */
844
    protected function handleRelationColumn($method, $label)
845
    {
846
        $model = $this->model()->eloquent();
847
848
        if (!method_exists($model, $method)) {
849
            return false;
850
        }
851
852
        if (!($relation = $model->$method()) instanceof Relation) {
853
            return false;
854
        }
855
856
        if ($relation instanceof HasOne || $relation instanceof BelongsTo) {
857
            $this->model()->with($method);
0 ignored issues
show
Documentation Bug introduced by
The method with does not exist on object<Encore\Admin\Grid\Model>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
858
859
            return $this->addColumn($method, $label)->setRelation(snake_case($method));
860
        }
861
862
        if ($relation instanceof HasMany || $relation instanceof BelongsToMany || $relation instanceof MorphToMany) {
863
            $this->model()->with($method);
0 ignored issues
show
Documentation Bug introduced by
The method with does not exist on object<Encore\Admin\Grid\Model>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
864
865
            return $this->addColumn(snake_case($method), $label);
866
        }
867
868
        return false;
869
    }
870
871
    /**
872
     * Dynamically add columns to the grid view.
873
     *
874
     * @param $method
875
     * @param $arguments
876
     *
877
     * @return Column
878
     */
879
    public function __call($method, $arguments)
880
    {
881
        $label = isset($arguments[0]) ? $arguments[0] : ucfirst($method);
882
883
        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...
884
            return $this->addColumn($method, $label);
885
        }
886
887
        if ($column = $this->handleGetMutatorColumn($method, $label)) {
888
            return $column;
889
        }
890
891
        if ($column = $this->handleRelationColumn($method, $label)) {
892
            return $column;
893
        }
894
895
        if ($column = $this->handleTableColumn($method, $label)) {
896
            return $column;
897
        }
898
899
        return $this->addColumn($method, $label);
900
    }
901
902
    /**
903
     * Register column displayers.
904
     *
905
     * @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...
906
     */
907
    public static function registerColumnDisplayer()
908
    {
909
        $map = [
910
            'editable'    => \Encore\Admin\Grid\Displayers\Editable::class,
911
            'switch'      => \Encore\Admin\Grid\Displayers\SwitchDisplay::class,
912
            'switchGroup' => \Encore\Admin\Grid\Displayers\SwitchGroup::class,
913
            'select'      => \Encore\Admin\Grid\Displayers\Select::class,
914
            'image'       => \Encore\Admin\Grid\Displayers\Image::class,
915
            'label'       => \Encore\Admin\Grid\Displayers\Label::class,
916
            'button'      => \Encore\Admin\Grid\Displayers\Button::class,
917
            'link'        => \Encore\Admin\Grid\Displayers\Link::class,
918
            'badge'       => \Encore\Admin\Grid\Displayers\Badge::class,
919
            'progressBar' => \Encore\Admin\Grid\Displayers\ProgressBar::class,
920
            'radio'       => \Encore\Admin\Grid\Displayers\Radio::class,
921
            'checkbox'    => \Encore\Admin\Grid\Displayers\Checkbox::class,
922
            'orderable'   => \Encore\Admin\Grid\Displayers\Orderable::class,
923
        ];
924
925
        foreach ($map as $abstract => $class) {
926
            Column::extend($abstract, $class);
927
        }
928
    }
929
930
    /**
931
     * Add variables to grid view.
932
     *
933
     * @param array $variables
934
     *
935
     * @return $this
936
     */
937
    public function with($variables = [])
938
    {
939
        $this->variables = $variables;
940
941
        return $this;
942
    }
943
944
    /**
945
     * Get all variables will used in grid view.
946
     *
947
     * @return array
948
     */
949
    protected function variables()
950
    {
951
        $this->variables['grid'] = $this;
952
953
        return $this->variables;
954
    }
955
956
    /**
957
     * Set a view to render.
958
     *
959
     * @param string $view
960
     * @param array  $variables
961
     */
962
    public function setView($view, $variables = [])
963
    {
964
        if (!empty($variables)) {
965
            $this->with($variables);
966
        }
967
968
        $this->view = $view;
969
    }
970
971
    /**
972
     * Get the string contents of the grid view.
973
     *
974
     * @return string
975
     */
976
    public function render()
977
    {
978
        try {
979
            $this->build();
980
        } catch (\Exception $e) {
981
            return Handler::renderException($e);
982
        }
983
984
        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...
985
    }
986
987
    /**
988
     * Get the string contents of the grid view.
989
     *
990
     * @return string
991
     */
992
    public function __toString()
993
    {
994
        return $this->render();
995
    }
996
}
997