Completed
Push — master ( 3a6a8b...8c64c3 )
by Song
02:41
created

Column::filesize()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 0
dl 0
loc 6
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Encore\Admin\Grid;
4
5
use Carbon\Carbon;
6
use Closure;
7
use Encore\Admin\Admin;
8
use Encore\Admin\Grid;
9
use Encore\Admin\Grid\Displayers\AbstractDisplayer;
10
use Illuminate\Contracts\Support\Arrayable;
11
use Illuminate\Database\Eloquent\Model;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, Encore\Admin\Grid\Model.

Let’s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let’s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
12
use Illuminate\Support\Arr;
13
use Illuminate\Support\Collection;
14
use Illuminate\Support\Str;
15
16
/**
17
 * Class Column.
18
 *
19
 * @method Displayers\Editable      editable()
20
 * @method Displayers\SwitchDisplay switch ($states = [])
21
 * @method Displayers\SwitchGroup   switchGroup($columns = [], $states = [])
22
 * @method Displayers\Select        select($options = [])
23
 * @method Displayers\Image         image($server = '', $width = 200, $height = 200)
24
 * @method Displayers\Label         label($style = 'success')
25
 * @method Displayers\Button        button($style = null)
26
 * @method Displayers\Link          link($href = '', $target = '_blank')
27
 * @method Displayers\Badge         badge($style = 'red')
28
 * @method Displayers\ProgressBar   progressBar($style = 'primary', $size = 'sm', $max = 100)
29
 * @method Displayers\Radio         radio($options = [])
30
 * @method Displayers\Checkbox      checkbox($options = [])
31
 * @method Displayers\Orderable     orderable($column, $label = '')
32
 * @method Displayers\Table         table($titles = [])
33
 * @method Displayers\Expand        expand($callback = null)
34
 * @method Displayers\Modal         modal($callback = null)
35
 * @method Displayers\Carousel      carousel(int $width = 300, int $height = 200, $server = '')
36
 * @method Displayers\Download      download($server = '')
37
 */
