Completed
Push — master ( d53180...5cbd8c )
by Song
02:18
created

Column::gravatar()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 1
dl 0
loc 12
rs 9.8666
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 progress($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
 * @method $this prefix($prefix)
39
 * @method $this suffix($suffix)
40
 */
41
class Column
42
{
43
    use Column\HasHeader;
44
45
    const SELECT_COLUMN_NAME = '__row_selector__';
46
47
    const ACTION_COLUMN_NAME = '__actions__';
48
49
    /**
50
     * @var Grid
51
     */
52
    protected $grid;
53
54
    /**
55
     * Name of column.
56
     *
57
     * @var string
58
     */
59
    protected $name;
60
61
    /**
62
     * Label of column.
63
     *
64
     * @var string
65
     */
66
    protected $label;
67
68
    /**
69
     * Original value of column.
70
     *
71
     * @var mixed
72
     */
73
    protected $original;
74
75
    /**
76
     * Attributes of column.
77
     *
78
     * @var array
79
     */
80
    protected $attributes = [];
81
82
    /**
83
     * Relation name.
84
     *
85
     * @var bool
86
     */
87
    protected $relation = false;
88
89
    /**
90
     * Relation column.
91
     *
92
     * @var string
93
     */
94
    protected $relationColumn;
95
96
    /**
97
     * Original grid data.
98
     *
99
     * @var Collection
100
     */
101
    protected static $originalGridModels;
102
103
    /**
104
     * @var []Closure
105
     */
106
    protected $displayCallbacks = [];
107
108
    /**
109
     * Displayers for grid column.
110
     *
111
     * @var array
112
     */
113
    public static $displayers = [
114
        'editable'    => Displayers\Editable::class,
115
        'switch'      => Displayers\SwitchDisplay::class,
116
        'switchGroup' => Displayers\SwitchGroup::class,
117
        'select'      => Displayers\Select::class,
118
        'image'       => Displayers\Image::class,
119
        'label'       => Displayers\Label::class,
120
        'button'      => Displayers\Button::class,
121
        'link'        => Displayers\Link::class,
122
        'badge'       => Displayers\Badge::class,
123
        'progressBar' => Displayers\ProgressBar::class,
124
        'progress'    => Displayers\ProgressBar::class,
125
        'radio'       => Displayers\Radio::class,
126
        'checkbox'    => Displayers\Checkbox::class,
127
        'orderable'   => Displayers\Orderable::class,
128
        'table'       => Displayers\Table::class,
129
        'expand'      => Displayers\Expand::class,
130
        'modal'       => Displayers\Modal::class,
131
        'carousel'    => Displayers\Carousel::class,
132
        'downloadable'=> Displayers\Downloadable::class,
133
        'copyable'    => Displayers\Copyable::class,
134
        'qrcode'      => Displayers\QRCode::class,
135
        'prefix'      => Displayers\Prefix::class,
136
        'suffix'      => Displayers\Suffix::class,
137
    ];
138
139
    /**
140
     * Defined columns.
141
     *
142
     * @var array
143
     */
144
    public static $defined = [];
145
146
    /**
147
     * @var array
148
     */
149
    protected static $htmlAttributes = [];
150
151
    /**
152
     * @var array
153
     */
154
    protected static $rowAttributes = [];
155
156
    /**
157
     * @var Model
158
     */
159
    protected static $model;
160
161
    /**
162
     * @param string $name
163
     * @param string $label
164
     */
165
    public function __construct($name, $label)
166
    {
167
        $this->name = $name;
168
169
        $this->label = $this->formatLabel($label);
170
171
        $this->initAttributes();
172
    }
173
174
    /**
175
     * Initialize column attributes.
176
     */
177
    protected function initAttributes()
178
    {
179
        $name = str_replace('.', '-', $this->name);
180
181
        $this->setAttributes(['class' => "column-{$name}"]);
182
    }
183
184
    /**
185
     * Extend column displayer.
186
     *
187
     * @param $name
188
     * @param $displayer
189
     */
190
    public static function extend($name, $displayer)
191
    {
192
        static::$displayers[$name] = $displayer;
193
    }
194
195
    /**
196
     * Define a column globally.
197
     *
198
     * @param string $name
199
     * @param mixed  $definition
200
     */
201
    public static function define($name, $definition)
202
    {
203
        static::$defined[$name] = $definition;
204
    }
205
206
    /**
207
     * Set grid instance for column.
208
     *
209
     * @param Grid $grid
210
     */
211
    public function setGrid(Grid $grid)
212
    {
213
        $this->grid = $grid;
214
215
        $this->setModel($grid->model()->eloquent());
216
    }
217
218
    /**
219
     * Set model for column.
220
     *
221
     * @param $model
222
     */
223
    public function setModel($model)
224
    {
225
        if (is_null(static::$model) && ($model instanceof Model)) {
226
            static::$model = $model->newInstance();
227
        }
228
    }
229
230
    /**
231
     * Set original data for column.
232
     *
233
     * @param Collection $collection
234
     */
235
    public static function setOriginalGridModels(Collection $collection)
236
    {
237
        static::$originalGridModels = $collection;
238
    }
239
240
    /**
241
     * Set column attributes.
242
     *
243
     * @param array $attributes
244
     *
245
     * @return $this
246
     */
247
    public function setAttributes($attributes = [], $key = null)
248
    {
249
        if ($key) {
250
            static::$rowAttributes[$this->name][$key] = array_merge(
251
                Arr::get(static::$rowAttributes, "{$this->name}.{$key}", []),
252
                $attributes
253
            );
254
255
            return $this;
256
        }
257
258
        static::$htmlAttributes[$this->name] = array_merge(
259
            Arr::get(static::$htmlAttributes, $this->name, []),
260
            $attributes
261
        );
262
263
        return $this;
264
    }
265
266
    /**
267
     * Get column attributes.
268
     *
269
     * @param string $name
270
     *
271
     * @return mixed
272
     */
273
    public static function getAttributes($name, $key = null)
274
    {
275
        $rowAttributes = [];
276
277
        if ($key && Arr::has(static::$rowAttributes, "{$name}.{$key}")) {
278
            $rowAttributes = Arr::get(static::$rowAttributes, "{$name}.{$key}", []);
279
        }
280
281
        $columnAttributes = Arr::get(static::$htmlAttributes, $name, []);
282
283
        return array_merge($rowAttributes, $columnAttributes);
284
    }
285
286
    /**
287
     * Format attributes to html.
288
     *
289
     * @return string
290
     */
291
    public function formatHtmlAttributes()
292
    {
293
        $attrArr = [];
294
        foreach (static::getAttributes($this->name) as $name => $val) {
295
            $attrArr[] = "$name=\"$val\"";
296
        }
297
298
        return implode(' ', $attrArr);
299
    }
300
301
    /**
302
     * Set style of this column.
303
     *
304
     * @param string $style
305
     *
306
     * @return $this
307
     */
308
    public function style($style)
309
    {
310
        return $this->setAttributes(compact('style'));
311
    }
312
313
    /**
314
     * Set the width of column.
315
     *
316
     * @param int $width
317
     *
318
     * @return $this
319
     */
320
    public function width(int $width)
321
    {
322
        return $this->style("width: {$width}px;");
323
    }
324
325
    /**
326
     * Set the color of column.
327
     *
328
     * @param string $color
329
     *
330
     * @return $this
331
     */
332
    public function color($color)
333
    {
334
        return $this->style("color:$color;");
335
    }
336
337
    /**
338
     * Get original column value.
339
     *
340
     * @return mixed
341
     */
342
    public function getOriginal()
343
    {
344
        return $this->original;
345
    }
346
347
    /**
348
     * Get name of this column.
349
     *
350
     * @return mixed
351
     */
352
    public function getName()
353
    {
354
        return $this->name;
355
    }
356
357
    /**
358
     * @return string
359
     */
360
    public function getClassName()
361
    {
362
        $name = str_replace('.', '-', $this->getName());
363
364
        return "column-{$name}";
365
    }
366
367
    /**
368
     * Format label.
369
     *
370
     * @param $label
371
     *
372
     * @return mixed
373
     */
374
    protected function formatLabel($label)
375
    {
376
        if ($label) {
377
            return $label;
378
        }
379
380
        $label = ucfirst($this->name);
381
382
        return __(str_replace(['.', '_'], ' ', $label));
383
    }
384
385
    /**
386
     * Get label of the column.
387
     *
388
     * @return mixed
389
     */
390
    public function getLabel()
391
    {
392
        return $this->label;
393
    }
394
395
    /**
396
     * Set relation.
397
     *
398
     * @param string $relation
399
     * @param string $relationColumn
400
     *
401
     * @return $this
402
     */
403
    public function setRelation($relation, $relationColumn = null)
404
    {
405
        $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...
406
        $this->relationColumn = $relationColumn;
407
408
        return $this;
409
    }
410
411
    /**
412
     * If this column is relation column.
413
     *
414
     * @return bool
415
     */
416
    protected function isRelation()
417
    {
418
        return (bool) $this->relation;
419
    }
420
421
    /**
422
     * Mark this column as sortable.
423
     *
424
     * @param null|string $cast
425
     *
426
     * @return Column|string
427
     */
428
    public function sortable($cast = null)
429
    {
430
        return $this->addSorter($cast);
431
    }
432
433
    /**
434
     * Set cast name for sortable.
435
     *
436
     * @return $this
437
     *
438
     * @deprecated Use `$column->sortable($cast)` instead.
439
     */
440
    public function cast($cast)
441
    {
442
        $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...
443
444
        return $this;
445
    }
446
447
    /**
448
     * Set help message for column.
449
     *
450
     * @param string $help
451
     *
452
     * @return $this|string
453
     */
454
    public function help($help = '')
455
    {
456
        return $this->addHelp($help);
457
    }
458
459
    /**
460
     * Set column filter.
461
     *
462
     * @param null $builder
463
     *
464
     * @return $this
465
     */
466
    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...
467
    {
468
        return $this->addFilter(...func_get_args());
469
    }
470
471
    /**
472
     * Add a display callback.
473
     *
474
     * @param Closure $callback
475
     *
476
     * @return $this
477
     */
478
    public function display(Closure $callback)
479
    {
480
        $this->displayCallbacks[] = $callback;
481
482
        return $this;
483
    }
484
485
    /**
486
     * Display using display abstract.
487
     *
488
     * @param string $abstract
489
     * @param array  $arguments
490
     *
491
     * @return $this
492
     */
493
    public function displayUsing($abstract, $arguments = [])
494
    {
495
        $grid = $this->grid;
496
497
        $column = $this;
498
499 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...
500
            /** @var AbstractDisplayer $displayer */
501
            $displayer = new $abstract($value, $grid, $column, $this);
502
503
            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...
504
        });
505
    }
