Completed
Push — master ( 648aa9...3341b8 )
by Song
03:51
created

Grid::disableActions()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
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\Handle;
7
use Encore\Admin\Grid\Column;
8
use Encore\Admin\Grid\Exporter;
9
use Encore\Admin\Grid\Filter;
10
use Encore\Admin\Grid\Model;
11
use Encore\Admin\Grid\Row;
12
use Encore\Admin\Pagination\AdminThreePresenter;
13
use Illuminate\Database\Eloquent\Model as Eloquent;
14
use Illuminate\Database\Eloquent\Relations\BelongsTo;
15
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
16
use Illuminate\Database\Eloquent\Relations\HasMany;
17
use Illuminate\Database\Eloquent\Relations\HasOne;
18
use Illuminate\Database\Eloquent\Relations\MorphToMany;
19
use Illuminate\Database\Eloquent\Relations\Relation;
20
use Illuminate\Support\Collection;
21
use Illuminate\Support\Facades\Input;
22
use Illuminate\Support\Facades\Schema;
23
use Jenssegers\Mongodb\Eloquent\Model as MongodbModel;
24
25
class Grid
26
{
27
    /**
28
     * The grid data model instance.
29
     *
30
     * @var \Encore\Admin\Grid\Model
31
     */
32
    protected $model;
33
34
    /**
35
     * Collection of all grid columns.
36
     *
37
     * @var \Illuminate\Support\Collection
38
     */
39
    protected $columns;
40
41
    /**
42
     * Collection of all data rows.
43
     *
44
     * @var \Illuminate\Support\Collection
45
     */
46
    protected $rows;
47
48
    /**
49
     * Rows callable fucntion.
50
     *
51
     * @var \Closure
52
     */
53
    protected $rowsCallback;
54
55
    /**
56
     * All column names of the grid.
57
     *
58
     * @var array
59
     */
60
    public $columnNames = [];
61
62
    /**
63
     * Grid builder.
64
     *
65
     * @var \Closure
66
     */
67
    protected $builder;
68
69
    /**
70
     * Mark if the grid is builded.
71
     *
72
     * @var bool
73
     */
74
    protected $builded = false;
75
76
    /**
77
     * All variables in grid view.
78
     *
79
     * @var array
80
     */
81
    protected $variables = [];
82
83
    /**
84
     * The grid Filter.
85
     *
86
     * @var \Encore\Admin\Grid\Filter
87
     */
88
    protected $filter;
89
90
    /**
91
     * Resource path of the grid.
92
     *
93
     * @var
94
     */
95
    protected $resourcePath;
96
97
    /**
98
     * Default primary key name.
99
     *
100
     * @var string
101
     */
102
    protected $keyName = 'id';
103
104
    /**
105
     * Allow batch allow.
106
     *
107
     * @var bool
108
     */
109
    protected $allowBatchDeletion = true;
110
111
    /**
112
     * Allow actions.
113
     *
114
     * @var bool
115
     */
116
    protected $allowActions = true;
117
118
    /**
119
     * @var Exporter
120
     */
121
    protected $exporter;
122
123
    /**
124
     * Create a new grid instance.
125
     *
126
     * @param Eloquent $model
127
     * @param callable $builder
128
     */
129
    public function __construct(Eloquent $model, Closure $builder)
130
    {
131
        $this->keyName = $model->getKeyName();
132
        $this->model = new Model($model);
133
        $this->columns = new Collection();
134
        $this->rows = new Collection();
135
        $this->builder = $builder;
136
137
        $this->setupFilter();
138
        $this->setupExporter();
139
    }
140
141
    /**
142
     * Add column to Grid.
143
     *
144
     * @param string $name
145
     * @param string $label
146
     *
147
     * @return Column
148
     */
149
    public function column($name, $label = '')
150
    {
151
        $relationName = $relationColumn = '';
152
153
        if (strpos($name, '.') !== false) {
154
            list($relationName, $relationColumn) = explode('.', $name);
155
156
            $relation = $this->model()->eloquent()->$relationName();
157
158
            $label = empty($label) ? ucfirst($relationColumn) : $label;
159
        }
160
161
        $column = $this->addColumn($name, $label);
162
163
        if (isset($relation) && $relation instanceof Relation) {
164
            $this->model()->with($relationName);
0 ignored issues
show
Documentation Bug introduced by
The method with does not exist on object<Encore\Admin\Grid\Model>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
165
            $column->setRelation($relation, $relationColumn);
0 ignored issues
show
Unused Code introduced by
The call to Column::setRelation() has too many arguments starting with $relationColumn.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
166
        }
167
168
        return $column;
169
    }
170
171
    /**
172
     * Batch add column to grid.
173
     *
174
     * @example
175
     * 1.$grid->columns(['name' => 'Name', 'email' => 'Email' ...]);
176
     * 2.$grid->columns('name', 'email' ...)
177
     *
178
     * @param array $columns
179
     *
180
     * @return Collection|void
181
     */
182
    public function columns($columns = [])
183
    {
184
        if (func_num_args() == 0) {
185
            return $this->columns;
186
        }
187
188
        if (func_num_args() == 1 && is_array($columns)) {
189
            foreach ($columns as $column => $label) {
190
                $this->column($column, $label);
191
            }
192
193
            return;
194
        }
195
196
        foreach (func_get_args() as $column) {
197
            $this->column($column);
198
        }
199
    }
200
201
    /**
202
     * Add column to grid.
203
     *
204
     * @param string $column
205
     * @param string $label
206
     *
207
     * @return Column
208
     */
209
    protected function addColumn($column = '', $label = '')
210
    {
211
        //$label = $label ?: Str::upper($column);
0 ignored issues
show
Unused Code Comprehensibility introduced by
57% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
212
213
        return $this->columns[] = new Column($column, $label);
214
    }
215
216
    public function blank($label)
217
    {
218
        return $this->addColumn('blank', $label);
219
    }
220
221
    /**
222
     * Get Grid model.
223
     *
224
     * @return Model
225
     */
226
    public function model()
227
    {
228
        return $this->model;
229
    }
230
231
    /**
232
     * Paginate the grid.
233
     *
234
     * @param int $perPage
235
     *
236
     * @return void
237
     */
238
    public function paginate($perPage = null)
239
    {
240
        $this->model()->paginate($perPage);
0 ignored issues
show
Bug introduced by
The method paginate() does not exist on Encore\Admin\Grid\Model. Did you maybe mean setPaginate()?

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

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

Loading history...
241
    }
242
243
    /**
244
     * Get the grid paginator.
245
     *
246
     * @return mixed
247
     */
248
    public function paginator()
249
    {
250
        $query = Input::all();
251
252
        return $this->model()->eloquent()->appends($query)->render(
253
            new AdminThreePresenter($this->model()->eloquent())
0 ignored issues
show
Documentation introduced by
$this->model()->eloquent() is of type object<Illuminate\Database\Eloquent\Model>, but the function expects a object<Illuminate\Contracts\Pagination\Paginator>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
254
        );
255
    }
256
257
    /**
258
     * Build the grid.
259
     *
260
     * @return void
261
     */
262
    public function build()
263
    {
264
        if ($this->builded) {
265
            return;
266
        }
267
268
        call_user_func($this->builder, $this);
269
270
        $data = $this->filter->execute();
271
272
        $this->columns->map(function (Column $column) use (&$data) {
273
            $data = $column->map($data);
274
275
            $this->columnNames[] = $column->getName();
276
        });
277
278
        $this->buildRows($data);
279
280
        $this->builded = true;
281
    }
282
283
    /**
284
     * Build the grid rows.
285
     *
286
     * @param array $data
287
     *
288
     * @return void
289
     */
290
    protected function buildRows(array $data)
291
    {
292
        $this->rows = collect($data)->map(function ($val, $key) {
293
            $row = new Row($key, $val);
294
295
            $row->setKeyName($this->keyName);
296
            $row->setPath($this->resource());
297
298
            return $row;
299
        });
300
301
        if ($this->rowsCallback) {
302
            $this->rows->map($this->rowsCallback);
303
        }
304
    }
305
306
    /**
307
     * Set grid row callback function.
308
     *
309
     * @param callable $callable
310
     *
311
     * @return Collection|void
312
     */
313
    public function rows(Closure $callable = null)
314
    {
315
        if (is_null($callable)) {
316
            return $this->rows;
317
        }
318
319
        $this->rowsCallback = $callable;
320
    }
321
322
    /**
323
     * Setup grid filter.
324
     *
325
     * @return void
326
     */
327
    protected function setupFilter()
328
    {
329
        $this->filter = new Filter($this->model());
330
    }
331
332
    /**
333
     * Setup grid exporter.
334
     *
335
     * @return void
336
     */
337
    protected function setupExporter()
338
    {
339
        $this->exporter = new Exporter($this);
340
    }
341
342
    /**
343
     * If allow batch delete.
344
     *
345
     * @return bool
346
     */
347
    public function allowBatchDeletion()
348
    {
349
        return $this->allowBatchDeletion;
350
    }
351
352
    /**
353
     * Disable batch deletion.
354
     */
355
    public function disableBatchDeletion()
356
    {
357
        $this->allowBatchDeletion = false;
358
    }
359
360
    /**
361
     * If allow actions.
362
     *
363
     * @return bool
364
     */
365
    public function allowActions()
366
    {
367
        return $this->allowActions;
368
    }
369
370
    /**
371
     * Disable all actions.
372
     */
373
    public function disableActions()
374
    {
375
        $this->allowActions = false;
376
    }
377
378
    /**
379
     * Set the grid filter.
380
     *
381
     * @param callable $callback
382
     */
383
    public function filter(Closure $callback)
384
    {
385
        call_user_func($callback, $this->filter);
386
    }
387
388
    /**
389
     * Render the grid filter.
390
     *
391
     * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
392
     */
393
    public function renderFilter()
394
    {
395
        return $this->filter->render();
396
    }
397
398
    /**
399
     * Get current resource uri.
400
     *
401
     * @param string $path
402
     *
403
     * @return string
404
     */
405
    public function resource($path = null)
406
    {
407
        if (!empty($path)) {
408
            $this->resourcePath = $path;
409
410
            return $this;
411
        }
412
413
        if (!empty($this->resourcePath)) {
414
            return $this->resourcePath;
415
        }
416
417
        return app('router')->current()->getPath();
418
    }
419
420
    public function pathOfCreate()
421
    {
422
        $path = $query = '';
423
424
        extract(parse_url($this->resource()));
0 ignored issues
show
Bug introduced by
parse_url($this->resource()) cannot be passed to extract() as the parameter $var_array expects a reference.
Loading history...
425
426
        return '/'.trim($path, '/').'/create'.$query;
427
    }
428
429
    /**
430
     * Add variables to grid view.
431
     *
432
     * @param array $variables
433
     *
434
     * @return $this
435
     */
436
    public function with($variables = [])
437
    {
438
        $this->variables = $variables;
439
440
        return $this;
441
    }
442
443
    /**
444
     * Get all variables will used in grid view.
445
     *
446
     * @return array
447
     */
448
    protected function variables()
449
    {
450
        $this->variables['grid'] = $this;
451
452
        return $this->variables;
453
    }
454
455
    /**
456
     * Get the string contents of the grid view.
457
     *
458
     * @return string
459
     */
460
    public function render()
461
    {
462
        try {
463
            $this->build();
464
        } catch (\Exception $e) {
465
            return with(new Handle($e))->render();
466
        }
467
468
        return view('admin::grid', $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...
469
    }
470
471
    /**
472
     * Dynamically add columns to the grid view.
473
     *
474
     * @param $method
475
     * @param $arguments
476
     *
477
     * @return $this|Column
478
     */
479
    public function __call($method, $arguments)
480
    {
481
        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...
482
            $label = isset($arguments[0]) ? $arguments[0] : ucfirst($method);
483
484
            return $this->addColumn($method, $label);
485
        }
486
487
        $connection = $this->model()->eloquent()->getConnectionName();
488
        if (Schema::connection($connection)->hasColumn($this->model()->getTable(), $method)) {
489
            $label = isset($arguments[0]) ? $arguments[0] : ucfirst($method);
490
491
            return $this->addColumn($method, $label);
492
        }
493
494
        $relation = $this->model()->eloquent()->$method();
495
496
        if ($relation instanceof HasOne || $relation instanceof BelongsTo) {
497
            $this->model()->with($method);
0 ignored issues
show
Documentation Bug introduced by
The method with does not exist on object<Encore\Admin\Grid\Model>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
498
499
            return $this->addColumn()->setRelation($method);
500
        }
501
502
        if ($relation instanceof HasMany || $relation instanceof BelongsToMany || $relation instanceof MorphToMany) {
503
            $this->model()->with($method);
0 ignored issues
show
Documentation Bug introduced by
The method with does not exist on object<Encore\Admin\Grid\Model>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
504
505
            return $this->addColumn($method);
506
        }
507
    }
508
509
    /**
510
     * Get the string contents of the grid view.
511
     *
512
     * @return string
513
     */
514
    public function __toString()
515
    {
516
        return $this->render();
517
    }
518
}
519