Completed
Push — master ( 15589f...c75704 )
by Song
82:53
created

Grid::getExporter()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 1
dl 0
loc 4
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\Displayers;
9
use Encore\Admin\Grid\Exporter;
10
use Encore\Admin\Grid\Exporters\AbstractExporter;
11
use Encore\Admin\Grid\Filter;
12
use Encore\Admin\Grid\HasElementNames;
13
use Encore\Admin\Grid\Model;
14
use Encore\Admin\Grid\Row;
15
use Encore\Admin\Grid\Tools;
16
use Illuminate\Database\Eloquent\Model as Eloquent;
17
use Illuminate\Database\Eloquent\Relations;
18
use Illuminate\Support\Collection;
19
use Illuminate\Support\Facades\Input;
20
use Jenssegers\Mongodb\Eloquent\Model as MongodbModel;
21
22
class Grid
23
{
24
    use HasElementNames;
25
26
    /**
27
     * The grid data model instance.
28
     *
29
     * @var \Encore\Admin\Grid\Model
30
     */
31
    protected $model;
32
33
    /**
34
     * Collection of all grid columns.
35
     *
36
     * @var \Illuminate\Support\Collection
37
     */
38
    protected $columns;
39
40
    /**
41
     * Collection of all data rows.
42
     *
43
     * @var \Illuminate\Support\Collection
44
     */
45
    protected $rows;
46
47
    /**
48
     * Rows callable fucntion.
49
     *
50
     * @var \Closure
51
     */
52
    protected $rowsCallback;
53
54
    /**
55
     * All column names of the grid.
56
     *
57
     * @var array
58
     */
59
    public $columnNames = [];
60
61
    /**
62
     * Grid builder.
63
     *
64
     * @var \Closure
65
     */
66
    protected $builder;
67
68
    /**
69
     * Mark if the grid is builded.
70
     *
71
     * @var bool
72
     */
73
    protected $builded = false;
74
75
    /**
76
     * All variables in grid view.
77
     *
78
     * @var array
79
     */
80
    protected $variables = [];
81
82
    /**
83
     * The grid Filter.
84
     *
85
     * @var \Encore\Admin\Grid\Filter
86
     */
87
    protected $filter;
88
89
    /**
90
     * Resource path of the grid.
91
     *
92
     * @var
93
     */
94
    protected $resourcePath;
95
96
    /**
97
     * Default primary key name.
98
     *
99
     * @var string
100
     */
101
    protected $keyName = 'id';
102
103
    /**
104
     * Export driver.
105
     *
106
     * @var string
107
     */
108
    protected $exporter;
109
110
    /**
111
     * View for grid to render.
112
     *
113
     * @var string
114
     */
115
    protected $view = 'admin::grid.table';
116
117
    /**
118
     * Per-page options.
119
     *
120
     * @var array
121
     */
122
    public $perPages = [10, 20, 30, 50, 100];
123
124
    /**
125
     * Default items count per-page.
126
     *
127
     * @var int
128
     */
129
    public $perPage = 20;
130
131
    /**
132
     * Header tools.
133
     *
134
     * @var Tools
135
     */
136
    public $tools;
137
138
    /**
139
     * Callback for grid actions.
140
     *
141
     * @var Closure
142
     */
143
    protected $actionsCallback;
144
145
    /**
146
     * Options for grid.
147
     *
148
     * @var array
149
     */
150
    protected $options = [
151
        'usePagination'  => true,
152
        'useFilter'      => true,
153
        'useExporter'    => true,
154
        'useActions'     => true,
155
        'useRowSelector' => true,
156
        'allowCreate'    => true,
157
    ];
158
159
    /**
160
     * @var Closure
161
     */
162
    protected $footer;
163
164
    /**
165
     * Create a new grid instance.
166
     *
167
     * @param Eloquent $model
168
     * @param Closure  $builder
169
     */
170
    public function __construct(Eloquent $model, Closure $builder = null)
171
    {
172
        $this->keyName = $model->getKeyName();
173
        $this->model = new Model($model);
174
        $this->columns = new Collection();
175
        $this->rows = new Collection();
176
        $this->builder = $builder;
177
178
        $this->model()->setGrid($this);
179
180
        $this->setupTools();
181
        $this->setupFilter();
182
183
        $this->handleExportRequest();
184
    }
185
186
    /**
187
     * Setup grid tools.
188
     */
189
    public function setupTools()
190
    {
191
        $this->tools = new Tools($this);
192
    }
193
194
    /**
195
     * Setup grid filter.
196
     *
197
     * @return void
198
     */
199
    protected function setupFilter()
200
    {
201
        $this->filter = new Filter($this->model());
202
    }
203
204
    /**
205
     * Handle export request.
206
     *
207
     * @param bool $forceExport
208
     */
209
    protected function handleExportRequest($forceExport = false)
210
    {
211
        if (!$scope = request(Exporter::$queryName)) {
212
            return;
213
        }
214
215
        // clear output buffer.
216
        if (ob_get_length()) {
217
            ob_end_clean();
218
        }
219
220
        $this->model()->usePaginate(false);
221
222
        if ($this->builder) {
223
            call_user_func($this->builder, $this);
224
225
            $this->getExporter($scope)->export();
226
        }
227
228
        if ($forceExport) {
229
            $this->getExporter($scope)->export();
230
        }
231
    }
232
233
    /**
234
     * @param string $scope
235
     *
236
     * @return AbstractExporter
237
     */
238
    protected function getExporter($scope)
239
    {
240
        return (new Exporter($this))->resolve($this->exporter)->withScope($scope);
241
    }
242
243
    /**
244
     * Get or set option for grid.
245
     *
246
     * @param string $key
247
     * @param mixed  $value
248
     *
249
     * @return $this|mixed
250
     */
251
    public function option($key, $value = null)
252
    {
253
        if (is_null($value)) {
254
            return $this->options[$key];
255
        }
256
257
        $this->options[$key] = $value;
258
259
        return $this;
260
    }
261
262
    /**
263
     * Get primary key name of model.
264
     *
265
     * @return string
266
     */
267
    public function getKeyName()
268
    {
269
        return $this->keyName ?: 'id';
270
    }
271
272
    /**
273
     * Add column to Grid.
274
     *
275
     * @param string $name
276
     * @param string $label
277
     *
278
     * @return Column
279
     */
280
    public function column($name, $label = '')
281
    {
282
        $relationName = $relationColumn = '';
283
284
        if (strpos($name, '.') !== false) {
285
            list($relationName, $relationColumn) = explode('.', $name);
286
287
            $relation = $this->model()->eloquent()->$relationName();
288
289
            $label = empty($label) ? ucfirst($relationColumn) : $label;
290
291
            $name = snake_case($relationName).'.'.$relationColumn;
292
        }
293
294
        $column = $this->addColumn($name, $label);
295
296
        if (isset($relation) && $relation instanceof Relations\Relation) {
297
            $this->model()->with($relationName);
298
            $column->setRelation($relationName, $relationColumn);
299
        }
300
301
        return $column;
302
    }
303
304
    /**
305
     * Batch add column to grid.
306
     *
307
     * @example
308
     * 1.$grid->columns(['name' => 'Name', 'email' => 'Email' ...]);
309
     * 2.$grid->columns('name', 'email' ...)
310
     *
311
     * @param array $columns
312
     *
313
     * @return Collection|null
314
     */
315
    public function columns($columns = [])
316
    {
317
        if (func_num_args() == 0) {
318
            return $this->columns;
319
        }
320
321
        if (func_num_args() == 1 && is_array($columns)) {
322
            foreach ($columns as $column => $label) {
323
                $this->column($column, $label);
324
            }
325
326
            return;
327
        }
328
329
        foreach (func_get_args() as $column) {
330
            $this->column($column);
331
        }
332
    }
333
334
    /**
335
     * Add column to grid.
336
     *
337
     * @param string $column
338
     * @param string $label
339
     *
340
     * @return Column
341
     */
342 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...
343
    {
344
        $column = new Column($column, $label);
345
        $column->setGrid($this);
346
347
        return tap($column, function ($value) {
348
            $this->columns->push($value);
349
        });
350
    }
351
352
    /**
353
     * Prepend column to grid.
354
     *
355
     * @param string $column
356
     * @param string $label
357
     *
358
     * @return Column
359
     */
360 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...
361
    {
362
        $column = new Column($column, $label);
363
        $column->setGrid($this);
364
365
        return tap($column, function ($value) {
366
            $this->columns->prepend($value);
367
        });
368
    }
369
370
    /**
371
     * Get Grid model.
372
     *
373
     * @return Model
374
     */
375
    public function model()
376
    {
377
        return $this->model;
378
    }
379
380
    /**
381
     * Paginate the grid.
382
     *
383
     * @param int $perPage
384
     *
385
     * @return void
386
     */
387
    public function paginate($perPage = 20)
388
    {
389
        $this->perPage = $perPage;
390
391
        $this->model()->paginate($perPage);
0 ignored issues
show
Bug introduced by
The method paginate() does not exist on Encore\Admin\Grid\Model. Did you maybe mean usePaginate()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
392
    }
393
394
    /**
395
     * Get the grid paginator.
396
     *
397
     * @return mixed
398
     */
399
    public function paginator()
400
    {
401
        return new Tools\Paginator($this);
402
    }
403
404
    /**
405
     * Disable grid pagination.
406
     *
407
     * @return $this
408
     */
409
    public function disablePagination()
410
    {
411
        $this->model->usePaginate(false);
412
413
        $this->option('usePagination', false);
414
415
        return $this;
416
    }
417
418
    /**
419
     * If this grid use pagination.
420
     *
421
     * @return bool
422
     */
423
    public function usePagination()
424
    {
425
        return $this->option('usePagination');
426
    }
427
428
    /**
429
     * Set per-page options.
430
     *
431
     * @param array $perPages
432
     */
433
    public function perPages(array $perPages)
434
    {
435
        $this->perPages = $perPages;
436
    }
437
438
    /**
439
     * Disable all actions.
440
     *
441
     * @return $this
442
     */
443
    public function disableActions()
444
    {
445
        return $this->option('useActions', false);
446
    }
447
448
    /**
449
     * Set grid action callback.
450
     *
451
     * @param Closure $callback
452
     *
453
     * @return $this
454
     */
455
    public function actions(Closure $callback)
456
    {
457
        $this->actionsCallback = $callback;
458
459
        return $this;
460
    }
461
462
    /**
463
     * Add `actions` column for grid.
464
     *
465
     * @return void
466
     */
467
    protected function appendActionsColumn()
468
    {
469
        if (!$this->option('useActions')) {
470
            return;
471
        }
472
473
        $this->addColumn('__actions__', trans('admin.action'))
474
            ->displayUsing(Displayers\Actions::class, [$this->actionsCallback]);
475
    }
476
477
    /**
478
     * Disable row selector.
479
     *
480
     * @return Grid|mixed
481
     */
482
    public function disableRowSelector()
483
    {
484
        $this->tools(function ($tools) {
485
            /* @var Grid\Tools $tools */
486
            $tools->disableBatchActions();
487
        });
488
489
        return $this->option('useRowSelector', false);
490
    }
491
492
    /**
493
     * Prepend checkbox column for grid.
494
     *
495
     * @return void
496
     */
497
    protected function prependRowSelectorColumn()
498
    {
499
        if (!$this->option('useRowSelector')) {
500
            return;
501
        }
502
503
        $this->prependColumn(Column::SELECT_COLUMN_NAME, ' ')
504
            ->displayUsing(Displayers\RowSelector::class);
505
    }
506
507
    /**
508
     * Build the grid.
509
     *
510
     * @return void
511
     */
512
    public function build()
513
    {
514
        if ($this->builded) {
515
            return;
516
        }
517
518
        $collection = $this->processFilter(false);
519
520
        $data = $collection->toArray();
521
522
        $this->prependRowSelectorColumn();
523
        $this->appendActionsColumn();
524
525
        Column::setOriginalGridModels($collection);
526
527
        $this->columns->map(function (Column $column) use (&$data) {
528
            $data = $column->fill($data);
529
530
            $this->columnNames[] = $column->getName();
531
        });
532
533
        $this->buildRows($data);
534
535
        $this->builded = true;
536
    }
537
538
    /**
539
     * Disable grid filter.
540
     *
541
     * @return $this
542
     */
543
    public function disableFilter()
544
    {
545
        $this->option('useFilter', false);
546
547
        $this->tools->disableFilterButton();
548
549
        return $this;
550
    }
551
552
    /**
553
     * Get filter of Grid.
554
     *
555
     * @return Filter
556
     */
557
    public function getFilter()
558
    {
559
        return $this->filter;
560
    }
561
562
    /**
563
     * Process the grid filter.
564
     *
565
     * @param bool $toArray
566
     *
567
     * @return array|Collection|mixed
568
     */
569
    public function processFilter($toArray = true)
570
    {
571
        if ($this->builder) {
572
            call_user_func($this->builder, $this);
573
        }
574
575
        return $this->filter->execute($toArray);
576
    }
577
578
    /**
579
     * Set the grid filter.
580
     *
581
     * @param Closure $callback
582
     */
583
    public function filter(Closure $callback)
584
    {
585
        call_user_func($callback, $this->filter);
586
    }
587
588
    /**
589
     * Render the grid filter.
590
     *
591
     * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View|string
592
     */
593
    public function renderFilter()
594
    {
595
        if (!$this->option('useFilter')) {
596
            return '';
597
        }
598
599
        return $this->filter->render();
600
    }
601
602
    /**
603
     * Expand filter.
604
     *
605
     * @return $this
606
     */
607
    public function expandFilter()
608
    {
609
        $this->filter->expand();
610
611
        return $this;
612
    }
613
614
    /**
615
     * Build the grid rows.
616
     *
617
     * @param array $data
618
     *
619
     * @return void
620
     */
621
    protected function buildRows(array $data)
622
    {
623
        $this->rows = collect($data)->map(function ($model, $number) {
624
            return new Row($number, $model);
625
        });
626
627
        if ($this->rowsCallback) {
628
            $this->rows->map($this->rowsCallback);
629
        }
630
    }
631
632
    /**
633
     * Set grid row callback function.
634
     *
635
     * @param Closure $callable
636
     *
637
     * @return Collection|null
638
     */
639
    public function rows(Closure $callable = null)
640
    {
641
        if (is_null($callable)) {
642
            return $this->rows;
643
        }
644
645
        $this->rowsCallback = $callable;
646
    }
647
648
    /**
649
     * Setup grid tools.
650
     *
651
     * @param Closure $callback
652
     *
653
     * @return void
654
     */
655
    public function tools(Closure $callback)
656
    {
657
        call_user_func($callback, $this->tools);
658
    }
659
660
    /**
661
     * Render custom tools.
662
     *
663
     * @return string
664
     */
665
    public function renderHeaderTools()
666
    {
667
        return $this->tools->render();
668
    }
669
670
    /**
671
     * Set exporter driver for Grid to export.
672
     *
673
     * @param $exporter
674
     *
675
     * @return $this
676
     */
677
    public function exporter($exporter)
678
    {
679
        $this->exporter = $exporter;
680
681
        return $this;
682
    }
683
684
    /**
685
     * Get the export url.
686
     *
687
     * @param int  $scope
688
     * @param null $args
689
     *
690
     * @return string
691
     */
692
    public function getExportUrl($scope = 1, $args = null)
693
    {
694
        $input = array_merge(Input::all(), Exporter::formatExportQuery($scope, $args));
695
696
        if ($constraints = $this->model()->getConstraints()) {
697
            $input = array_merge($input, $constraints);
698
        }
699
700
        return $this->resource().'?'.http_build_query($input);
701
    }
702
703
    /**
704
     * Get create url.
705
     *
706
     * @return string
707
     */
708
    public function getCreateUrl()
709
    {
710
        $queryString = '';
711
712
        if ($constraints = $this->model()->getConstraints()) {
713
            $queryString = http_build_query($constraints);
714
        }
715
716
        return sprintf('%s/create%s',
717
            $this->resource(),
718
            $queryString ? ('?'.$queryString) : ''
719
        );
720
    }
721
722
    /**
723
     * If grid allows export.s.
724
     *
725
     * @return bool
726
     */
727
    public function allowExport()
728
    {
729
        return $this->option('useExporter');
730
    }
731
732
    /**
733
     * Disable export.
734
     *
735
     * @return $this
736
     */
737
    public function disableExport()
738
    {
739
        return $this->option('useExporter', false);
740
    }
741
742
    /**
743
     * Render export button.
744
     *
745
     * @return string
746
     */
747
    public function renderExportButton()
748
    {
749
        return (new Tools\ExportButton($this))->render();
750
    }
751
752
    /**
753
     * Alias for method `disableCreateButton`.
754
     *
755
     * @return $this
756
     *
757
     * @deprecated
758
     */
759
    public function disableCreation()
760
    {
761
        return $this->disableCreateButton();
762
    }
763
764
    /**
765
     * Remove create button on grid.
766
     *
767
     * @return $this
768
     */
769
    public function disableCreateButton()
770
    {
771
        return $this->option('allowCreate', false);
772
    }
773
774
    /**
775
     * If allow creation.
776
     *
777
     * @return bool
778
     */
779
    public function allowCreation()
780
    {
781
        return $this->option('allowCreate');
782
    }
783
784
    /**
785
     * Render create button for grid.
786
     *
787
     * @return string
788
     */
789
    public function renderCreateButton()
790
    {
791
        return (new Tools\CreateButton($this))->render();
792
    }
793
794
    /**
795
     * Set grid footer.
796
     *
797
     * @param Closure|null $closure
798
     *
799
     * @return Closure
800
     */
801
    public function footer(Closure $closure = null)
802
    {
803
        if (!$closure) {
804
            return $this->footer;
805
        }
806
807
        $this->footer = $closure;
808
809
        return $this;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this; (Encore\Admin\Grid) is incompatible with the return type documented by Encore\Admin\Grid::footer of type Closure.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
810
    }
811
812
    /**
813
     * Render grid footer.
814
     *
815
     * @return Tools\Footer|string
816
     */
817
    public function renderFooter()
818
    {
819
        if (!$this->footer) {
820
            return '';
821
        }
822
823
        return (new Tools\Footer($this))->render();
824
    }
825
826
    /**
827
     * Get current resource uri.
828
     *
829
     * @param string $path
830
     *
831
     * @return string
832
     */
833
    public function resource($path = null)
834
    {
835
        if (!empty($path)) {
836
            $this->resourcePath = $path;
837
838
            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...
839
        }
840
841
        if (!empty($this->resourcePath)) {
842
            return $this->resourcePath;
843
        }
844
845
        return app('request')->getPathInfo();
846
    }
847
848
    /**
849
     * Handle get mutator column for grid.
850
     *
851
     * @param string $method
852
     * @param string $label
853
     *
854
     * @return bool|Column
855
     */
856
    protected function handleGetMutatorColumn($method, $label)
857
    {
858
        if ($this->model()->eloquent()->hasGetMutator($method)) {
859
            return $this->addColumn($method, $label);
860
        }
861
862
        return false;
863
    }
864
865
    /**
866
     * Handle relation column for grid.
867
     *
868
     * @param string $method
869
     * @param string $label
870
     *
871
     * @return bool|Column
872
     */
873
    protected function handleRelationColumn($method, $label)
874
    {
875
        $model = $this->model()->eloquent();
876
877
        if (!method_exists($model, $method)) {
878
            return false;
879
        }
880
881
        if (!($relation = $model->$method()) instanceof Relations\Relation) {
882
            return false;
883
        }
884
885
        if ($relation instanceof Relations\HasOne || $relation instanceof Relations\BelongsTo) {
886
            $this->model()->with($method);
887
888
            return $this->addColumn($method, $label)->setRelation(snake_case($method));
889
        }
890
891
        if ($relation instanceof Relations\HasMany
892
            || $relation instanceof Relations\BelongsToMany
893
            || $relation instanceof Relations\MorphToMany
894
        ) {
895
            $this->model()->with($method);
896
897
            return $this->addColumn(snake_case($method), $label);
898
        }
899
900
        return false;
901
    }
902
903
    /**
904
     * Dynamically add columns to the grid view.
905
     *
906
     * @param $method
907
     * @param $arguments
908
     *
909
     * @return Column
910
     */
911
    public function __call($method, $arguments)
912
    {
913
        $label = isset($arguments[0]) ? $arguments[0] : ucfirst($method);
914
915
        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...
916
            return $this->addColumn($method, $label);
917
        }
918
919
        if ($column = $this->handleGetMutatorColumn($method, $label)) {
920
            return $column;
921
        }
922
923
        if ($column = $this->handleRelationColumn($method, $label)) {
924
            return $column;
925
        }
926
927
        return $this->addColumn($method, $label);
928
    }
