Completed
Push — master ( 92ed1e...e49da3 )
by Song
06:13 queued 03:41
created

Grid::callInitCallbacks()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

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