Completed
Push — master ( 8bf0fe...b37564 )
by Song
05:18 queued 03:01
created

Grid::callRenderingCallback()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

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