Completed
Push — master ( c8a423...a23ea0 )
by Song
02:21
created

Grid::addDefaultColumns()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

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