38
class Column
39
{
40
    const SELECT_COLUMN_NAME = '__row_selector__';
41
42
    const ACTION_COLUMN_NAME = '__actions__';
43
44
    /**
45
     * @var Grid
46
     */
47
    protected $grid;
48
49
    /**
50
     * Name of column.
51
     *
52
     * @var string
53
     */
54
    protected $name;
55
56
    /**
57
     * Label of column.
58
     *
59
     * @var string
60
     */
61
    protected $label;
62
63
    /**
64
     * Original value of column.
65
     *
66
     * @var mixed
67
     */
68
    protected $original;
69
70
    /**
71
     * Is column sortable.
72
     *
73
     * @var bool
74
     */
75
    protected $sortable = false;
76
77
    /**
78
     * Sort arguments.
79
     *
80
     * @var array
81
     */
82
    protected $sort;
83
84
    /**
85
     * Help message.
86
     *
87
     * @var string
88
     */
89
    protected $help = '';
90
91
    /**
92
     * Cast Name.
93
     *
94
     * @var array
95
     */
96
    protected $cast;
97
98
    /**
99
     * Attributes of column.
100
     *
101
     * @var array
102
     */
103
    protected $attributes = [];
104
105
    /**
106
     * Relation name.
107
     *
108
     * @var bool
109
     */
110
    protected $relation = false;
111
112
    /**
113
     * Relation column.
114
     *
115
     * @var string
116
     */
117
    protected $relationColumn;
118
119
    /**
120
     * Original grid data.
121
     *
122
     * @var Collection
123
     */
124
    protected static $originalGridModels;
125
126
    /**
127
     * @var []Closure
128
     */
129
    protected $displayCallbacks = [];
130
131
    /**
132
     * Displayers for grid column.
133
     *
134
     * @var array
135
     */
136
    public static $displayers = [];
137
138
    /**
139
     * Defined columns.
140
     *
141
     * @var array
142
     */
143
    public static $defined = [];
144
145
    /**
146
     * @var array
147
     */
148
    protected static $htmlAttributes = [];
149
150
    /**
151
     * @var Model
152
     */
153
    protected static $model;
154
155
    /**
156
     * @param string $name
157
     * @param string $label
158
     */
159
    public function __construct($name, $label)
160
    {
161
        $this->name = $name;
162
163
        $this->label = $this->formatLabel($label);
164
    }
165
166
    /**
167
     * Extend column displayer.
168
     *
169
     * @param $name
170
     * @param $displayer
171
     */
172
    public static function extend($name, $displayer)
173
    {
174
        static::$displayers[$name] = $displayer;
175
    }
176
177
    /**
178
     * Define a column globally.
179
     *
180
     * @param string $name
181
     * @param mixed  $definition
182
     */
183
    public static function define($name, $definition)
184
    {
185
        static::$defined[$name] = $definition;
186
    }
187
188
    /**
189
     * Set grid instance for column.
190
     *
191
     * @param Grid $grid
192
     */
193
    public function setGrid(Grid $grid)
194
    {
195
        $this->grid = $grid;
196
197
        $this->setModel($grid->model()->eloquent());
198
    }
199
200
    /**
201
     * Set model for column.
202
     *
203
     * @param $model
204
     */
205
    public function setModel($model)
206
    {
207
        if (is_null(static::$model) && ($model instanceof Model)) {
208
            static::$model = $model->newInstance();
209
        }
210
    }
211
212
    /**
213
     * Set original data for column.
214
     *
215
     * @param Collection $collection
216
     */
217
    public static function setOriginalGridModels(Collection $collection)
218
    {
219
        static::$originalGridModels = $collection;
220
    }
221
222
    /**
223
     * Set column attributes.
224
     *
225
     * @param array $attributes
226
     *
227
     * @return $this
228
     */
229
    public function setAttributes($attributes = [])
230
    {
231
        static::$htmlAttributes[$this->name] = $attributes;
232
233
        return $this;
234
    }
235
236
    /**
237
     * Get column attributes.
238
     *
239
     * @param string $name
240
     *
241
     * @return mixed
242
     */
243
    public static function getAttributes($name)
244
    {
245
        return Arr::get(static::$htmlAttributes, $name, '');
246
    }
247
248
    /**
249
     * Set style of this column.
250
     *
251
     * @param string $style
252
     *
253
     * @return $this
254
     */
255
    public function style($style)
256
    {
257
        return $this->setAttributes(compact('style'));
258
    }
259
260
    /**
261
     * Set the width of column.
262
     *
263
     * @param int $width
264
     *
265
     * @return $this
266
     */
267
    public function width(int $width)
268
    {
269
        return $this->style("width: {$width}px;");
270
    }
271
272
    /**
273
     * Set the color of column.
274
     *
275
     * @param string $color
276
     *
277
     * @return $this
278
     */
279
    public function color($color)
280
    {
281
        return $this->style("color:$color;");
282
    }
283
284
    /**
285
     * Get name of this column.
286
     *
287
     * @return mixed
288
     */
289
    public function getName()
290
    {
291
        return $this->name;
292
    }
293
294
    /**
295
     * Format label.
296
     *
297
     * @param $label
298
     *
299
     * @return mixed
300
     */
301
    protected function formatLabel($label)
302
    {
303
        if ($label) {
304
            return $label;
305
        }
306
307
        $label = ucfirst($this->name);
308
309
        return __(str_replace(['.', '_'], ' ', $label));
310
    }
311
312
    /**
313
     * Get label of the column.
314
     *
315
     * @return mixed
316
     */
317
    public function getLabel()
318
    {
319
        return $this->label;
320
    }
321
322
    /**
323
     * Set relation.
324
     *
325
     * @param string $relation
326
     * @param string $relationColumn
327
     *
328
     * @return $this
329
     */
330
    public function setRelation($relation, $relationColumn = null)
331
    {
332
        $this->relation = $relation;
0 ignored issues
show
Documentation Bug introduced by
The property $relation was declared of type boolean, but $relation is of type string. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
333
        $this->relationColumn = $relationColumn;
334
335
        return $this;
336
    }
337
338
    /**
339
     * If this column is relation column.
340
     *
341
     * @return bool
342
     */
343
    protected function isRelation()
344
    {
345
        return (bool) $this->relation;
346
    }
347
348
    /**
349
     * Set sort value.
350
     *
351
     * @param bool $sort
352
     *
353
     * @return $this
354
     */
355
    public function sort($sort)
356
    {
357
        $this->sortable = $sort;
358
359
        return $this;
360
    }
361
362
    /**
363
     * Mark this column as sortable.
364
     *
365
     * @return $this
366
     */
367
    public function sortable()
368
    {
369
        return $this->sort(true);
370
    }
371
372
    /**
373
     * Set cast name for sortable.
374
     *
375
     * @return $this
376
     */
377
    public function cast($cast)
378
    {
379
        $this->cast = $cast;
380
381
        return $this;
382
    }
383
384
    /**
385
     * Add a display callback.
386
     *
387
     * @param Closure $callback
388
     *
389
     * @return $this
390
     */
391
    public function display(Closure $callback)
392
    {
393
        $this->displayCallbacks[] = $callback;
394
395
        return $this;
396
    }
397
398
    /**
399
     * Display using display abstract.
400
     *
401
     * @param string $abstract
402
     * @param array  $arguments
403
     *
404
     * @return $this
405
     */
406
    public function displayUsing($abstract, $arguments = [])
407
    {
408
        $grid = $this->grid;
409
410
        $column = $this;
411
412 View Code Duplication
        return $this->display(function ($value) use ($grid, $column, $abstract, $arguments) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
413
            /** @var AbstractDisplayer $displayer */
414
            $displayer = new $abstract($value, $grid, $column, $this);
415
416
            return $displayer->display(...$arguments);
0 ignored issues
show
Unused Code introduced by
The call to AbstractDisplayer::display() has too many arguments starting with $arguments.

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...
417
        });
418
    }
