Completed
Push — master ( 5cbd8c...10b8c5 )
by Song
02:23
created

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