Completed
Push — master ( 959f3b...22ac2d )
by Song
03:09
created

Grid::prependColumn()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9

Duplication

Lines 9
Ratio 100 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 2
dl 9
loc 9
rs 9.9666
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\Filter;
11
use Encore\Admin\Grid\HasElementNames;
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 Jenssegers\Mongodb\Eloquent\Model as MongodbModel;
20
21
class Grid
22
{
23
    use HasElementNames;
24
25
    /**
26
     * The grid data model instance.
27
     *
28
     * @var \Encore\Admin\Grid\Model
29
     */
30
    protected $model;
31
32
    /**
33
     * Collection of all grid columns.
34
     *
35
     * @var \Illuminate\Support\Collection
36
     */
37
    protected $columns;
38
39
    /**
40
     * Collection of all data rows.
41
     *
42
     * @var \Illuminate\Support\Collection
43
     */
44
    protected $rows;
45
46
    /**
47
     * Rows callable fucntion.
48
     *
49
     * @var \Closure
50
     */
51
    protected $rowsCallback;
52
53
    /**
54
     * All column names of the grid.
55
     *
56
     * @var array
57
     */
58
    public $columnNames = [];
59
60
    /**
61
     * Grid builder.
62
     *
63
     * @var \Closure
64
     */
65
    protected $builder;
66
67
    /**
68
     * Mark if the grid is builded.
69
     *
70
     * @var bool
71
     */
72
    protected $builded = false;
73
74
    /**
75
     * All variables in grid view.
76
     *
77
     * @var array
78
     */
79
    protected $variables = [];
80
81
    /**
82
     * The grid Filter.
83
     *
84
     * @var \Encore\Admin\Grid\Filter
85
     */
86
    protected $filter;
87
88
    /**
89
     * Resource path of the grid.
90
     *
91
     * @var
92
     */
93
    protected $resourcePath;
94
95
    /**
96
     * Default primary key name.
97
     *
98
     * @var string
99
     */
100
    protected $keyName = 'id';
101
102
    /**
103
     * Export driver.
104
     *
105
     * @var string
106
     */
107
    protected $exporter;
108
109
    /**
110
     * View for grid to render.
111
     *
112
     * @var string
113
     */
114
    protected $view = 'admin::grid.table';
115
116
    /**
117
     * Per-page options.
118
     *
119
     * @var array
120
     */
121
    public $perPages = [10, 20, 30, 50, 100];
122
123
    /**
124
     * Default items count per-page.
125
     *
126
     * @var int
127
     */
128
    public $perPage = 20;
129
130
    /**
131
     * Header tools.
132
     *
133
     * @var Tools
134
     */
135
    public $tools;
136
137
    /**
138
     * Callback for grid actions.
139
     *
140
     * @var Closure
141
     */
142
    protected $actionsCallback;
143
144
    /**
145
     * Options for grid.
146
     *
147
     * @var array
148
     */
149
    protected $options = [
150
        'usePagination'  => true,
151
        'useFilter'      => true,
152
        'useExporter'    => true,
153
        'useActions'     => true,
154
        'useRowSelector' => true,
155
        'allowCreate'    => true,
156
    ];
157
158
    /**
159
     * @var Closure
160
     */
161
    protected $footer;
162
163
    /**
164
     * Create a new grid instance.
165
     *
166
     * @param Eloquent $model
167
     * @param Closure  $builder
168
     */
169
    public function __construct(Eloquent $model, Closure $builder = null)
170
    {
171
        $this->keyName = $model->getKeyName();
172
        $this->model = new Model($model);
173
        $this->columns = new Collection();
174
        $this->rows = new Collection();
175
        $this->builder = $builder;
176
177
        $this->model()->setGrid($this);
178
179
        $this->setupTools();
180
        $this->setupFilter();
181
182
        $this->handleExportRequest();
183
    }
184
185
    /**
186
     * Setup grid tools.
187
     */
188
    public function setupTools()
189
    {
190
        $this->tools = new Tools($this);
191
    }
192
193
    /**
194
     * Setup grid filter.
195
     *
196
     * @return void
197
     */
198
    protected function setupFilter()
199
    {
200
        $this->filter = new Filter($this->model());
201
    }
202
203
    /**
204
     * Handle export request.
205
     *
206
     * @param bool $forceExport
207
     */
208
    protected function handleExportRequest($forceExport = false)
209
    {
210
        if (!$scope = request(Exporter::$queryName)) {
211
            return;
212
        }
213
214
        // clear output buffer.
215
        if (ob_get_length()) {
216
            ob_end_clean();
217
        }
218
219
        $this->model()->usePaginate(false);
220
221
        $exporter = (new Exporter($this))->resolve($this->exporter)->withScope($scope);
222
223
        if ($forceExport) {
224
            $exporter->export();
225
        }
226
227
        if ($this->builder) {
228
            call_user_func($this->builder, $this);
229
230
            $exporter->export();
231
        }
232
    }
233
234
    /**
235
     * Get or set option for grid.
236
     *
237
     * @param string $key
238
     * @param mixed  $value
239
     *
240
     * @return $this|mixed
241
     */
242
    public function option($key, $value = null)
243
    {
244
        if (is_null($value)) {
245
            return $this->options[$key];
246
        }
247
248
        $this->options[$key] = $value;
249
250
        return $this;
251
    }
252
253
    /**
254
     * Get primary key name of model.
255
     *
256
     * @return string
257
     */
258
    public function getKeyName()
259
    {
260
        return $this->keyName ?: 'id';
261
    }
262
263
    /**
264
     * Add column to Grid.
265
     *
266
     * @param string $name
267
     * @param string $label
268
     *
269
     * @return Column
270
     */
271
    public function column($name, $label = '')
272
    {
273
        $relationName = $relationColumn = '';
274
275
        if (strpos($name, '.') !== false) {
276
            list($relationName, $relationColumn) = explode('.', $name);
277
278
            $relation = $this->model()->eloquent()->$relationName();
279
280
            $label = empty($label) ? ucfirst($relationColumn) : $label;
281
282
            $name = snake_case($relationName).'.'.$relationColumn;
283
        }
284
285
        $column = $this->addColumn($name, $label);
286
287
        if (isset($relation) && $relation instanceof Relations\Relation) {
288
            $this->model()->with($relationName);
289
            $column->setRelation($relationName, $relationColumn);
290
        }
291
292
        return $column;
293
    }
294
295
    /**
296
     * Batch add column to grid.
297
     *
298
     * @example
299
     * 1.$grid->columns(['name' => 'Name', 'email' => 'Email' ...]);
300
     * 2.$grid->columns('name', 'email' ...)
301
     *
302
     * @param array $columns
303
     *
304
     * @return Collection|null
305
     */
306
    public function columns($columns = [])
307
    {
308
        if (func_num_args() == 0) {
309
            return $this->columns;
310
        }
311
312
        if (func_num_args() == 1 && is_array($columns)) {
313
            foreach ($columns as $column => $label) {
314
                $this->column($column, $label);
315
            }
316
317
            return;
318
        }
319
320
        foreach (func_get_args() as $column) {
321
            $this->column($column);
322
        }
323
    }
324
325
    /**
326
     * Add column to grid.
327
     *
328
     * @param string $column
329
     * @param string $label
330
     *
331
     * @return Column
332
     */
333 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...
334
    {
335
        $column = new Column($column, $label);
336
        $column->setGrid($this);
337
338
        return tap($column, function ($value) {
339
            $this->columns->push($value);
340
        });
341
    }
342
343
    /**
344
     * Prepend column to grid.
345
     *
346
     * @param string $column
347
     * @param string $label
348
     * @return Column
349
     */
350 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...
351
    {
352
        $column = new Column($column, $label);
353
        $column->setGrid($this);
354
355
        return tap($column, function ($value) {
356
            $this->columns->prepend($value);
357
        });
358
    }
359
360
    /**
361
     * Get Grid model.
362
     *
363
     * @return Model
364
     */
365
    public function model()
366
    {
367
        return $this->model;
368
    }
369
370
    /**
371
     * Paginate the grid.
372
     *
373
     * @param int $perPage
374
     *
375
     * @return void
376
     */
377
    public function paginate($perPage = 20)
378
    {
379
        $this->perPage = $perPage;
380
381
        $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...
382
    }
383
384
    /**
385
     * Get the grid paginator.
386
     *
387
     * @return mixed
388
     */
389
    public function paginator()
390
    {
391
        return new Tools\Paginator($this);
392
    }
393
394
    /**
395
     * Disable grid pagination.
396
     *
397
     * @return $this
398
     */
399
    public function disablePagination()
400
    {
401
        $this->model->usePaginate(false);
402
403
        $this->option('usePagination', false);
404
405
        return $this;
406
    }
407
408
    /**
409
     * If this grid use pagination.
410
     *
411
     * @return bool
412
     */
413
    public function usePagination()
414
    {
415
        return $this->option('usePagination');
416
    }
417
418
    /**
419
     * Set per-page options.
420
     *
421
     * @param array $perPages
422
     */
423
    public function perPages(array $perPages)
424
    {
425
        $this->perPages = $perPages;
426
    }
427
428
    /**
429
     * Disable all actions.
430
     *
431
     * @return $this
432
     */
433
    public function disableActions()
434
    {
435
        return $this->option('useActions', false);
436
    }
437
438
    /**
439
     * Set grid action callback.
440
     *
441
     * @param Closure $callback
442
     *
443
     * @return $this
444
     */
445
    public function actions(Closure $callback)
446
    {
447
        $this->actionsCallback = $callback;
448
449
        return $this;
450
    }
451
452
    /**
453
     * Add `actions` column for grid.
454
     *
455
     * @return void
456
     */
457
    protected function appendActionsColumn()
458
    {
459
        if (!$this->option('useActions')) {
460
            return;
461
        }
462
463
        $this->addColumn('__actions__', trans('admin.action'))
464
            ->displayUsing(Displayers\Actions::class, [$this->actionsCallback]);
465
    }
466
467
    /**
468
     * Disable row selector.
469
     *
470
     * @return Grid|mixed
471
     */
472
    public function disableRowSelector()
473
    {
474
        $this->tools(function ($tools) {
475
            /* @var Grid\Tools $tools */
476
            $tools->disableBatchActions();
477
        });
478
479
        return $this->option('useRowSelector', false);
480
    }
481
482
    /**
483
     * Prepend checkbox column for grid.
484
     *
485
     * @return void
486
     */
487
    protected function prependRowSelectorColumn()
488
    {
489
        if (!$this->option('useRowSelector')) {
490
            return;
491
        }
492
493
        $this->prependColumn(Column::SELECT_COLUMN_NAME, ' ')
494
            ->displayUsing(Displayers\RowSelector::class);
495
    }
496
497
    /**
498
     * Build the grid.
499
     *
500
     * @return void
501
     */
502
    public function build()
503
    {
504
        if ($this->builded) {
505
            return;
506
        }
507
508
        $collection = $this->processFilter(false);
509
510
        $data = $collection->toArray();
511
512
        $this->prependRowSelectorColumn();
513
        $this->appendActionsColumn();
514
515
        Column::setOriginalGridModels($collection);
516
517
        $this->columns->map(function (Column $column) use (&$data) {
518
            $data = $column->fill($data);
519
520
            $this->columnNames[] = $column->getName();
521
        });
522
523
        $this->buildRows($data);
524
525
        $this->builded = true;
526
    }
527
528
    /**
529
     * Disable grid filter.
530
     *
531
     * @return $this
532
     */
533
    public function disableFilter()
534
    {
535
        $this->option('useFilter', false);
536
537
        $this->tools->disableFilterButton();
538
539
        return $this;
540
    }
541
542
    /**
543
     * Get filter of Grid.
544
     *
545
     * @return Filter
546
     */
547
    public function getFilter()
548
    {
549
        return $this->filter;
550
    }
551
552
    /**
553
     * Process the grid filter.
554
     *
555
     * @param bool $toArray
556
     *
557
     * @return array|Collection|mixed
558
     */
559
    public function processFilter($toArray = true)
560
    {
561
        if ($this->builder) {
562
            call_user_func($this->builder, $this);
563
        }
564
565
        return $this->filter->execute($toArray);
566
    }
567
568
    /**
569
     * Set the grid filter.
570
     *
571
     * @param Closure $callback
572
     */
573
    public function filter(Closure $callback)
574
    {
575
        call_user_func($callback, $this->filter);
576
    }
577
578
    /**
579
     * Render the grid filter.
580
     *
581
     * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View|string
582
     */
583
    public function renderFilter()
584
    {
585
        if (!$this->option('useFilter')) {
586
            return '';
587
        }
588
589
        return $this->filter->render();
590
    }
591
592
    /**
593
     * Expand filter.
594
     *
595
     * @return $this
596
     */
597
    public function expandFilter()
598
    {
599
        $this->filter->expand();
600
601
        return $this;
602
    }
603
604
    /**
605
     * Build the grid rows.
606
     *
607
     * @param array $data
608
     *
609
     * @return void
610
     */
611
    protected function buildRows(array $data)
612
    {
613
        $this->rows = collect($data)->map(function ($model, $number) {
614
            return new Row($number, $model);
615
        });
616
617
        if ($this->rowsCallback) {
618
            $this->rows->map($this->rowsCallback);
619
        }
620
    }
621
622
    /**
623
     * Set grid row callback function.
624
     *
625
     * @param Closure $callable
626
     *
627
     * @return Collection|null
628
     */
629
    public function rows(Closure $callable = null)
630
    {
631
        if (is_null($callable)) {
632
            return $this->rows;
633
        }
634
635
        $this->rowsCallback = $callable;
636
    }
637
638
    /**
639
     * Setup grid tools.
640
     *
641
     * @param Closure $callback
642
     *
643
     * @return void
644
     */
645
    public function tools(Closure $callback)
646
    {
647
        call_user_func($callback, $this->tools);
648
    }
649
650
    /**
651
     * Render custom tools.
652
     *
653
     * @return string
654
     */
655
    public function renderHeaderTools()
656
    {
657
        return $this->tools->render();
658
    }
659
660
    /**
661
     * Set exporter driver for Grid to export.
662
     *
663
     * @param $exporter
664
     *
665
     * @return $this
666
     */
667
    public function exporter($exporter)
668
    {
669
        $this->exporter = $exporter;
670
671
        return $this;
672
    }
673
674
    /**
675
     * Get the export url.
676
     *
677
     * @param int  $scope
678
     * @param null $args
679
     *
680
     * @return string
681
     */
682
    public function getExportUrl($scope = 1, $args = null)
683
    {
684
        $input = array_merge(Input::all(), Exporter::formatExportQuery($scope, $args));
685
686
        if ($constraints = $this->model()->getConstraints()) {
687
            $input = array_merge($input, $constraints);
688
        }
689
690
        return $this->resource().'?'.http_build_query($input);
691
    }
692
693
    /**
694
     * Get create url.
695
     *
696
     * @return string
697
     */
698
    public function getCreateUrl()
699
    {
700
        $queryString = '';
701
702
        if ($constraints = $this->model()->getConstraints()) {
703
            $queryString = http_build_query($constraints);
704
        }
705
706
        return sprintf('%s/create%s',
707
            $this->resource(),
708
            $queryString ? ('?'.$queryString) : ''
709
        );
710
    }
711
712
    /**
713
     * If grid allows export.s.
714
     *
715
     * @return bool
716
     */
717
    public function allowExport()
718
    {
719
        return $this->option('useExporter');
720
    }
721
722
    /**
723
     * Disable export.
724
     *
725
     * @return $this
726
     */
727
    public function disableExport()
728
    {
729
        return $this->option('useExporter', false);
730
    }
731
732
    /**
733
     * Render export button.
734
     *
735
     * @return string
736
     */
737
    public function renderExportButton()
738
    {
739
        return (new Tools\ExportButton($this))->render();
740
    }
741
742
    /**
743
     * Alias for method `disableCreateButton`.
744
     *
745
     * @return $this
746
     *
747
     * @deprecated
748
     */
749
    public function disableCreation()
750
    {
751
        return $this->disableCreateButton();
752
    }
753
754
    /**
755
     * Remove create button on grid.
756
     *
757
     * @return $this
758
     */
759
    public function disableCreateButton()
760
    {
761
        return $this->option('allowCreate', false);
762
    }
763
764
    /**
765
     * If allow creation.
766
     *
767
     * @return bool
768
     */
769
    public function allowCreation()
770
    {
771
        return $this->option('allowCreate');
772
    }
773
774
    /**
775
     * Render create button for grid.
776
     *
777
     * @return string
778
     */
779
    public function renderCreateButton()
780
    {
781
        return (new Tools\CreateButton($this))->render();
782
    }
783
784
    /**
785
     * Set grid footer.
786
     *
787
     * @param Closure|null $closure
788
     *
789
     * @return Closure
790
     */
791
    public function footer(Closure $closure = null)
792
    {
793
        if (!$closure) {
794
            return $this->footer;
795
        }
796
797
        $this->footer = $closure;
798
799
        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::footer of type Closure.

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...
800
    }
801
802
    /**
803
     * Render grid footer.
804
     *
805
     * @return Tools\Footer|string
806
     */
807
    public function renderFooter()
808
    {
809
        if (!$this->footer) {
810
            return '';
811
        }
812
813
        return (new Tools\Footer($this))->render();
814
    }
815
816
    /**
817
     * Get current resource uri.
818
     *
819
     * @param string $path
820
     *
821
     * @return string
822
     */
823
    public function resource($path = null)
824
    {
825
        if (!empty($path)) {
826
            $this->resourcePath = $path;
827
828
            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...
829
        }
830
831
        if (!empty($this->resourcePath)) {
832
            return $this->resourcePath;
833
        }
834
835
        return app('request')->getPathInfo();
836
    }
837
838
    /**
839
     * Handle get mutator column for grid.
840
     *
841
     * @param string $method
842
     * @param string $label
843
     *
844
     * @return bool|Column
845
     */
846
    protected function handleGetMutatorColumn($method, $label)
847
    {
848
        if ($this->model()->eloquent()->hasGetMutator($method)) {
849
            return $this->addColumn($method, $label);
850
        }
851
852
        return false;
853
    }
854
855
    /**
856
     * Handle relation column for grid.
857
     *
858
     * @param string $method
859
     * @param string $label
860
     *
861
     * @return bool|Column
862
     */
863
    protected function handleRelationColumn($method, $label)
864
    {
865
        $model = $this->model()->eloquent();
866
867
        if (!method_exists($model, $method)) {
868
            return false;
869
        }
870
871
        if (!($relation = $model->$method()) instanceof Relations\Relation) {
872
            return false;
873
        }
874
875
        if ($relation instanceof Relations\HasOne || $relation instanceof Relations\BelongsTo) {
876
            $this->model()->with($method);
877
878
            return $this->addColumn($method, $label)->setRelation(snake_case($method));
879
        }
880
881
        if ($relation instanceof Relations\HasMany
882
            || $relation instanceof Relations\BelongsToMany
883
            || $relation instanceof Relations\MorphToMany
884
        ) {
885
            $this->model()->with($method);
886
887
            return $this->addColumn(snake_case($method), $label);
888
        }
889
890
        return false;
891
    }
892
893
    /**
894
     * Dynamically add columns to the grid view.
895
     *
896
     * @param $method
897
     * @param $arguments
898
     *
899
     * @return Column
900
     */
901
    public function __call($method, $arguments)
902
    {
903
        $label = isset($arguments[0]) ? $arguments[0] : ucfirst($method);
904
905
        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...
906
            return $this->addColumn($method, $label);
907
        }
908
909
        if ($column = $this->handleGetMutatorColumn($method, $label)) {
910
            return $column;
911
        }
912
913
        if ($column = $this->handleRelationColumn($method, $label)) {
914
            return $column;
915
        }
916
917
        return $this->addColumn($method, $label);
918
    }
