Completed
Push — master ( 8bf0fe...b37564 )
by Song
05:18 queued 03:01
created

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

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
311
     *
312
     * @return string
313
     */
314
    public function getClassName()
315
    {
316
        $name = str_replace('.', '-', $this->getName());
317
318
        return "column-{$name}";
319
    }
320
321
    /**
322
     * Format label.
323
     *
324
     * @param $label
325
     *
326
     * @return mixed
327
     */
328
    protected function formatLabel($label)
329
    {
330
        if ($label) {
331
            return $label;
332
        }
333
334
        $label = ucfirst($this->name);
335
336
        return __(str_replace(['.', '_'], ' ', $label));
337
    }
338
339
    /**
340
     * Get label of the column.
341
     *
342
     * @return mixed
343
     */
344
    public function getLabel()
345
    {
346
        return $this->label;
347
    }
348
349
    /**
350
     * Set relation.
351
     *
352
     * @param string $relation
353
     * @param string $relationColumn
354
     *
355
     * @return $this
356
     */
357
    public function setRelation($relation, $relationColumn = null)
358
    {
359
        $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...
360
        $this->relationColumn = $relationColumn;
361
362
        return $this;
363
    }
364
365
    /**
366
     * If this column is relation column.
367
     *
368
     * @return bool
369
     */
370
    protected function isRelation()
371
    {
372
        return (bool) $this->relation;
373
    }
374
375
    /**
376
     * Mark this column as sortable.
377
     *
378
     * @param null|string $cast
379
     *
380
     * @return Column|string
381
     */
382
    public function sortable($cast = null)
383
    {
384
        return $this->addSorter($cast);
385
    }
386
387
    /**
388
     * Set cast name for sortable.
389
     *
390
     * @return $this
391
     *
392
     * @deprecated Use `$column->sortable($cast)` instead.
393
     */
394
    public function cast($cast)
395
    {
396
        $this->cast = $cast;
0 ignored issues
show
Bug introduced by
The property cast does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
397
398
        return $this;
399
    }
400
401
    /**
402
     * Set help message for column.
403
     *
404
     * @param string $help
405
     *
406
     * @return $this|string
407
     */
408
    public function help($help = '')
409
    {
410
        return $this->addHelp($help);
411
    }
412
413
    /**
414
     * Set column filter.
415
     *
416
     * @param null $builder
417
     *
418
     * @return $this
419
     */
420
    public function filter($builder = null)
0 ignored issues
show
Unused Code introduced by
The parameter $builder is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
421
    {
422
        return $this->addFilter(...func_get_args());
423
    }
424
425
    /**
426
     * Add a display callback.
427
     *
428
     * @param Closure $callback
429
     *
430
     * @return $this
431
     */
432
    public function display(Closure $callback)
433
    {
434
        $this->displayCallbacks[] = $callback;
435
436
        return $this;
437
    }
438
439
    /**
440
     * Display using display abstract.
441
     *
442
     * @param string $abstract
443
     * @param array  $arguments
444
     *
445
     * @return $this
446
     */
447
    public function displayUsing($abstract, $arguments = [])
448
    {
449
        $grid = $this->grid;
450
451
        $column = $this;
452
453 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...
454
            /** @var AbstractDisplayer $displayer */
455
            $displayer = new $abstract($value, $grid, $column, $this);
456
457
            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...
458
        });
459
    }
460
461
    /**
462
     * Display column using array value map.
463
     *
464
     * @param array $values
465
     * @param null  $default
466
     *
467
     * @return $this
468
     */
469 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...
470
    {
471
        return $this->display(function ($value) use ($values, $default) {
472
            if (is_null($value)) {
473
                return $default;
474
            }
475
476
            return Arr::get($values, $value, $default);
477
        });
478
    }
479
480
    /**
481
     * Replace output value with giving map.
482
     *
483
     * @param array $replacements
484
     *
485
     * @return $this
486
     */
487
    public function replace(array $replacements)
488
    {
489
        return $this->display(function ($value) use ($replacements) {
490
            if (isset($replacements[$value])) {
491
                return $replacements[$value];
492
            }
493
494
            return $value;
495
        });
496
    }
497
498
    /**
499
     * Render this column with the given view.
500
     *
501
     * @param string $view
502
     *
503
     * @return $this
504
     */
505
    public function view($view)
506
    {
507
        return $this->display(function ($value) use ($view) {
508
            $model = $this;
509
510
            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...
511
        });
512
    }
513
514
    /**
515
     * Hide this column by default.
516
     *
517
     * @return $this
518
     */