506
507
    /**
508
     * Display column using array value map.
509
     *
510
     * @param array $values
511
     * @param null  $default
512
     *
513
     * @return $this
514
     */
515 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...
516
    {
517
        return $this->display(function ($value) use ($values, $default) {
518
            if (is_null($value)) {
519
                return $default;
520
            }
521
522
            return Arr::get($values, $value, $default);
523
        });
524
    }
525
526
    /**
527
     * Replace output value with giving map.
528
     *
529
     * @param array $replacements
530
     *
531
     * @return $this
532
     */
533
    public function replace(array $replacements)
534
    {
535
        return $this->display(function ($value) use ($replacements) {
536
            if (isset($replacements[$value])) {
537
                return $replacements[$value];
538
            }
539
540
            return $value;
541
        });
542
    }
543
544
    /**
545
     * Render this column with the given view.
546
     *
547
     * @param string $view
548
     *
549
     * @return $this
550
     */
551
    public function view($view)
552
    {
553
        return $this->display(function ($value) use ($view) {
554
            $model = $this;
555
556
            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...
557
        });
558
    }
559
560
    /**
561
     * Hide this column by default.
562
     *
563
     * @return $this
564
     */
565
    public function hide()
566
    {
567
        $this->grid->hideColumns($this->getName());
568
569
        return $this;
570
    }