919
920
    /**
921
     * Register column displayers.
922
     *
923
     * @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...
924
     */
925
    public static function registerColumnDisplayer()
926
    {
927
        $map = [
928
            'editable'    => Displayers\Editable::class,
929
            'switch'      => Displayers\SwitchDisplay::class,
930
            'switchGroup' => Displayers\SwitchGroup::class,
931
            'select'      => Displayers\Select::class,
932
            'image'       => Displayers\Image::class,
933
            'label'       => Displayers\Label::class,
934
            'button'      => Displayers\Button::class,
935
            'link'        => Displayers\Link::class,
936
            'badge'       => Displayers\Badge::class,
937
            'progressBar' => Displayers\ProgressBar::class,
938
            'radio'       => Displayers\Radio::class,
939
            'checkbox'    => Displayers\Checkbox::class,
940
            'orderable'   => Displayers\Orderable::class,
941
            'table'       => Displayers\Table::class,
942
        ];
943
944
        foreach ($map as $abstract => $class) {
945
            Column::extend($abstract, $class);
946
        }
947
    }
948
949
    /**
950
     * Add variables to grid view.
951
     *
952
     * @param array $variables
953
     *
954
     * @return $this
955
     */
956
    public function with($variables = [])
957
    {
958
        $this->variables = $variables;
959
960
        return $this;
961
    }