419
420
    /**
421
     * Display column using array value map.
422
     *
423
     * @param array $values
424
     * @param null  $default
425
     *
426
     * @return $this
427
     */
428 View Code Duplication
    public function using(array $values, $default = null)
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...
429
    {
430
        return $this->display(function ($value) use ($values, $default) {
431
            if (is_null($value)) {
432
                return $default;
433
            }
434
435
            return Arr::get($values, $value, $default);
436
        });
437
    }
438
439
    /**
440
     * Render this column with the given view.
441
     *
442
     * @param string $view
443
     *
444
     * @return $this
445
     */
446
    public function view($view)
447
    {
448
        return $this->display(function ($value) use ($view) {
449
            $model = $this;
450
451
            return view($view, compact('model', 'value'))->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...
452
        });
453
    }
454
455
    /**
456
     * Hide this column by default.
457
     *
458
     * @return $this
459
     */
460
    public function hide()
461
    {
462
        $this->grid->hideColumns($this->getName());
463
464
        return $this;
465
    }
466
467
    /**
468
     * Add column to total-row.
469
     *
470
     * @param null $display
471
     *
472
     * @return $this
473
     */
474
    public function totalRow($display = null)
475
    {
476
        $this->grid->addTotalRow($this->name, $display);
0 ignored issues
show
Documentation introduced by
$display is of type null, but the function expects a object<Closure>.

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...
477
478
        return $this;
479
    }
480
481
    /**
482
     * Convert file size to a human readable format like `100mb`.
483
     *
484
     * @return $this
485
     */
486
    public function filesize()
487
    {
488
        return $this->display(function ($value) {
489
            return file_size($value);
490
        });
491
    }
492
493
    /**
494
     * Display the fields in the email format as gavatar.
495
     *
496
     * @param int $size
497
     *
498
     * @return $this
499
     */
500
    public function gravatar($size = 30)
501
    {
502
        return $this->display(function ($value) use ($size) {
503
            $src = sprintf(
504
                'https://www.gravatar.com/avatar/%s?s=%d',
505
                md5(strtolower($value)),
506
                $size
507
            );
508
509
            return "<img src='$src' class='img img-circle'/>";
510
        });
511
    }