571
572
    /**
573
     * Add column to total-row.
574
     *
575
     * @param null $display
576
     *
577
     * @return $this
578
     */
579
    public function totalRow($display = null)
580
    {
581
        $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...
582
583
        return $this;
584
    }
585
586
    /**
587
     * Convert file size to a human readable format like `100mb`.
588
     *
589
     * @return $this
590
     */
591
    public function filesize()
592
    {
593
        return $this->display(function ($value) {
594
            return file_size($value);
595
        });
596
    }
597
598
    /**
599
     * Display the fields in the email format as gavatar.
600
     *
601
     * @param int $size
602
     *
603
     * @return $this
604
     */
605
    public function gravatar($size = 30)
606
    {
607
        return $this->display(function ($value) use ($size) {
608
            $src = sprintf(
609
                'https://www.gravatar.com/avatar/%s?s=%d',
610
                md5(strtolower($value)),
611
                $size
612
            );
613
614
            return "<img src='$src' class='img img-circle'/>";
615
        });
616
    }
617
618
    /**
619
     * Display field as a loading icon.
620
     *
621
     * @param array $values
622
     * @param array $others
623
     *
624
     * @return $this
625
     */
626
    public function loading($values = [], $others = [])
627
    {
628
        return $this->display(function ($value) use ($values, $others) {
629
            $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...
630
631
            if (in_array($value, $values)) {
632
                return '<i class="fa fa-refresh fa-spin text-primary"></i>';
633
            }
634
635
            return Arr::get($others, $value, $value);
636
        });
637
    }
