Completed
Push — master ( 89214f...54cb04 )
by Song
03:18 queued 10s
created

Grid::selectColumns()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 1
dl 0
loc 5
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\Concerns;
9
use Encore\Admin\Grid\Displayers;
10
use Encore\Admin\Grid\Exporter;
11
use Encore\Admin\Grid\Exporters\AbstractExporter;
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;
17
use Illuminate\Support\Collection;
18
use Illuminate\Support\Facades\Input;
19
use Illuminate\Support\Str;
20
use Jenssegers\Mongodb\Eloquent\Model as MongodbModel;
21
22
class Grid
23
{
24
    use Concerns\HasElementNames,
25
        Concerns\HasHeader,
26
        Concerns\HasFooter,
27
        Concerns\HasFilter,
28
        Concerns\HasTools,
29
        Concerns\HasTotalRow;
30
31
    /**
32
     * The grid data model instance.
33
     *
34
     * @var \Encore\Admin\Grid\Model
35
     */
36
    protected $model;
37
38
    /**
39
     * Collection of all grid columns.
40
     *
41
     * @var \Illuminate\Support\Collection
42
     */
43
    protected $columns;
44
45
    /**
46
     * Collection of all data rows.
47
     *
48
     * @var \Illuminate\Support\Collection
49
     */
50
    protected $rows;
51
52
    /**
53
     * Rows callable fucntion.
54
     *
55
     * @var \Closure
56
     */
57
    protected $rowsCallback;
58
59
    /**
60
     * All column names of the grid.
61
     *
62
     * @var array
63
     */
64
    public $columnNames = [];
65
66
    /**
67
     * Default columns be shown
68
     *
69
     * @var array
70
     */
71
    public $columnShownNames = [];
72
73
    /**
74
     * Grid builder.
75
     *
76
     * @var \Closure
77
     */
78
    protected $builder;
79
80
    /**
81
     * Mark if the grid is builded.
82
     *
83
     * @var bool
84
     */
85
    protected $builded = false;
86
87
    /**
88
     * All variables in grid view.
89
     *
90
     * @var array
91
     */
92
    protected $variables = [];
93
94
    /**
95
     * Resource path of the grid.
96
     *
97
     * @var
98
     */
99
    protected $resourcePath;
100
101
    /**
102
     * Default primary key name.
103
     *
104
     * @var string
105
     */
106
    protected $keyName = 'id';
107
108
    /**
109
     * Export driver.
110
     *
111
     * @var string
112
     */
113
    protected $exporter;
114
115
    /**
116
     * View for grid to render.
117
     *
118
     * @var string
119
     */
120
    protected $view = 'admin::grid.table';
121
122
    /**
123
     * Per-page options.
124
     *
125
     * @var array
126
     */
127
    public $perPages = [10, 20, 30, 50, 100];
128
129
    /**
130
     * Default items count per-page.
131
     *
132
     * @var int
133
     */
134
    public $perPage = 20;
135
136
    /**
137
     * Callback for grid actions.
138
     *
139
     * @var Closure
140
     */
141
    protected $actionsCallback;
142
143
    /**
144
     * Actions column display class.
145
     *
146
     * @var string
147
     */
148
    protected $actionsClass = Displayers\Actions::class;
149
150
    /**
151
     * Options for grid.
152
     *
153
     * @var array
154
     */
155
    protected $options = [
156
        'show_pagination'        => true,
157
        'show_tools'             => true,
158
        'show_filter'            => true,
159
        'show_exporter'          => true,
160
        'show_actions'           => true,
161
        'show_row_selector'      => true,
162
        'show_create_btn'        => true,
163
        'show_column_selector'   => true,
164
    ];
165
166
    /**
167
     * @var string
168
     */
169
    public $tableID;
170
171
    /**
172
     * Initialization closure array.
173
     *
174
     * @var []Closure
175
     */
176
    protected static $initCallbacks = [];
177
178
    /**
179
     * Create a new grid instance.
180
     *
181
     * @param Eloquent $model
182
     * @param Closure  $builder
183
     */
184
    public function __construct(Eloquent $model, Closure $builder = null)
185
    {
186
        $this->keyName = $model->getKeyName();
187
        $this->model = new Model($model);
188
        $this->columns = new Collection();
189
        $this->rows = new Collection();
190
        $this->builder = $builder;
191
        $this->tableID = uniqid('grid-table');
192
193
        $this->model()->setGrid($this);
194
195
        $this->setupTools();
196
        $this->setupFilter();
197
198
        $this->handleExportRequest();
199
200
        $this->callInitCallbacks();
201
    }
202
203
    /**
204
     * Initialize with user pre-defined default disables and exporter, etc.
205
     *
206
     * @param Closure $callback
207
     */
208
    public static function init(Closure $callback = null)
209
    {
210
        static::$initCallbacks[] = $callback;
211
    }
212
213
    /**
214
     * Call the initialization closure array in sequence.
215
     */
216
    protected function callInitCallbacks()
217
    {
218
        if (empty(static::$initCallbacks)) {
219
            return;
220
        }
221
222
        foreach (static::$initCallbacks as $callback) {
223
            call_user_func($callback, $this);
224
        }
225
    }
226
227
    /**
228
     * Handle export request.
229
     *
230
     * @param bool $forceExport
231
     */
232
    protected function handleExportRequest($forceExport = false)
233
    {
234
        if (!$scope = request(Exporter::$queryName)) {
235
            return;
236
        }
237
238
        // clear output buffer.
239
        if (ob_get_length()) {
240
            ob_end_clean();
241
        }
242
243
        $this->model()->usePaginate(false);
244
245
        if ($this->builder) {
246
            call_user_func($this->builder, $this);
247
248
            $this->getExporter($scope)->export();
249
        }
250
251
        if ($forceExport) {
252
            $this->getExporter($scope)->export();
253
        }
254
    }
255
256
    /**
257
     * @param string $scope
258
     *
259
     * @return AbstractExporter
260
     */
261
    protected function getExporter($scope)
262
    {
263
        return (new Exporter($this))->resolve($this->exporter)->withScope($scope);
264
    }
265
266
    /**
267
     * Get or set option for grid.
268
     *
269
     * @param string $key
270
     * @param mixed  $value
271
     *
272
     * @return $this|mixed
273
     */
274
    public function option($key, $value = null)
275
    {
276
        if (is_null($value)) {
277
            return $this->options[$key];
278
        }
279
280
        $this->options[$key] = $value;
281
282
        return $this;
283
    }
284
285
    /**
286
     * Get primary key name of model.
287
     *
288
     * @return string
289
     */
290
    public function getKeyName()
291
    {
292
        return $this->keyName ?: 'id';
293
    }
294
295
    /**
296
     * Add a column to Grid.
297
     *
298
     * @param string $name
299
     * @param string $label
300
     *
301
     * @return Column
302
     */
303
    public function column($name, $label = '')
304
    {
305
        if (Str::contains($name, '.')) {
306
            return $this->addRelationColumn($name, $label);
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->addRelationColumn($name, $label); of type Encore\Admin\Grid|Encore\Admin\Grid\Column adds the type Encore\Admin\Grid to the return on line 306 which is incompatible with the return type documented by Encore\Admin\Grid::column of type Encore\Admin\Grid\Column.
Loading history...
307
        }
308
309
        if (Str::contains($name, '->')) {
310
            return $this->addJsonColumn($name, $label);
311
        }
312
313
        return $this->__call($name, [$label]);
314
    }
315
316
    /**
317
     * Batch add column to grid.
318
     *
319
     * @example
320
     * 1.$grid->columns(['name' => 'Name', 'email' => 'Email' ...]);
321
     * 2.$grid->columns('name', 'email' ...)
322
     *
323
     * @param array $columns
324
     *
325
     * @return Collection|null
326
     */
327
    public function columns($columns = [])
328
    {
329
        if (func_num_args() == 0) {
330
            return $this->columns;
331
        }
332
333
        if (func_num_args() == 1 && is_array($columns)) {
334
            foreach ($columns as $column => $label) {
335
                $this->column($column, $label);
336
            }
337
338
            return;
339
        }
340
341
        foreach (func_get_args() as $column) {
342
            $this->column($column);
343
        }
344
    }
345
346
    /**
347
     * Get all visible column instances.
348
     *
349
     * @return Collection|static
350
     */
351 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...
352
    {
353
        $querySelections = array_filter(explode(',', request(Tools\ColumnSelector::SELECT_COLUMN_NAME)));
354
        if ( count($querySelections) > 0) {
355
            $visible = $querySelections;
356
        } else {
357
            $visible = $this->columnShownNames;
358
        }
359
360
        if (empty($visible)) {
361
            return $this->columns;
362
        }
363
364
        array_push($visible, '__row_selector__', '__actions__');
365
366
        return $this->columns->filter(function (Column $column) use ($visible) {
367
            return in_array($column->getName(), $visible);
368
        });
369
    }
370
371
    /**
372
     * Get all visible column names.
373
     *
374
     * @return array|static
375
     */
376 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...
377
    {
378
        $querySelections = array_filter(explode(',', request(Tools\ColumnSelector::SELECT_COLUMN_NAME)));
379
        if ( count($querySelections) > 0) {
380
            $visible = $querySelections;
381
        } else {
382
            $visible = $this->columnShownNames;
383
        }
384
385
        if (empty($visible)) {
386
            return $this->columnNames;
387
        }
388
389
        array_push($visible, '__row_selector__', '__actions__');
390
391
        return collect($this->columnNames)->filter(function ($column) use ($visible) {
392
            return in_array($column, $visible);
393
        });
394
    }
395
396
    /**
397
     * Add column to grid.
398
     *
399
     * @param string $column
400
     * @param string $label
401
     *
402
     * @return Column
403
     */
404 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...
405
    {
406
        $column = new Column($column, $label);
407
        $column->setGrid($this);
408
409
        return tap($column, function ($value) {
410
            $this->columns->push($value);
411
        });
412
    }
413
414
    /**
415
     * Add a relation column to grid.
416
     *
417
     * @param string $name
418
     * @param string $label
419
     *
420
     * @return $this|bool|Column
421
     */
422
    protected function addRelationColumn($name, $label = '')
423
    {
424
        list($relation, $column) = explode('.', $name);
425
426
        $model = $this->model()->eloquent();
427
428
        if (!method_exists($model, $relation) || !$model->{$relation}() instanceof Relations\Relation) {
429
            $class = get_class($model);
430
431
            admin_error("Call to undefined relationship [{$relation}] on model [{$class}].");
432
433
            return $this;
434
        }
435
436
        $name = Str::snake($relation).'.'.$column;
437
438
        $this->model()->with($relation);
439
440
        return $this->addColumn($name, $label ?: ucfirst($column))->setRelation($relation, $column);
441
    }
442
443
    /**
444
     * Add a json type column to grid.
445
     *
446
     * @param string $name
447
     * @param string $label
448
     *
449
     * @return Column
450
     */
451
    protected function addJsonColumn($name, $label = '')
452
    {
453
        $column = substr($name, strrpos($name, '->') + 2);
454
455
        $name = str_replace('->', '.', $name);
456
457
        return $this->addColumn($name, $label ?: ucfirst($column));
458
    }
459
460
    /**
461
     * Prepend column to grid.
462
     *
463
     * @param string $column
464
     * @param string $label
465
     *
466
     * @return Column
467
     */
468 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...
469
    {
470
        $column = new Column($column, $label);
471
        $column->setGrid($this);
472
473
        return tap($column, function ($value) {
474
            $this->columns->prepend($value);
475
        });
476
    }
477
478
    /**
479
     * Get Grid model.
480
     *
481
     * @return Model
482
     */
483
    public function model()
484
    {
485
        return $this->model;
486
    }
487
488
    /**
489
     * Paginate the grid.
490
     *
491
     * @param int $perPage
492
     *
493
     * @return void
494
     */
495
    public function paginate($perPage = 20)
496
    {
497
        $this->perPage = $perPage;
498
499
        $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...
500
    }
501
502
    /**
503
     * Get the grid paginator.
504
     *
505
     * @return mixed
506
     */
507
    public function paginator()
508
    {
509
        return new Tools\Paginator($this);
510
    }
511
512
    /**
513
     * Disable grid pagination.
514
     *
515
     * @return $this
516
     */
517
    public function disablePagination(bool $disable = true)
518
    {
519
        $this->model->usePaginate(!$disable);
520
521
        return $this->option('show_pagination', !$disable);
522
    }
523
524
    /**
525
     * If this grid use pagination.
526
     *
527
     * @return bool
528
     */
529
    public function showPagination()
530
    {
531
        return $this->option('show_pagination');
532
    }
533
534
    /**
535
     * Set per-page options.
536
     *
537
     * @param array $perPages
538
     */
539
    public function perPages(array $perPages)
540
    {
541
        $this->perPages = $perPages;
542
    }
543
544
    /**
545
     * Disable all actions.
546
     *
547
     * @return $this
548
     */
549
    public function disableActions(bool $disable = true)
550
    {
551
        return $this->option('show_actions', !$disable);
552
    }
553
554
    /**
555
     * Set grid action callback.
556
     *
557
     * @param Closure|string $actions
558
     *
559
     * @return $this
560
     */
561
    public function actions($actions)
562
    {
563
        if ($actions instanceof Closure) {
564
            $this->actionsCallback = $actions;
565
        }
566
567
        if (is_string($actions) && is_subclass_of($actions, Displayers\Actions::class)) {
0 ignored issues
show
Bug introduced by
Due to PHP Bug #53727, is_subclass_of might return inconsistent results on some PHP versions if \Encore\Admin\Grid\Displayers\Actions::class can be an interface. If so, you could instead use ReflectionClass::implementsInterface.
Loading history...
568
            $this->actionsClass = $actions;
569
        }
570
571
        return $this;
572
    }
573
574
    /**
575
     * Add `actions` column for grid.
576
     *
577
     * @return void
578
     */
579
    protected function appendActionsColumn()
580
    {
581
        if (!$this->option('show_actions')) {
582
            return;
583
        }
584
585
        $this->addColumn('__actions__', trans('admin.action'))
586
            ->displayUsing($this->actionsClass, [$this->actionsCallback]);
587
    }
588
589
    /**
590
     * Disable row selector.
591
     *
592
     * @return Grid|mixed
593
     */
594
    public function disableRowSelector(bool $disable = true)
595
    {
596
        $this->tools->disableBatchActions($disable);
597
598
        return $this->option('show_row_selector', !$disable);
599
    }
600
601
    /**
602
     * Prepend checkbox column for grid.
603
     *
604
     * @return void
605
     */
606
    protected function prependRowSelectorColumn()
607
    {
608
        if (!$this->option('show_row_selector')) {
609
            return;
610
        }
611
612
        $this->prependColumn(Column::SELECT_COLUMN_NAME, ' ')
613
            ->displayUsing(Displayers\RowSelector::class);
614
    }
615
616
    /**
617
     * Build the grid.
618
     *
619
     * @return void
620
     */
621
    public function build()
622
    {
623
        if ($this->builded) {
624
            return;
625
        }
626
627
        $collection = $this->processFilter(false);
628
629
        $data = $collection->toArray();
630
631
        $this->prependRowSelectorColumn();
632
        $this->appendActionsColumn();
633
634
        Column::setOriginalGridModels($collection);
635
636
        $this->columns->map(function (Column $column) use (&$data) {
637
            $data = $column->fill($data);
638
639
            $this->columnNames[] = $column->getName();
640
        });
641
642
        $this->buildRows($data);
643
644
        $this->builded = true;
645
    }
646
647
    /**
648
     * Build the grid rows.
649
     *
650
     * @param array $data
651
     *
652
     * @return void
653
     */
654
    protected function buildRows(array $data)
655
    {
656
        $this->rows = collect($data)->map(function ($model, $number) {
657
            return new Row($number, $model);
658
        });
659
660
        if ($this->rowsCallback) {
661
            $this->rows->map($this->rowsCallback);
662
        }
663
    }
664
665
    /**
666
     * Set grid row callback function.
667
     *
668
     * @param Closure $callable
669
     *
670
     * @return Collection|null
671
     */
672
    public function rows(Closure $callable = null)
673
    {
674
        if (is_null($callable)) {
675
            return $this->rows;
676
        }
677
678
        $this->rowsCallback = $callable;
679
    }
680
681
    /**
682
     * Set exporter driver for Grid to export.
683
     *
684
     * @param $exporter
685
     *
686
     * @return $this
687
     */
688
    public function exporter($exporter)
689
    {
690
        $this->exporter = $exporter;
691
692
        return $this;
693
    }
694
695
    /**
696
     * Get the export url.
697
     *
698
     * @param int  $scope
699
     * @param null $args
700
     *
701
     * @return string
702
     */
703
    public function getExportUrl($scope = 1, $args = null)
704
    {
705
        $input = array_merge(Input::all(), Exporter::formatExportQuery($scope, $args));
706
707
        if ($constraints = $this->model()->getConstraints()) {
708
            $input = array_merge($input, $constraints);
709
        }
710
711
        return $this->resource().'?'.http_build_query($input);
712
    }
713
714
    /**
715
     * Get create url.
716
     *
717
     * @return string
718
     */
719
    public function getCreateUrl()
720
    {
721
        $queryString = '';
722
723
        if ($constraints = $this->model()->getConstraints()) {
724
            $queryString = http_build_query($constraints);
725
        }
726
727
        return sprintf('%s/create%s',
728
            $this->resource(),
729
            $queryString ? ('?'.$queryString) : ''
730
        );
731
    }
732
733
    /**
734
     * If grid show export btn.
735
     *
736
     * @return bool
737
     */
738
    public function showExportBtn()
739
    {
740
        return $this->option('show_exporter');
741
    }
742
743
    /**
744
     * Disable export.
745
     *
746
     * @return $this
747
     */
748
    public function disableExport(bool $disable = true)
749
    {
750
        return $this->option('show_exporter', !$disable);
751
    }
752
753
    /**
754
     * Render export button.
755
     *
756
     * @return string
757
     */
758
    public function renderExportButton()
759
    {
760
        return (new Tools\ExportButton($this))->render();
761
    }
762
763
    /**
764
     * Alias for method `disableCreateButton`.
765
     *
766
     * @return $this
767
     *
768
     * @deprecated
769
     */
770
    public function disableCreation()
771
    {
772
        return $this->disableCreateButton();
773
    }
774
775
    /**
776
     * Remove create button on grid.
777
     *
778
     * @return $this
779
     */
780
    public function disableCreateButton(bool $disable = true)
781
    {
782
        return $this->option('show_create_btn', !$disable);
783
    }
784
785
    /**
786
     * If allow creation.
787
     *
788
     * @return bool
789
     */
790
    public function showCreateBtn()
791
    {
792
        return $this->option('show_create_btn');
793
    }
794
795
    /**
796
     * Render create button for grid.
797
     *
798
     * @return string
799
     */
800
    public function renderCreateButton()
801
    {
802
        return (new Tools\CreateButton($this))->render();
803
    }
804
805
    /**
806
     * Remove column selector on grid.
807
     *
808
     * @param bool $disable
809
     *
810
     * @return Grid|mixed
811
     */
812
    public function disableColumnSelector(bool $disable = true)
813
    {
814
        return $this->option('show_column_selector', !$disable);
815
    }
816
817
    /**
818
     * @return bool
819
     */
820
    public function showColumnSelector()
821
    {
822
        return $this->option('show_column_selector');
823
    }
824
825
    /**
826
     * @return string
827
     */
828
    public function renderColumnSelector()
829
    {
830
        $columnSelector = new Grid\Tools\ColumnSelector($this);
831
        $columnSelector->columnShownNames = $this->columnShownNames;
832
        return $columnSelector->render();
833
    }
834
835
    /**
836
     * Setting default shown columns on grid.
837
     *
838
     * @param array $columns
839
     * @return array
840
     */
841
    public function selectColumns($columns = [])
842
    {
843
        $this->columnShownNames = $columns;
844
        return $this->columnShownNames;
845
    }
846
847
    /**
848
     * Get current resource uri.
849
     *
850
     * @param string $path
851
     *
852
     * @return string
853
     */
854
    public function resource($path = null)
855
    {
856
        if (!empty($path)) {
857
            $this->resourcePath = $path;
858
859
            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...
860
        }
861
862
        if (!empty($this->resourcePath)) {
863
            return $this->resourcePath;
864
        }
865
866
        return app('request')->getPathInfo();
867
    }
868
869
    /**
870
     * Handle get mutator column for grid.
871
     *
872
     * @param string $method
873
     * @param string $label
874
     *
875
     * @return bool|Column
876
     */
877
    protected function handleGetMutatorColumn($method, $label)
878
    {
879
        if ($this->model()->eloquent()->hasGetMutator($method)) {
880
            return $this->addColumn($method, $label);
881
        }
882
883
        return false;
884
    }
885
886
    /**
887
     * Handle relation column for grid.
888
     *
889
     * @param string $method
890
     * @param string $label
891
     *
892
     * @return bool|Column
893
     */
894
    protected function handleRelationColumn($method, $label)
895
    {
896
        $model = $this->model()->eloquent();
897
898
        if (!method_exists($model, $method)) {
899
            return false;
900
        }
901
902
        if (!($relation = $model->$method()) instanceof Relations\Relation) {
903
            return false;
904
        }
905
906
        if ($relation instanceof Relations\HasOne ||
907
            $relation instanceof Relations\BelongsTo ||
908
            $relation instanceof Relations\MorphOne
909
        ) {
910
            $this->model()->with($method);
911
912
            return $this->addColumn($method, $label)->setRelation(Str::snake($method));
913
        }
914
915
        if ($relation instanceof Relations\HasMany
916
            || $relation instanceof Relations\BelongsToMany
917
            || $relation instanceof Relations\MorphToMany
918
            || $relation instanceof Relations\HasManyThrough
919
        ) {
920
            $this->model()->with($method);
921
922
            return $this->addColumn(Str::snake($method), $label);
923
        }
924
925
        return false;
926
    }
927
928
    /**
929
     * Dynamically add columns to the grid view.
930
     *
931
     * @param $method
932
     * @param $arguments
933
     *
934
     * @return Column
935
     */
936
    public function __call($method, $arguments)
937
    {
938
        $label = isset($arguments[0]) ? $arguments[0] : ucfirst($method);
939
940
        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...
941
            return $this->addColumn($method, $label);
942
        }
943
944
        if ($column = $this->handleGetMutatorColumn($method, $label)) {
945
            return $column;
946
        }
947
948
        if ($column = $this->handleRelationColumn($method, $label)) {
949
            return $column;
950
        }
951
952
        return $this->addColumn($method, $label);
953
    }
