Completed
Push — master ( f09455...266dce )
by Song
02:34
created

Grid::getColumns()   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 0
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\Concerns;
9
use Encore\Admin\Grid\Displayers;
10
use Encore\Admin\Grid\Model;
11
use Encore\Admin\Grid\Row;
12
use Encore\Admin\Grid\Tools;
13
use Encore\Admin\Traits\ShouldSnakeAttributes;
14
use Illuminate\Database\Eloquent\Model as Eloquent;
15
use Illuminate\Database\Eloquent\Relations;
16
use Illuminate\Support\Collection;
17
use Illuminate\Support\Str;
18
use Illuminate\Support\Traits\Macroable;
19
use Jenssegers\Mongodb\Eloquent\Model as MongodbModel;
20
21
class Grid
22
{
23
    use Concerns\HasElementNames,
24
        Concerns\HasHeader,
25
        Concerns\HasFooter,
26
        Concerns\HasFilter,
27
        Concerns\HasTools,
28
        Concerns\HasTotalRow,
29
        Concerns\HasHotKeys,
30
        Concerns\HasQuickCreate,
31
        Concerns\HasActions,
32
        Concerns\HasSelector,
33
        Concerns\CanHidesColumns,
34
        Concerns\CanFixColumns,
35
        Concerns\CanExportGrid,
36
        ShouldSnakeAttributes,
37
        Macroable {
38
            __call as macroCall;
39
        }
40
41
    /**
42
     * The grid data model instance.
43
     *
44
     * @var \Encore\Admin\Grid\Model|\Illuminate\Database\Eloquent\Builder
45
     */
46
    protected $model;
47
48
    /**
49
     * Collection of all grid columns.
50
     *
51
     * @var \Illuminate\Support\Collection
52
     */
53
    protected $columns;
54
55
    /**
56
     * Collection of all data rows.
57
     *
58
     * @var \Illuminate\Support\Collection
59
     */
60
    protected $rows;
61
62
    /**
63
     * Rows callable fucntion.
64
     *
65
     * @var \Closure
66
     */
67
    protected $rowsCallback;
68
69
    /**
70
     * All column names of the grid.
71
     *
72
     * @var array
73
     */
74
    public $columnNames = [];
75
76
    /**
77
     * Grid builder.
78
     *
79
     * @var \Closure
80
     */
81
    protected $builder;
82
83
    /**
84
     * Mark if the grid is builded.
85
     *
86
     * @var bool
87
     */
88
    protected $builded = false;
89
90
    /**
91
     * All variables in grid view.
92
     *
93
     * @var array
94
     */
95
    protected $variables = [];
96
97
    /**
98
     * Resource path of the grid.
99
     *
100
     * @var
101
     */
102
    protected $resourcePath;
103
104
    /**
105
     * Default primary key name.
106
     *
107
     * @var string
108
     */
109
    protected $keyName = 'id';
110
111
    /**
112
     * View for grid to render.
113
     *
114
     * @var string
115
     */
116
    protected $view = 'admin::grid.table';
117
118
    /**
119
     * Per-page options.
120
     *
121
     * @var array
122
     */
123
    public $perPages = [10, 20, 30, 50, 100];
124
125
    /**
126
     * Default items count per-page.
127
     *
128
     * @var int
129
     */
130
    public $perPage = 20;
131
132
    /**
133
     * @var []callable
134
     */
135
    protected $renderingCallbacks = [];
136
137
    /**
138
     * Options for grid.
139
     *
140
     * @var array
141
     */
142
    protected $options = [
143
        'show_pagination'        => true,
144
        'show_tools'             => true,
145
        'show_filter'            => true,
146
        'show_exporter'          => true,
147
        'show_actions'           => true,
148
        'show_row_selector'      => true,
149
        'show_create_btn'        => true,
150
        'show_column_selector'   => true,
151
        'show_define_empty_page' => true,
152
    ];
153
154
    /**
155
     * @var string
156
     */
157
    public $tableID;
158
159
    /**
160
     * Initialization closure array.
161
     *
162
     * @var []Closure
163
     */
164
    protected static $initCallbacks = [];
165
166
    /**
167
     * Create a new grid instance.
168
     *
169
     * @param Eloquent $model
170
     * @param Closure  $builder
171
     */
172
    public function __construct(Eloquent $model, Closure $builder = null)
173
    {
174
        $this->model = new Model($model, $this);
175
        $this->keyName = $model->getKeyName();
176
        $this->builder = $builder;
177
178
        $this->initialize();
179
180
        $this->callInitCallbacks();
181
    }
182
183
    /**
184
     * Initialize.
185
     */
186
    protected function initialize()
187
    {
188
        $this->tableID = uniqid('grid-table');
189
190
        $this->columns = Collection::make();
191
        $this->rows = Collection::make();
192
193
        $this->initTools()
194
            ->initFilter();
195
    }
196
197
    /**
198
     * Initialize with user pre-defined default disables and exporter, etc.
199
     *
200
     * @param Closure $callback
201
     */
202
    public static function init(Closure $callback = null)
203
    {
204
        static::$initCallbacks[] = $callback;
205
    }
206
207
    /**
208
     * Call the initialization closure array in sequence.
209
     */
210
    protected function callInitCallbacks()
211
    {
212
        if (empty(static::$initCallbacks)) {
213
            return;
214
        }
215
216
        foreach (static::$initCallbacks as $callback) {
217
            call_user_func($callback, $this);
218
        }
219
    }
220
221
    /**
222
     * Get or set option for grid.
223
     *
224
     * @param string $key
225
     * @param mixed  $value
226
     *
227
     * @return $this|mixed
228
     */
229
    public function option($key, $value = null)
230
    {
231
        if (is_null($value)) {
232
            return $this->options[$key];
233
        }
234
235
        $this->options[$key] = $value;
236
237
        return $this;
238
    }
239
240
    /**
241
     * Get primary key name of model.
242
     *
243
     * @return string
244
     */
245
    public function getKeyName()
246
    {
247
        return $this->keyName ?: 'id';
248
    }
249
250
    /**
251
     * Add a column to Grid.
252
     *
253
     * @param string $name
254
     * @param string $label
255
     *
256
     * @return Column
257
     */
258
    public function column($name, $label = '')
259
    {
260
        if (Str::contains($name, '.')) {
261
            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 261 which is incompatible with the return type documented by Encore\Admin\Grid::column of type Encore\Admin\Grid\Column.
Loading history...
262
        }
263
264
        if (Str::contains($name, '->')) {
265
            return $this->addJsonColumn($name, $label);
266
        }
267
268
        return $this->__call($name, array_filter([$label]));
269
    }
270
271
    /**
272
     * Batch add column to grid.
273
     *
274
     * @example
275
     * 1.$grid->columns(['name' => 'Name', 'email' => 'Email' ...]);
276
     * 2.$grid->columns('name', 'email' ...)
277
     *
278
     * @param array $columns
279
     *
280
     * @return Collection|null
281
     */
282
    public function columns($columns = [])
283
    {
284
        if (func_num_args() == 0) {
285
            return $this->columns;
286
        }
287
288
        if (func_num_args() == 1 && is_array($columns)) {
289
            foreach ($columns as $column => $label) {
290
                $this->column($column, $label);
291
            }
292
293
            return;
294
        }
295
296
        foreach (func_get_args() as $column) {
297
            $this->column($column);
298
        }
299
    }
300
301
    /**
302
     * Add column to grid.
303
     *
304
     * @param string $column
305
     * @param string $label
306
     *
307
     * @return Column
308
     */
309 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...
310
    {
311
        $column = new Column($column, $label);
312
        $column->setGrid($this);
313
314
        return tap($column, function ($value) {
315
            $this->columns->push($value);
316
        });
317
    }
318
319
    /**
320
     * Get all columns object.
321
     *
322
     * @return Collection
323
     */
324
    public function getColumns()
325
    {
326
        return $this->columns;
327
    }
328
329
    /**
330
     * Add a relation column to grid.
331
     *
332
     * @param string $name
333
     * @param string $label
334
     *
335
     * @return $this|bool|Column
336
     */
337
    protected function addRelationColumn($name, $label = '')
338
    {
339
        list($relation, $column) = explode('.', $name);
340
341
        $model = $this->model()->eloquent();
0 ignored issues
show
Bug introduced by
The method eloquent does only exist in Encore\Admin\Grid\Model, but not in Illuminate\Database\Eloquent\Builder.

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...
342
343
        if (!method_exists($model, $relation) || !$model->{$relation}() instanceof Relations\Relation) {
344
            $class = get_class($model);
345
346
            admin_error("Call to undefined relationship [{$relation}] on model [{$class}].");
347
348
            return $this;
349
        }
350
351
        $name = ($this->shouldSnakeAttributes() ? Str::snake($relation) : $relation).'.'.$column;
352
353
        $this->model()->with($relation);
354
355
        return $this->addColumn($name, $label)->setRelation($relation, $column);
356
    }
357
358
    /**
359
     * Add a json type column to grid.
360
     *
361
     * @param string $name
362
     * @param string $label
363
     *
364
     * @return Column
365
     */
366
    protected function addJsonColumn($name, $label = '')
367
    {
368
        $column = substr($name, strrpos($name, '->') + 2);
369
370
        $name = str_replace('->', '.', $name);
371
372
        return $this->addColumn($name, $label ?: ucfirst($column));
373
    }
374
375
    /**
376
     * Prepend column to grid.
377
     *
378
     * @param string $column
379
     * @param string $label
380
     *
381
     * @return Column
382
     */
383 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...
384
    {
385
        $column = new Column($column, $label);
386
        $column->setGrid($this);
387
388
        return tap($column, function ($value) {
389
            $this->columns->prepend($value);
390
        });
391
    }
392
393
    /**
394
     * Get Grid model.
395
     *
396
     * @return Model|\Illuminate\Database\Eloquent\Builder
397
     */
398
    public function model()
399
    {
400
        return $this->model;
401
    }
402
403
    /**
404
     * Paginate the grid.
405
     *
406
     * @param int $perPage
407
     *
408
     * @return void
409
     */
410
    public function paginate($perPage = 20)
411
    {
412
        $this->perPage = $perPage;
413
414
        $this->model()->setPerPage($perPage);
0 ignored issues
show
Bug introduced by
The method setPerPage does only exist in Encore\Admin\Grid\Model, but not in Illuminate\Database\Eloquent\Builder.

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...
415
    }
416
417
    /**
418
     * Get the grid paginator.
419
     *
420
     * @return mixed
421
     */
422
    public function paginator()
423
    {
424
        return new Tools\Paginator($this);
425
    }
426
427
    /**
428
     * Disable grid pagination.
429
     *
430
     * @return $this
431
     */
432
    public function disablePagination(bool $disable = true)
433
    {
434
        $this->model->usePaginate(!$disable);
0 ignored issues
show
Bug introduced by
The method usePaginate does only exist in Encore\Admin\Grid\Model, but not in Illuminate\Database\Eloquent\Builder.

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...
435
436
        return $this->option('show_pagination', !$disable);
437
    }
438
439
    /**
440
     * If this grid use pagination.
441
     *
442
     * @return bool
443
     */
444
    public function showPagination()
445
    {
446
        return $this->option('show_pagination');
447
    }
448
449
    /**
450
     * Set per-page options.
451
     *
452
     * @param array $perPages
453
     */
454
    public function perPages(array $perPages)
455
    {
456
        $this->perPages = $perPages;
457
    }
458
459
    /**
460
     * Disable row selector.
461
     *
462
     * @return Grid|mixed
463
     */
464
    public function disableRowSelector(bool $disable = true)
465
    {
466
        return $this->disableBatchActions($disable);
467
    }
468
469
    /**
470
     * Prepend checkbox column for grid.
471
     *
472
     * @return void
473
     */
474
    protected function prependRowSelectorColumn()
475
    {
476
        if (!$this->option('show_row_selector')) {
477
            return;
478
        }
479
480
        $checkAllBox = "<input type=\"checkbox\" class=\"{$this->getSelectAllName()}\" />&nbsp;";
481
482
        $this->prependColumn(Column::SELECT_COLUMN_NAME, ' ')
483
            ->displayUsing(Displayers\RowSelector::class)
484
            ->addHeader($checkAllBox);
485
    }
486
487
    /**
488
     * Apply column filter to grid query.
489
     *
490
     * @return void
491
     */
492
    protected function applyColumnFilter()
493
    {
494
        $this->columns->each->bindFilterQuery($this->model());
495
    }
496
497
    /**
498
     * Apply column search to grid query.
499
     *
500
     * @return void
501
     */
502
    protected function applyColumnSearch()
503
    {
504
        $this->columns->each->bindSearchQuery($this->model());
505
    }
506
507
    /**
508
     * @return array|Collection|mixed
509
     */
510
    public function applyQuery()
511
    {
512
        $this->applyQuickSearch();
513
514
        $this->applyColumnFilter();
515
516
        $this->applyColumnSearch();
517
518
        $this->applySelectorQuery();
519
    }
520
521
    /**
522
     * Add row selector columns and action columns before and after the grid.
523
     *
524
     * @return void
525
     */
526
    protected function addDefaultColumns()
527
    {
528
        $this->prependRowSelectorColumn();
529
530
        $this->appendActionsColumn();
531
    }
532
533
    /**
534
     * Build the grid.
535
     *
536
     * @return void
537
     */
538
    public function build()
539
    {
540
        if ($this->builded) {
541
            return;
542
        }
543
544
        $this->applyQuery();
545
546
        $collection = $this->applyFilter(false);
547
548
        $this->addDefaultColumns();
549
550
        Column::setOriginalGridModels($collection);
551
552
        $data = $collection->toArray();
553
554
        $this->columns->map(function (Column $column) use (&$data) {
555
            $data = $column->fill($data);
556
557
            $this->columnNames[] = $column->getName();
558
        });
559
560
        $this->buildRows($data);
561
562
        $this->builded = true;
563
    }
564
565
    /**
566
     * Build the grid rows.
567
     *
568
     * @param array $data
569
     *
570
     * @return void
571
     */
572
    protected function buildRows(array $data)
573
    {
574
        $this->rows = collect($data)->map(function ($model, $number) {
575
            return new Row($number, $model, $this->keyName);
576
        });
577
578
        if ($this->rowsCallback) {
579
            $this->rows->map($this->rowsCallback);
580
        }
581
    }
582
583
    /**
584
     * Set grid row callback function.
585
     *
586
     * @param Closure $callable
587
     *
588
     * @return Collection|null
589
     */
590
    public function rows(Closure $callable = null)
591
    {
592
        if (is_null($callable)) {
593
            return $this->rows;
594
        }
595
596
        $this->rowsCallback = $callable;
597
    }
598
599
    /**
600
     * Get create url.
601
     *
602
     * @return string
603
     */
604
    public function getCreateUrl()
605
    {
606
        $queryString = '';
607
608
        if ($constraints = $this->model()->getConstraints()) {
0 ignored issues
show
Bug introduced by
The method getConstraints does only exist in Encore\Admin\Grid\Model, but not in Illuminate\Database\Eloquent\Builder.

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...
609
            $queryString = http_build_query($constraints);
610
        }
611
612
        return sprintf(
613
            '%s/create%s',
614
            $this->resource(),
615
            $queryString ? ('?'.$queryString) : ''
616
        );
617
    }
618
619
    /**
620
     * Alias for method `disableCreateButton`.
621
     *
622
     * @return $this
623
     *
624
     * @deprecated
625
     */
626
    public function disableCreation()
627
    {
628
        return $this->disableCreateButton();
629
    }
630
631
    /**
632
     * Remove create button on grid.
633
     *
634
     * @return $this
635
     */
636
    public function disableCreateButton(bool $disable = true)
637
    {
638
        return $this->option('show_create_btn', !$disable);
639
    }
640
641
    /**
642
     * Remove define empty page on grid.
643
     *
644
     * @return $this
645
     */
646
    public function disableDefineEmptyPage(bool $disable = true)
647
    {
648
        return $this->option('show_define_empty_page', !$disable);
649
    }
650
651
    /**
652
     * If grid show define empty page on grid.
653
     *
654
     * @return bool
655
     */
656
    public function showDefineEmptyPage()
657
    {
658
        return $this->option('show_define_empty_page');
659
    }
660
661
    /**
662
     * If allow creation.
663
     *
664
     * @return bool
665
     */
666
    public function showCreateBtn()
667
    {
668
        return $this->option('show_create_btn');
669
    }
670
671
    /**
672
     * Render create button for grid.
673
     *
674
     * @return string
675
     */
676
    public function renderCreateButton()
677
    {
678
        return (new Tools\CreateButton($this))->render();
679
    }
680
681
    /**
682
     * Get current resource url.
683
     *
684
     * @param string $path
685
     *
686
     * @return string
687
     */
688
    public function resource($path = null)
689
    {
690
        if (!empty($path)) {
691
            $this->resourcePath = $path;
692
693
            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...
694
        }
695
696
        if (!empty($this->resourcePath)) {
697
            return $this->resourcePath;
698
        }
699
700
        return url(app('request')->getPathInfo());
0 ignored issues
show
Bug Compatibility introduced by
The expression url(app('request')->getPathInfo()); of type Illuminate\Contracts\Routing\UrlGenerator|string adds the type Illuminate\Contracts\Routing\UrlGenerator to the return on line 700 which is incompatible with the return type documented by Encore\Admin\Grid::resource of type string.
Loading history...
701
    }
702
703
    /**
704
     * Handle get mutator column for grid.
705
     *
706
     * @param string $method
707
     * @param string $label
708
     *
709
     * @return bool|Column
710
     */
711
    protected function handleGetMutatorColumn($method, $label)
712
    {
713
        if ($this->model()->eloquent()->hasGetMutator($method)) {
0 ignored issues
show
Bug introduced by
The method eloquent does only exist in Encore\Admin\Grid\Model, but not in Illuminate\Database\Eloquent\Builder.

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...
714
            return $this->addColumn($method, $label);
715
        }
716
717
        return false;
718
    }
719
720
    /**
721
     * Handle relation column for grid.
722
     *
723
     * @param string $method
724
     * @param string $label
725
     *
726
     * @return bool|Column
727
     */
728
    protected function handleRelationColumn($method, $label)
729
    {
730
        $model = $this->model()->eloquent();
0 ignored issues
show
Bug introduced by
The method eloquent does only exist in Encore\Admin\Grid\Model, but not in Illuminate\Database\Eloquent\Builder.

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...
731
732
        if (!method_exists($model, $method)) {
733
            return false;
734
        }
735
736
        if (!($relation = $model->$method()) instanceof Relations\Relation) {
737
            return false;
738
        }
739
740
        if ($relation instanceof Relations\HasOne ||
741
            $relation instanceof Relations\BelongsTo ||
742
            $relation instanceof Relations\MorphOne
743
        ) {
744
            $this->model()->with($method);
745
746
            return $this->addColumn($method, $label)->setRelation(
747
                $this->shouldSnakeAttributes() ? Str::snake($method) : $method
748
            );
749
        }
750
751
        if ($relation instanceof Relations\HasMany
752
            || $relation instanceof Relations\BelongsToMany
753
            || $relation instanceof Relations\MorphToMany
754
            || $relation instanceof Relations\HasManyThrough
755
        ) {
756
            $this->model()->with($method);
757
758
            return $this->addColumn($this->shouldSnakeAttributes() ? Str::snake($method) : $method, $label);
759
        }
760
761
        return false;
762
    }
763
764
    /**
765
     * Dynamically add columns to the grid view.
766
     *
767
     * @param $method
768
     * @param $arguments
769
     *
770
     * @return Column
771
     */
772
    public function __call($method, $arguments)
773
    {
774
        if (static::hasMacro($method)) {
775
            return $this->macroCall($method, $arguments);
776
        }
777
778
        $label = $arguments[0] ?? null;
779
780
        if ($this->model()->eloquent() instanceof MongodbModel) {
0 ignored issues
show
Bug introduced by
The method eloquent does only exist in Encore\Admin\Grid\Model, but not in Illuminate\Database\Eloquent\Builder.

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...
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...
781
            return $this->addColumn($method, $label);
782
        }
783
784
        if ($column = $this->handleGetMutatorColumn($method, $label)) {
785
            return $column;
786
        }
787
788
        if ($column = $this->handleRelationColumn($method, $label)) {
789
            return $column;
790
        }
791
792
        return $this->addColumn($method, $label);
793
    }
794
795
    /**
796
     * Add variables to grid view.
797
     *
798
     * @param array $variables
799
     *
800
     * @return $this
801
     */
802
    public function with($variables = [])
803
    {
804
        $this->variables = $variables;
805
806
        return $this;
807
    }
808
809
    /**
810
     * Get all variables will used in grid view.
811
     *
812
     * @return array
813
     */
814
    protected function variables()
815
    {
816
        $this->variables['grid'] = $this;
817
818
        return $this->variables;
819
    }
820
821
    /**
822
     * Set a view to render.
823
     *
824
     * @param string $view
825
     * @param array  $variables
826
     */
827
    public function setView($view, $variables = [])
828
    {
829
        if (!empty($variables)) {
830
            $this->with($variables);
831
        }
832
833
        $this->view = $view;
834
    }
835
836
    /**
837
     * Set grid title.
838
     *
839
     * @param string $title
840
     *
841
     * @return $this
842
     */
843
    public function setTitle($title)
844
    {
845
        $this->variables['title'] = $title;
846
847
        return $this;
848
    }
849
850
    /**
851
     * Set relation for grid.
852
     *
853
     * @param Relations\Relation $relation
854
     *
855
     * @return $this
856
     */
857
    public function setRelation(Relations\Relation $relation)
858
    {
859
        $this->model()->setRelation($relation);
0 ignored issues
show
Bug introduced by
The method setRelation does only exist in Encore\Admin\Grid\Model, but not in Illuminate\Database\Eloquent\Builder.

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...
860
861
        return $this;
862
    }
863
864
    /**
865
     * Set resource path for grid.
866
     *
867
     * @param string $path
868
     *
869
     * @return $this
870
     */
871
    public function setResource($path)
872
    {
873
        $this->resourcePath = $path;
874
875
        return $this;
876
    }
877
878
    /**
879
     * Set rendering callback.
880
     *
881
     * @param callable $callback
882
     *
883
     * @return $this
884
     */
885
    public function rendering(callable $callback)
886
    {
887
        $this->renderingCallbacks[] = $callback;
888
889
        return $this;
890
    }
891
892
    /**
893
     * Call callbacks before render.
894
     *
895
     * @return void
896
     */
897
    protected function callRenderingCallback()
898
    {
899
        foreach ($this->renderingCallbacks as $callback) {
900
            call_user_func($callback, $this);
901
        }
902
    }
903
904
    /**
905
     * Get the string contents of the grid view.
906
     *
907
     * @return string
908
     */
909
    public function render()
910
    {
911
        $this->handleExportRequest(true);
912
913
        try {
914
            $this->build();
915
        } catch (\Exception $e) {
916
            return Handler::renderException($e);
917
        }
918
919
        $this->callRenderingCallback();
920
921
        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...
922
    }
923
}
924