962
963
    /**
964
     * Get all variables will used in grid view.
965
     *
966
     * @return array
967
     */
968
    protected function variables()
969
    {
970
        $this->variables['grid'] = $this;
971
972
        return $this->variables;
973
    }
974
975
    /**
976
     * Set a view to render.
977
     *
978
     * @param string $view
979
     * @param array  $variables
980
     */
981
    public function setView($view, $variables = [])
982
    {
983
        if (!empty($variables)) {
984
            $this->with($variables);
985
        }
986
987
        $this->view = $view;
988
    }
989
990
    /**
991
     * Set grid title.
992
     *
993
     * @param string $title
994
     *
995
     * @return $this
996
     */
997
    public function setTitle($title)
998
    {
999
        $this->variables['title'] = $title;
1000
1001
        return $this;
1002
    }
1003
1004
    /**
1005
     * Set relation for grid.
1006
     *
1007
     * @param Relations\Relation $relation
1008
     *
1009
     * @return $this
1010
     */
1011
    public function setRelation(Relations\Relation $relation)
1012
    {
1013
        $this->model()->setRelation($relation);
1014
1015
        return $this;
1016
    }
1017
1018
    /**
1019
     * Set resource path for grid.
1020
     *
1021
     * @param string $path
1022
     *
1023
     * @return $this
1024
     */
1025
    public function setResource($path)
1026
    {
1027
        $this->resourcePath = $path;
1028
1029
        return $this;
1030
    }
1031
1032
    /**
1033
     * Get the string contents of the grid view.
1034
     *
1035
     * @return string
1036
     */
1037
    public function render()
1038
    {
1039
        $this->handleExportRequest(true);
1040
1041
        try {
1042
            $this->build();
1043
        } catch (\Exception $e) {
1044
            return Handler::renderException($e);
1045
        }
1046
1047
        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...
1048
    }
1049
}
1050