954
955
    /**
956
     * Register column displayers.
957
     *
958
     * @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...
959
     */
960
    public static function registerColumnDisplayer()
961
    {
962
        $map = [
963
            'editable'    => Displayers\Editable::class,
964
            'switch'      => Displayers\SwitchDisplay::class,
965
            'switchGroup' => Displayers\SwitchGroup::class,
966
            'select'      => Displayers\Select::class,
967
            'image'       => Displayers\Image::class,
968
            'label'       => Displayers\Label::class,
969
            'button'      => Displayers\Button::class,
970
            'link'        => Displayers\Link::class,
971
            'badge'       => Displayers\Badge::class,
972
            'progressBar' => Displayers\ProgressBar::class,
973
            'radio'       => Displayers\Radio::class,
974
            'checkbox'    => Displayers\Checkbox::class,
975
            'orderable'   => Displayers\Orderable::class,
976
            'table'       => Displayers\Table::class,
977
            'expand'      => Displayers\Expand::class,
978
            'modal'       => Displayers\Modal::class,
979
            'gravatar'    => Displayers\Gravatar::class,
980
            'carousel'    => Displayers\Carousel::class,
981
        ];
982
983
        foreach ($map as $abstract => $class) {
984
            Column::extend($abstract, $class);
985
        }
986
    }