512
513
    /**
514
     * Display field as a loading icon.
515
     *
516
     * @param array $values
517
     * @param array $others
518
     *
519
     * @return $this
520
     */
521
    public function loading($values = [], $others = [])
522
    {
523
        return $this->display(function ($value) use ($values, $others) {
524
525
            $values = (array) $values;
0 ignored issues
show
Bug introduced by
Consider using a different name than the imported variable $values, or did you forget to import by reference?

It seems like you are assigning to a variable which was imported through a use statement which was not imported by reference.

For clarity, we suggest to use a different name or import by reference depending on whether you would like to have the change visibile in outer-scope.

Change not visible in outer-scope

$x = 1;
$callable = function() use ($x) {
    $x = 2; // Not visible in outer scope. If you would like this, how
            // about using a different variable name than $x?
};

$callable();
var_dump($x); // integer(1)

Change visible in outer-scope

$x = 1;
$callable = function() use (&$x) {
    $x = 2;
};

$callable();
var_dump($x); // integer(2)
Loading history...
526
527
            if (in_array($value, $values)) {
528
                return '<i class="fa fa-refresh fa-spin text-primary"></i>';
529
            }
530
531
            return Arr::get($others, $value, $value);
532
        });
533
    }
534
535
    /**
536
     * Display column as an font-awesome icon based on it's value.
537
     *
538
     * @param array $setting
539
     * @param string $default
540
     *
541
     * @return $this
542
     */
543
    public function icon(array $setting, $default = '')
544
    {
545
        return $this->display(function ($value) use ($setting, $default) {
546
547
            $fa = '';
548
549
            if (isset($setting[$value])) {
550
                $fa = $setting[$value];
551
            } elseif ($default) {
552
                $fa = $default;
553
            }
554
555
            return "<i class=\"fa fa-{$fa}\"></i>";
556
        });
557
    }
558
559
    /**
560
     * Return a human readable format time.
561
     *
562
     * @param null $locale
563
     *
564
     * @return $this
565
     */
566
    public function diffForHumans($locale = null)
567
    {
568
        if ($locale) {
569
            Carbon::setLocale($locale);
570
        }
571
572
        return $this->display(function ($value) {
573
            return Carbon::parse($value)->diffForHumans();
0 ignored issues
show
Bug introduced by
The method diffForHumans does only exist in Carbon\CarbonInterface, but not in Carbon\Traits\Creator.

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...
574
        });
575
    }
576
577
    /**
578
     * If has display callbacks.
579
     *
580
     * @return bool
581
     */
582
    protected function hasDisplayCallbacks()
583
    {
584
        return !empty($this->displayCallbacks);
585
    }
586
587
    /**
588
     * Call all of the "display" callbacks column.
589
     *
590
     * @param mixed $value
591
     * @param int   $key
592
     *
593
     * @return mixed
594
     */
595
    protected function callDisplayCallbacks($value, $key)
596
    {
597
        foreach ($this->displayCallbacks as $callback) {
598
            $previous = $value;
599
600
            $callback = $this->bindOriginalRowModel($callback, $key);
601
            $value = call_user_func_array($callback, [$value, $this]);
602
603
            if (($value instanceof static) &&
604
                ($last = array_pop($this->displayCallbacks))
605
            ) {
606
                $last = $this->bindOriginalRowModel($last, $key);
607
                $value = call_user_func($last, $previous);
608
            }
609
        }
610
611
        return $value;
612
    }
613
614
    /**
615
     * Set original grid data to column.
616
     *
617
     * @param Closure $callback
618
     * @param int     $key
619
     *
620
     * @return Closure
621
     */
622
    protected function bindOriginalRowModel(Closure $callback, $key)
623
    {
624
        $rowModel = static::$originalGridModels[$key];
625
626
        return $callback->bindTo($rowModel);
627
    }
628
629
    /**
630
     * Fill all data to every column.
631
     *
632
     * @param array $data
633
     *
634
     * @return mixed
635
     */
636
    public function fill(array $data)