638
639
    /**
640
     * Display column as an font-awesome icon based on it's value.
641
     *
642
     * @param array  $setting
643
     * @param string $default
644
     *
645
     * @return $this
646
     */
647
    public function icon(array $setting, $default = '')
648
    {
649
        return $this->display(function ($value) use ($setting, $default) {
650
            $fa = '';
651
652
            if (isset($setting[$value])) {
653
                $fa = $setting[$value];
654
            } elseif ($default) {
655
                $fa = $default;
656
            }
657
658
            return "<i class=\"fa fa-{$fa}\"></i>";
659
        });
660
    }
661
662
    /**
663
     * Return a human readable format time.
664
     *
665
     * @param null $locale
666
     *
667
     * @return $this
668
     */
669
    public function diffForHumans($locale = null)
670
    {
671
        if ($locale) {
672
            Carbon::setLocale($locale);
673
        }
674
675
        return $this->display(function ($value) {
676
            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...
677
        });
678
    }
679
680
    /**
681
     * Returns a string formatted according to the given format string.
682
     *
683
     * @param string $format
684
     *
685
     * @return $this
686
     */
687
    public function date($format)
688
    {
689
        return $this->display(function ($value) use ($format) {
690
            return date($format, strtotime($value));
691
        });
692
    }
693
694
    /**
695
     * If has display callbacks.
696
     *
697
     * @return bool
698
     */
699
    protected function hasDisplayCallbacks()
700
    {
701
        return !empty($this->displayCallbacks);
702
    }
703
704
    /**
705
     * Call all of the "display" callbacks column.
706
     *
707
     * @param mixed $value
708
     * @param int   $key
709
     *
710
     * @return mixed
711
     */
712
    protected function callDisplayCallbacks($value, $key)
713
    {
714
        foreach ($this->displayCallbacks as $callback) {
715
            $previous = $value;
716
717
            $callback = $this->bindOriginalRowModel($callback, $key);
718
            $value = call_user_func_array($callback, [$value, $this]);
719
720
            if (($value instanceof static) &&
721
                ($last = array_pop($this->displayCallbacks))
722
            ) {
723
                $last = $this->bindOriginalRowModel($last, $key);
724
                $value = call_user_func($last, $previous);
725
            }
726
        }
727
728
        return $value;
729
    }
730
731
    /**
732
     * Set original grid data to column.
733
     *
734
     * @param Closure $callback
735
     * @param int     $key
736
     *
737
     * @return Closure
738
     */
739
    protected function bindOriginalRowModel(Closure $callback, $key)
740
    {
741
        $rowModel = static::$originalGridModels[$key];
742
743
        return $callback->bindTo($rowModel);
744
    }
745
746
    /**
747
     * Fill all data to every column.
748
     *
749
     * @param array $data
750
     *
751
     * @return mixed
752
     */
753
    public function fill(array $data)
754
    {
755
        foreach ($data as $key => &$row) {
756
            $this->original = $value = Arr::get($row, $this->name);
757
758
            $value = $this->htmlEntityEncode($value);
759
760
            Arr::set($row, $this->name, $value);
761
762
            if ($this->isDefinedColumn()) {
763
                $this->useDefinedColumn();
764
            }
765
766
            if ($this->hasDisplayCallbacks()) {
767
                $value = $this->callDisplayCallbacks($this->original, $key);
768
                Arr::set($row, $this->name, $value);
769
            }
770
        }
771
772
        return $data;
773
    }