519
    public function hide()
520
    {
521
        $this->grid->hideColumns($this->getName());
522
523
        return $this;
524
    }
525
526
    /**
527
     * Add column to total-row.
528
     *
529
     * @param null $display
530
     *
531
     * @return $this
532
     */
533
    public function totalRow($display = null)
534
    {
535
        $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...
536
537
        return $this;
538
    }
539
540
    /**
541
     * Convert file size to a human readable format like `100mb`.
542
     *
543
     * @return $this
544
     */
545
    public function filesize()
546
    {
547
        return $this->display(function ($value) {
548
            return file_size($value);
549
        });
550
    }
551
552
    /**
553
     * Display the fields in the email format as gavatar.
554
     *
555
     * @param int $size
556
     *
557
     * @return $this
558
     */
559
    public function gravatar($size = 30)
560
    {
561
        return $this->display(function ($value) use ($size) {
562
            $src = sprintf(
563
                'https://www.gravatar.com/avatar/%s?s=%d',
564
                md5(strtolower($value)),
565
                $size
566
            );
567
568
            return "<img src='$src' class='img img-circle'/>";
569
        });
570
    }
571
572
    /**
573
     * Display field as a loading icon.
574
     *
575
     * @param array $values
576
     * @param array $others
577
     *
578
     * @return $this
579
     */
580
    public function loading($values = [], $others = [])
581
    {
582
        return $this->display(function ($value) use ($values, $others) {
583
            $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...
584
585
            if (in_array($value, $values)) {
586
                return '<i class="fa fa-refresh fa-spin text-primary"></i>';
587
            }
588
589
            return Arr::get($others, $value, $value);
590
        });
591
    }
592
593
    /**
594
     * Display column as an font-awesome icon based on it's value.
595
     *
596
     * @param array  $setting
597
     * @param string $default
598
     *
599
     * @return $this
600
     */
601
    public function icon(array $setting, $default = '')
602
    {
603
        return $this->display(function ($value) use ($setting, $default) {
604
            $fa = '';
605
606
            if (isset($setting[$value])) {
607
                $fa = $setting[$value];
608
            } elseif ($default) {
609
                $fa = $default;
610
            }
611
612
            return "<i class=\"fa fa-{$fa}\"></i>";
613
        });
614
    }
615
616
    /**
617
     * Return a human readable format time.
618
     *
619
     * @param null $locale
620
     *
621
     * @return $this
622
     */
623
    public function diffForHumans($locale = null)
624
    {
625
        if ($locale) {
626
            Carbon::setLocale($locale);
627
        }
628
629
        return $this->display(function ($value) {
630
            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...
631
        });
632
    }
633
634
    /**
635
     * If has display callbacks.
636
     *
637
     * @return bool
638
     */
639
    protected function hasDisplayCallbacks()
640
    {
641
        return !empty($this->displayCallbacks);
642
    }
643
644
    /**
645
     * Call all of the "display" callbacks column.
646
     *
647
     * @param mixed $value
648
     * @param int   $key
649
     *
650
     * @return mixed
651
     */
652
    protected function callDisplayCallbacks($value, $key)
653
    {
654
        foreach ($this->displayCallbacks as $callback) {
655
            $previous = $value;
656
657
            $callback = $this->bindOriginalRowModel($callback, $key);
658
            $value = call_user_func_array($callback, [$value, $this]);
659
660
            if (($value instanceof static) &&
661
                ($last = array_pop($this->displayCallbacks))
662
            ) {
663
                $last = $this->bindOriginalRowModel($last, $key);
664
                $value = call_user_func($last, $previous);
665
            }
666
        }
667
668
        return $value;
669
    }
670
671
    /**
672
     * Set original grid data to column.
673
     *
674
     * @param Closure $callback
675
     * @param int     $key
676
     *
677
     * @return Closure
678
     */
679
    protected function bindOriginalRowModel(Closure $callback, $key)
680
    {
681
        $rowModel = static::$originalGridModels[$key];
682
683
        return $callback->bindTo($rowModel);
684
    }
685
686
    /**
687
     * Fill all data to every column.
688
     *
689
     * @param array $data
690
     *
691
     * @return mixed
692
     */
693
    public function fill(array $data)