637
    {
638
        foreach ($data as $key => &$row) {
639
            $this->original = $value = Arr::get($row, $this->name);
640
641
            $value = $this->htmlEntityEncode($value);
642
643
            Arr::set($row, $this->name, $value);
644
645
            if ($this->isDefinedColumn()) {
646
                $this->useDefinedColumn();
647
            }
648
649
            if ($this->hasDisplayCallbacks()) {
650
                $value = $this->callDisplayCallbacks($this->original, $key);
651
                Arr::set($row, $this->name, $value);
652
            }
653
        }
654
655
        return $data;
656
    }
657
658
    /**
659
     * If current column is a defined column.
660
     *
661
     * @return bool
662
     */
663
    protected function isDefinedColumn()
664
    {
665
        return array_key_exists($this->name, static::$defined);
666
    }
667
668
    /**
669
     * Use a defined column.
670
     *
671
     * @throws \Exception
672
     */
673
    protected function useDefinedColumn()
674
    {
675
        // clear all display callbacks.
676
        $this->displayCallbacks = [];
677
678
        $class = static::$defined[$this->name];
679
680
        if ($class instanceof Closure) {
681
            $this->display($class);
682
683
            return;
684
        }
685
686
        if (!class_exists($class) || !is_subclass_of($class, AbstractDisplayer::class)) {
0 ignored issues
show
Bug introduced by
Due to PHP Bug #53727, is_subclass_of might return inconsistent results on some PHP versions if \Encore\Admin\Grid\Displ...bstractDisplayer::class can be an interface. If so, you could instead use ReflectionClass::implementsInterface.
Loading history...
687
            throw new \Exception("Invalid column definition [$class]");
688
        }
689
690
        $grid = $this->grid;
691
        $column = $this;
692
693
        $this->display(function ($value) use ($grid, $column, $class) {
694
            /** @var AbstractDisplayer $definition */
695
            $definition = new $class($value, $grid, $column, $this);
696
697
            return $definition->display();
698
        });
699
    }
700
701
    /**
702
     * Convert characters to HTML entities recursively.
703
     *
704
     * @param array|string $item
705
     *
706
     * @return mixed
707
     */
708
    protected function htmlEntityEncode($item)
709
    {
710
        if (is_array($item)) {
711
            array_walk_recursive($item, function (&$value) {
712
                $value = htmlentities($value);
713
            });
714
        } else {
715
            $item = htmlentities($item);
716
        }
717
718
        return $item;
719
    }
720
721
    /**
722
     * Create the column sorter.
723
     *
724
     * @return string
725
     */
726
    public function sorter()
727
    {
728
        if (!$this->sortable) {
729
            return '';
730
        }
731
732
        $icon = 'fa-sort';
733
        $type = 'desc';
734
735
        if ($this->isSorted()) {
736
            $type = $this->sort['type'] == 'desc' ? 'asc' : 'desc';
737
            $icon .= "-amount-{$this->sort['type']}";
738
        }
739
740
        // set sort value
741
        $sort = ['column' => $this->name, 'type' => $type];
742
        if (isset($this->cast)) {
743
            $sort['cast'] = $this->cast;
744
        }
745
746
        $query = app('request')->all();
747
        $query = array_merge($query, [$this->grid->model()->getSortName() => $sort]);
748
749
        $url = url()->current().'?'.http_build_query($query);
750
751
        return "<a class=\"fa fa-fw $icon\" href=\"$url\"></a>";
752
    }
753
754
    /**
755
     * Determine if this column is currently sorted.
756
     *
757
     * @return bool
758
     */
759
    protected function isSorted()
760
    {
761
        $this->sort = app('request')->get($this->grid->model()->getSortName());
762
763
        if (empty($this->sort)) {
764
            return false;
765
        }
766
767
        return isset($this->sort['column']) && $this->sort['column'] == $this->name;
768
    }
769
770
    /**
771
     * Set help message for column.
772
     *
773
     * @param string $help
774
     *
775
     * @return $this|string
776
     */
777
    public function help($help = '')
