Completed
Push — master ( addbc6...6731dd )
by Song
02:29
created

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