774
775
    /**
776
     * If current column is a defined column.
777
     *
778
     * @return bool
779
     */
780
    protected function isDefinedColumn()
781
    {
782
        return array_key_exists($this->name, static::$defined);
783
    }
784
785
    /**
786
     * Use a defined column.
787
     *
788
     * @throws \Exception
789
     */
790
    protected function useDefinedColumn()
791
    {
792
        // clear all display callbacks.
793
        $this->displayCallbacks = [];
794
795
        $class = static::$defined[$this->name];
796
797
        if ($class instanceof Closure) {
798
            $this->display($class);
799
800
            return;
801
        }
802
803
        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...
804
            throw new \Exception("Invalid column definition [$class]");
805
        }
806
807
        $grid = $this->grid;
808
        $column = $this;
809
810
        $this->display(function ($value) use ($grid, $column, $class) {
811
            /** @var AbstractDisplayer $definition */
812
            $definition = new $class($value, $grid, $column, $this);
813
814
            return $definition->display();
815
        });
816
    }
817
818
    /**
819
     * Convert characters to HTML entities recursively.
820
     *
821
     * @param array|string $item
822
     *
823
     * @return mixed
824
     */
825
    protected function htmlEntityEncode($item)
826
    {
827
        if (is_array($item)) {
828
            array_walk_recursive($item, function (&$value) {
829
                $value = htmlentities($value);
830
            });
831
        } else {
832
            $item = htmlentities($item);
833
        }
834
835
        return $item;
836
    }
837
838
    /**
839
     * Find a displayer to display column.
840
     *
841
     * @param string $abstract
842
     * @param array  $arguments
843
     *
844
     * @return $this
845
     */
846
    protected function resolveDisplayer($abstract, $arguments)
847
    {
848
        if (array_key_exists($abstract, static::$displayers)) {
849
            return $this->callBuiltinDisplayer(static::$displayers[$abstract], $arguments);
850
        }
851
852
        return $this->callSupportDisplayer($abstract, $arguments);
853
    }
854
855
    /**
856
     * Call Illuminate/Support displayer.
857
     *
858
     * @param string $abstract
859
     * @param array  $arguments
860
     *
861
     * @return $this
862
     */
863
    protected function callSupportDisplayer($abstract, $arguments)
864
    {
865
        return $this->display(function ($value) use ($abstract, $arguments) {
866
            if (is_array($value) || $value instanceof Arrayable) {
867
                return call_user_func_array([collect($value), $abstract], $arguments);
868
            }
869
870
            if (is_string($value)) {
871
                return call_user_func_array([Str::class, $abstract], array_merge([$value], $arguments));
872
            }
873
874
            return $value;
875
        });
876
    }
877
878
    /**
879
     * Call Builtin displayer.
880
     *
881
     * @param string $abstract
882
     * @param array  $arguments
883
     *
884
     * @return $this
885
     */
886
    protected function callBuiltinDisplayer($abstract, $arguments)
887
    {
888
        if ($abstract instanceof Closure) {
889
            return $this->display(function ($value) use ($abstract, $arguments) {
890
                return $abstract->call($this, ...array_merge([$value], $arguments));
891
            });
892
        }
893
894
        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...
895
            $grid = $this->grid;
896
            $column = $this;
897
898 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...
899
                /** @var AbstractDisplayer $displayer */
900
                $displayer = new $abstract($value, $grid, $column, $this);
901
902
                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...
903
            });
904
        }
905
906
        return $this;
907
    }
908
909
    /**
910
     * Passes through all unknown calls to builtin displayer or supported displayer.
911
     *
912
     * Allow fluent calls on the Column object.
913
     *
914
     * @param string $method
915
     * @param array  $arguments
916
     *
917
     * @return $this
918
     */
919
    public function __call($method, $arguments)
920
    {
921
        if ($this->isRelation() && !$this->relationColumn) {
922
            $this->name = "{$this->relation}.$method";
923
            $this->label = $this->formatLabel($arguments[0] ?? null);
924
925
            $this->relationColumn = $method;
926
927
            return $this;
928
        }
929
930
        return $this->resolveDisplayer($method, $arguments);
931
    }
932
}
933