778
    {
779
        if (!empty($help)) {
780
            $this->help = $help;
781
782
            return $this;
783
        }
784
785
        if (empty($this->help)) {
786
            return '';
787
        }
788
789
        Admin::script("$('.column-help').popover();");
790
791
        $data = [
792
            'container' => 'body',
793
            'toggle'    => 'popover',
794
            'trigger'   => 'hover',
795
            'placement' => 'bottom',
796
            'content'   => $this->help,
797
        ];
798
799
        $data = collect($data)->map(function ($val, $key) {
800
            return "data-{$key}=\"{$val}\"";
801
        })->implode(' ');
802
803
        return <<<HELP
804
<a href="javascript:void(0);" class="column-help" {$data}>
805
    <i class="fa fa-question-circle"></i>
806
</a>
807
HELP;
808
    }
809
810
    /**
811
     * Find a displayer to display column.
812
     *
813
     * @param string $abstract
814
     * @param array  $arguments
815
     *
816
     * @return $this
817
     */
818
    protected function resolveDisplayer($abstract, $arguments)
819
    {
820
        if (array_key_exists($abstract, static::$displayers)) {
821
            return $this->callBuiltinDisplayer(static::$displayers[$abstract], $arguments);
822
        }
823
824
        return $this->callSupportDisplayer($abstract, $arguments);
825
    }
826
827
    /**
828
     * Call Illuminate/Support displayer.
829
     *
830
     * @param string $abstract
831
     * @param array  $arguments
832
     *
833
     * @return $this
834
     */
835
    protected function callSupportDisplayer($abstract, $arguments)
836
    {
837
        return $this->display(function ($value) use ($abstract, $arguments) {
838
            if (is_array($value) || $value instanceof Arrayable) {
839
                return call_user_func_array([collect($value), $abstract], $arguments);
840
            }
841
842
            if (is_string($value)) {
843
                return call_user_func_array([Str::class, $abstract], array_merge([$value], $arguments));
844
            }
845
846
            return $value;
847
        });
848
    }
849
850
    /**
851
     * Call Builtin displayer.
852
     *
853
     * @param string $abstract
854
     * @param array  $arguments
855
     *
856
     * @return $this
857
     */
858
    protected function callBuiltinDisplayer($abstract, $arguments)
859
    {
860
        if ($abstract instanceof Closure) {
861
            return $this->display(function ($value) use ($abstract, $arguments) {
862
                return $abstract->call($this, ...array_merge([$value], $arguments));
863
            });
864
        }
865
866
        if (class_exists($abstract) && is_subclass_of($abstract, AbstractDisplayer::class)) {
0 ignored issues
show
Bug introduced by
Due to PHP Bug #53727, is_subclass_of might return inconsistent results on some PHP versions if \Encore\Admin\Grid\Displ...bstractDisplayer::class can be an interface. If so, you could instead use ReflectionClass::implementsInterface.
Loading history...
867
            $grid = $this->grid;
868
            $column = $this;
869
870 View Code Duplication
            return $this->display(function ($value) use ($abstract, $grid, $column, $arguments) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
871
                /** @var AbstractDisplayer $displayer */
872
                $displayer = new $abstract($value, $grid, $column, $this);
873
874
                return $displayer->display(...$arguments);
0 ignored issues
show
Unused Code introduced by
The call to AbstractDisplayer::display() has too many arguments starting with $arguments.

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...
875
            });
876
        }
877
878
        return $this;
879
    }
880
881
    /**
882
     * Passes through all unknown calls to builtin displayer or supported displayer.
883
     *
884
     * Allow fluent calls on the Column object.
885
     *
886
     * @param string $method
887
     * @param array  $arguments
888
     *
889
     * @return $this
890
     */
891
    public function __call($method, $arguments)
892
    {
893
        if ($this->isRelation() && !$this->relationColumn) {
894
            $this->name = "{$this->relation}.$method";
895
            $this->label = $this->formatLabel($arguments[0] ?? null);
896
897
            $this->relationColumn = $method;
898
899
            return $this;
900
        }
901
902
        return $this->resolveDisplayer($method, $arguments);
903
    }
904
}
905