Completed
Push — master ( 515aaa...169b7e )
by Song
02:36
created

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