987
988
    /**
989
     * Add variables to grid view.
990
     *
991
     * @param array $variables
992
     *
993
     * @return $this
994
     */
995
    public function with($variables = [])
996
    {
997
        $this->variables = $variables;
998
999
        return $this;
1000
    }
1001
1002
    /**
1003
     * Get all variables will used in grid view.
1004
     *
1005
     * @return array
1006
     */
1007
    protected function variables()
1008
    {
1009
        $this->variables['grid'] = $this;
1010
1011
        return $this->variables;
1012
    }
1013
1014
    /**
1015
     * Set a view to render.
1016
     *
1017
     * @param string $view
1018
     * @param array  $variables
1019
     */
1020
    public function setView($view, $variables = [])
1021
    {
1022
        if (!empty($variables)) {
1023
            $this->with($variables);
1024
        }
1025
1026
        $this->view = $view;
1027
    }
1028
1029
    /**
1030
     * Set grid title.
1031
     *
1032
     * @param string $title
1033
     *
1034
     * @return $this
1035
     */
1036
    public function setTitle($title)
1037
    {
1038
        $this->variables['title'] = $title;
1039
1040
        return $this;
1041
    }
1042
1043
    /**
1044
     * Set relation for grid.
1045
     *
1046
     * @param Relations\Relation $relation
1047
     *
1048
     * @return $this
1049
     */
1050
    public function setRelation(Relations\Relation $relation)
1051
    {
1052
        $this->model()->setRelation($relation);
1053
1054
        return $this;
1055
    }
1056
1057
    /**
1058
     * Set resource path for grid.
1059
     *
1060
     * @param string $path
1061
     *
1062
     * @return $this
1063
     */
1064
    public function setResource($path)
1065
    {
1066
        $this->resourcePath = $path;
1067
1068
        return $this;
1069
    }
1070
1071
    /**
1072
     * Get the string contents of the grid view.
1073
     *
1074
     * @return string
1075
     */
1076
    public function render()
1077
    {
1078
        $this->handleExportRequest(true);
1079
1080
        try {
1081
            $this->build();
1082
        } catch (\Exception $e) {
1083
            return Handler::renderException($e);
1084
        }
1085
1086
        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...
1087
    }
1088
}
1089