694
    {
695
        foreach ($data as $key => &$row) {
696
            $this->original = $value = Arr::get($row, $this->name);
697
698
            $value = $this->htmlEntityEncode($value);
699
700
            Arr::set($row, $this->name, $value);
701
702
            if ($this->isDefinedColumn()) {
703
                $this->useDefinedColumn();
704
            }
705
706
            if ($this->hasDisplayCallbacks()) {
707
                $value = $this->callDisplayCallbacks($this->original, $key);
708
                Arr::set($row, $this->name, $value);
709
            }
710
        }
711
712
        return $data;
713
    }
714
715
    /**
716
     * If current column is a defined column.
717
     *
718
     * @return bool
719
     */
720
    protected function isDefinedColumn()
721
    {
722
        return array_key_exists($this->name, static::$defined);
723
    }
724
725
    /**
726
     * Use a defined column.
727
     *
728
     * @throws \Exception
729
     */
730
    protected function useDefinedColumn()
731
    {
732
        // clear all display callbacks.
733
        $this->displayCallbacks = [];
734
735
        $class = static::$defined[$this->name];
736
737
        if ($class instanceof Closure) {
738
            $this->display($class);
739
740
            return;
741
        }
742
743
        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...
744
            throw new \Exception("Invalid column definition [$class]");
745
        }
746
747
        $grid = $this->grid;
748
        $column = $this;
749
750
        $this->display(function ($value) use ($grid, $column, $class) {
751
            /** @var AbstractDisplayer $definition */
752
            $definition = new $class($value, $grid, $column, $this);
753
754
            return $definition->display();
755
        });
756
    }
757
758
    /**
759
     * Convert characters to HTML entities recursively.
760
     *
761
     * @param array|string $item
762
     *
763
     * @return mixed
764
     */
765
    protected function htmlEntityEncode($item)
766
    {
767
        if (is_array($item)) {
768
            array_walk_recursive($item, function (&$value) {
769
                $value = htmlentities($value);
770
            });
771
        } else {
772
            $item = htmlentities($item);
773
        }
774
775
        return $item;
776
    }
777
778
    /**
779
     * Find a displayer to display column.
780
     *
781
     * @param string $abstract
782
     * @param array  $arguments
783
     *
784
     * @return $this
785
     */
786
    protected function resolveDisplayer($abstract, $arguments)
787
    {
788
        if (array_key_exists($abstract, static::$displayers)) {
789
            return $this->callBuiltinDisplayer(static::$displayers[$abstract], $arguments);
790
        }
791
792
        return $this->callSupportDisplayer($abstract, $arguments);
793
    }
794
795
    /**
796
     * Call Illuminate/Support displayer.
797
     *
798
     * @param string $abstract
799
     * @param array  $arguments
800
     *
801
     * @return $this
802
     */
803
    protected function callSupportDisplayer($abstract, $arguments)
804
    {
805
        return $this->display(function ($value) use ($abstract, $arguments) {
806
            if (is_array($value) || $value instanceof Arrayable) {
807
                return call_user_func_array([collect($value), $abstract], $arguments);
808
            }
809
810
            if (is_string($value)) {
811
                return call_user_func_array([Str::class, $abstract], array_merge([$value], $arguments));
812
            }
813
814
            return $value;
815
        });
816
    }
817
818
    /**
819
     * Call Builtin displayer.
820
     *
821
     * @param string $abstract
822
     * @param array  $arguments
823
     *
824
     * @return $this
825
     */
826
    protected function callBuiltinDisplayer($abstract, $arguments)
827
    {
828
        if ($abstract instanceof Closure) {
829
            return $this->display(function ($value) use ($abstract, $arguments) {
830
                return $abstract->call($this, ...array_merge([$value], $arguments));
831
            });
832
        }
833
834
        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...
835
            $grid = $this->grid;
836
            $column = $this;
837
838 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...
839
                /** @var AbstractDisplayer $displayer */
840
                $displayer = new $abstract($value, $grid, $column, $this);
841
842
                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...
843
            });
844
        }
845
846
        return $this;
847
    }
848
849
    /**
850
     * Passes through all unknown calls to builtin displayer or supported displayer.
851
     *
852
     * Allow fluent calls on the Column object.
853
     *
854
     * @param string $method
855
     * @param array  $arguments
856
     *
857
     * @return $this
858
     */
859
    public function __call($method, $arguments)
860
    {
861
        if ($this->isRelation() && !$this->relationColumn) {
862
            $this->name = "{$this->relation}.$method";
863
            $this->label = $this->formatLabel($arguments[0] ?? null);
864
865
            $this->relationColumn = $method;
866
867
            return $this;
868
        }
869
870
        return $this->resolveDisplayer($method, $arguments);
871
    }
872
}
873