929
930
    /**
931
     * Register column displayers.
932
     *
933
     * @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...
934
     */
935
    public static function registerColumnDisplayer()
936
    {
937
        $map = [
938
            'editable'    => Displayers\Editable::class,
939
            'switch'      => Displayers\SwitchDisplay::class,
940
            'switchGroup' => Displayers\SwitchGroup::class,
941
            'select'      => Displayers\Select::class,
942
            'image'       => Displayers\Image::class,
943
            'label'       => Displayers\Label::class,
944
            'button'      => Displayers\Button::class,
945
            'link'        => Displayers\Link::class,
946
            'badge'       => Displayers\Badge::class,
947
            'progressBar' => Displayers\ProgressBar::class,
948
            'radio'       => Displayers\Radio::class,
949
            'checkbox'    => Displayers\Checkbox::class,
950
            'orderable'   => Displayers\Orderable::class,
951
            'table'       => Displayers\Table::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
     * Get the string contents of the grid view.
1044
     *
1045
     * @return string
1046
     */
1047
    public function render()
1048
    {
1049
        $this->handleExportRequest(true);
1050
1051
        try {
1052
            $this->build();
1053
        } catch (\Exception $e) {
1054
            return Handler::renderException($e);
1055
        }
1056
1057
        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...
1058
    }
1059
}
1060