Completed
Push — master ( 3e1348...65fa37 )
by Song
02:57
created

src/Grid/Column.php (1 issue)

Severity

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
namespace Encore\Admin\Grid;
4
5
use Carbon\Carbon;
6
use Closure;
7
use Encore\Admin\Actions\RowAction;
8
use Encore\Admin\Grid;
9
use Encore\Admin\Grid\Displayers\AbstractDisplayer;
10
use Illuminate\Contracts\Support\Arrayable;
11
use Illuminate\Database\Eloquent\Model as BaseModel;
12
use Illuminate\Support\Arr;
13
use Illuminate\Support\Collection;
14
use Illuminate\Support\Str;
15
16
/**
17
 * Class Column.
18
 *
19
 * @method $this editable()
20
 * @method $this switch ($states = [])
21
 * @method $this switchGroup($columns = [], $states = [])
22
 * @method $this select($options = [])
23
 * @method $this image($server = '', $width = 200, $height = 200)
24
 * @method $this label($style = 'success')
25
 * @method $this button($style = null)
26
 * @method $this link($href = '', $target = '_blank')
27
 * @method $this badge($style = 'red')
28
 * @method $this progress($style = 'primary', $size = 'sm', $max = 100)
29
 * @method $this radio($options = [])
30
 * @method $this checkbox($options = [])
31
 * @method $this orderable($column, $label = '')
32
 * @method $this table($titles = [])
33
 * @method $this expand($callback = null)
34
 * @method $this modal($title, $callback = null)
35
 * @method $this carousel(int $width = 300, int $height = 200, $server = '')
36
 * @method $this downloadable($server = '')
37
 * @method $this copyable()
38
 * @method $this qrcode($formatter = null, $width = 150, $height = 150)
39
 * @method $this prefix($prefix, $delimiter = '&nbsp;')
40
 * @method $this suffix($suffix, $delimiter = '&nbsp;')
41
 * @method $this secret($dotCount = 6)
42
 * @method $this limit($limit = 100, $end = '...')
43
 */
44
class Column
45
{
46
    use Column\HasHeader;
47
48
    const SELECT_COLUMN_NAME = '__row_selector__';
49
50
    const ACTION_COLUMN_NAME = '__actions__';
51
52
    /**
53
     * @var Grid
54
     */
55
    protected $grid;
56
57
    /**
58
     * Name of column.
59
     *
60
     * @var string
61
     */
62
    protected $name;
63
64
    /**
65
     * Label of column.
66
     *
67
     * @var string
68
     */
69
    protected $label;
70
71
    /**
72
     * Original value of column.
73
     *
74
     * @var mixed
75
     */
76
    protected $original;
77
78
    /**
79
     * Attributes of column.
80
     *
81
     * @var array
82
     */
83
    protected $attributes = [];
84
85
    /**
86
     * Relation name.
87
     *
88
     * @var bool
89
     */
90
    protected $relation = false;
91
92
    /**
93
     * Relation column.
94
     *
95
     * @var string
96
     */
97
    protected $relationColumn;
98
99
    /**
100
     * Original grid data.
101
     *
102
     * @var Collection
103
     */
104
    protected static $originalGridModels;
105
106
    /**
107
     * @var []Closure
108
     */
109
    protected $displayCallbacks = [];
110
111
    /**
112
     * Displayers for grid column.
113
     *
114
     * @var array
115
     */
116
    public static $displayers = [
117
        'editable'      => Displayers\Editable::class,
118
        'switch'        => Displayers\SwitchDisplay::class,
119
        'switchGroup'   => Displayers\SwitchGroup::class,
120
        'select'        => Displayers\Select::class,
121
        'image'         => Displayers\Image::class,
122
        'label'         => Displayers\Label::class,
123
        'button'        => Displayers\Button::class,
124
        'link'          => Displayers\Link::class,
125
        'badge'         => Displayers\Badge::class,
126
        'progressBar'   => Displayers\ProgressBar::class,
127
        'progress'      => Displayers\ProgressBar::class,
128
        'radio'         => Displayers\Radio::class,
129
        'checkbox'      => Displayers\Checkbox::class,
130
        'orderable'     => Displayers\Orderable::class,
131
        'table'         => Displayers\Table::class,
132
        'expand'        => Displayers\Expand::class,
133
        'modal'         => Displayers\Modal::class,
134
        'carousel'      => Displayers\Carousel::class,
135
        'downloadable'  => Displayers\Downloadable::class,
136
        'copyable'      => Displayers\Copyable::class,
137
        'qrcode'        => Displayers\QRCode::class,
138
        'prefix'        => Displayers\Prefix::class,
139
        'suffix'        => Displayers\Suffix::class,
140
        'secret'        => Displayers\Secret::class,
141
        'limit'         => Displayers\Limit::class,
142
    ];
143
144
    /**
145
     * Defined columns.
146
     *
147
     * @var array
148
     */
149
    public static $defined = [];
150
151
    /**
152
     * @var array
153
     */
154
    protected static $htmlAttributes = [];
155
156
    /**
157
     * @var array
158
     */
159
    protected static $rowAttributes = [];
160
161
    /**
162
     * @var Model
163
     */
164
    protected static $model;
165
166
    /**
167
     * @var bool
168
     */
169
    protected $searchable = false;
170
171
    /**
172
     * @param string $name
173
     * @param string $label
174
     */
175
    public function __construct($name, $label)
176
    {
177
        $this->name = $name;
178
179
        $this->label = $this->formatLabel($label);
180
181
        $this->initAttributes();
182
    }
183
184
    /**
185
     * Initialize column attributes.
186
     */
187
    protected function initAttributes()
188
    {
189
        $name = str_replace('.', '-', $this->name);
190
191
        $this->setAttributes(['class' => "column-{$name}"]);
192
    }
193
194
    /**
195
     * Extend column displayer.
196
     *
197
     * @param $name
198
     * @param $displayer
199
     */
200
    public static function extend($name, $displayer)
201
    {
202
        static::$displayers[$name] = $displayer;
203
    }
204
205
    /**
206
     * Define a column globally.
207
     *
208
     * @param string $name
209
     * @param mixed  $definition
210
     */
211
    public static function define($name, $definition)
212
    {
213
        static::$defined[$name] = $definition;
214
    }
215
216
    /**
217
     * Set grid instance for column.
218
     *
219
     * @param Grid $grid
220
     */
221
    public function setGrid(Grid $grid)
222
    {
223
        $this->grid = $grid;
224
225
        $this->setModel($grid->model()->eloquent());
226
    }
227
228
    /**
229
     * Set model for column.
230
     *
231
     * @param $model
232
     */
233
    public function setModel($model)
234
    {
235
        if (is_null(static::$model) && ($model instanceof BaseModel)) {
236
            static::$model = $model->newInstance();
237
        }
238
    }
239
240
    /**
241
     * Set original data for column.
242
     *
243
     * @param Collection $collection
244
     */
245
    public static function setOriginalGridModels(Collection $collection)
246
    {
247
        static::$originalGridModels = $collection;
248
    }
249
250
    /**
251
     * Set column attributes.
252
     *
253
     * @param array $attributes
254
     *
255
     * @return $this
256
     */
257
    public function setAttributes($attributes = [], $key = null)
258
    {
259
        if ($key) {
260
            static::$rowAttributes[$this->name][$key] = array_merge(
261
                Arr::get(static::$rowAttributes, "{$this->name}.{$key}", []),
262
                $attributes
263
            );
264
265
            return $this;
266
        }
267
268
        static::$htmlAttributes[$this->name] = array_merge(
269
            Arr::get(static::$htmlAttributes, $this->name, []),
270
            $attributes
271
        );
272
273
        return $this;
274
    }
275
276
    /**
277
     * Get column attributes.
278
     *
279
     * @param string $name
280
     *
281
     * @return mixed
282
     */
283
    public static function getAttributes($name, $key = null)
284
    {
285
        $rowAttributes = [];
286
287
        if ($key && Arr::has(static::$rowAttributes, "{$name}.{$key}")) {
288
            $rowAttributes = Arr::get(static::$rowAttributes, "{$name}.{$key}", []);
289
        }
290
291
        $columnAttributes = Arr::get(static::$htmlAttributes, $name, []);
292
293
        return array_merge($rowAttributes, $columnAttributes);
294
    }
295
296
    /**
297
     * Format attributes to html.
298
     *
299
     * @return string
300
     */
301
    public function formatHtmlAttributes()
302
    {
303
        $attrArr = [];
304
        foreach (static::getAttributes($this->name) as $name => $val) {
305
            $attrArr[] = "$name=\"$val\"";
306
        }
307
308
        return implode(' ', $attrArr);
309
    }
310
311
    /**
312
     * Set style of this column.
313
     *
314
     * @param string $style
315
     *
316
     * @return $this
317
     */
318
    public function style($style)
319
    {
320
        return $this->setAttributes(compact('style'));
321
    }
322
323
    /**
324
     * Set the width of column.
325
     *
326
     * @param int $width
327
     *
328
     * @return $this
329
     */
330
    public function width(int $width)
331
    {
332
        return $this->style("width: {$width}px;max-width: {$width}px;word-wrap: break-word;word-break: normal;");
333
    }
334
335
    /**
336
     * Set the color of column.
337
     *
338
     * @param string $color
339
     *
340
     * @return $this
341
     */
342
    public function color($color)
343
    {
344
        return $this->style("color:$color;");
345
    }
346
347
    /**
348
     * Get original column value.
349
     *
350
     * @return mixed
351
     */
352
    public function getOriginal()
353
    {
354
        return $this->original;
355
    }
356
357
    /**
358
     * Get name of this column.
359
     *
360
     * @return mixed
361
     */
362
    public function getName()
363
    {
364
        return $this->name;
365
    }
366
367
    /**
368
     * @return string
369
     */
370
    public function getClassName()
371
    {
372
        $name = str_replace('.', '-', $this->getName());
373
374
        return "column-{$name}";
375
    }
376
377
    /**
378
     * Format label.
379
     *
380
     * @param $label
381
     *
382
     * @return mixed
383
     */
384
    protected function formatLabel($label)
385
    {
386
        if ($label) {
387
            return $label;
388
        }
389
390
        $label = ucfirst($this->name);
391
392
        return __(str_replace(['.', '_'], ' ', $label));
393
    }
394
395
    /**
396
     * Get label of the column.
397
     *
398
     * @return mixed
399
     */
400
    public function getLabel()
401
    {
402
        return $this->label;
403
    }
404
405
    /**
406
     * Set relation.
407
     *
408
     * @param string $relation
409
     * @param string $relationColumn
410
     *
411
     * @return $this
412
     */
413
    public function setRelation($relation, $relationColumn = null)
414
    {
415
        $this->relation = $relation;
416
        $this->relationColumn = $relationColumn;
417
418
        return $this;
419
    }
420
421
    /**
422
     * If this column is relation column.
423
     *
424
     * @return bool
425
     */
426
    protected function isRelation()
427
    {
428
        return (bool) $this->relation;
429
    }
430
431
    /**
432
     * Mark this column as sortable.
433
     *
434
     * @param null|string $cast
435
     *
436
     * @return Column|string
437
     */
438
    public function sortable($cast = null)
439
    {
440
        return $this->addSorter($cast);
441
    }
442
443
    /**
444
     * Set cast name for sortable.
445
     *
446
     * @return $this
447
     *
448
     * @deprecated Use `$column->sortable($cast)` instead.
449
     */
450
    public function cast($cast)
451
    {
452
        $this->cast = $cast;
453
454
        return $this;
455
    }
456
457
    /**
458
     * Set help message for column.
459
     *
460
     * @param string $help
461
     *
462
     * @return $this|string
463
     */
464
    public function help($help = '')
465
    {
466
        return $this->addHelp($help);
467
    }
468
469
    /**
470
     * Set column filter.
471
     *
472
     * @param mixed|null $builder
473
     *
474
     * @return $this
475
     */
476
    public function filter($builder = null)
477
    {
478
        return $this->addFilter(...func_get_args());
479
    }
480
481
    /**
482
     * Set column as searchable.
483
     *
484
     * @return $this
485
     */
486
    public function searchable()
487
    {
488
        $this->searchable = true;
489
490
        $name = $this->getName();
491
        $query = request()->query();
492
493
        $this->prefix(function ($_, $original) use ($name, $query) {
494
            Arr::set($query, $name, $original);
495
496
            $url = request()->fullUrlWithQuery($query);
497
498
            return "<a href=\"{$url}\"><i class=\"fa fa-search\"></i></a>";
499
        }, '&nbsp;&nbsp;');
500
501
        return $this;
502
    }
503
504
    /**
505
     * Bind search query to grid model.
506
     *
507
     * @param Model $model
508
     */
509
    public function bindSearchQuery(Model $model)
510
    {
511
        if ($this->searchable && ($value = request($this->getName())) != '') {
512
            $model->where($this->getName(), $value);
513
        }
514
    }
515
516
    /**
517
     * Add a display callback.
518
     *
519
     * @param Closure $callback
520
     *
521
     * @return $this
522
     */
523
    public function display(Closure $callback)
524
    {
525
        $this->displayCallbacks[] = $callback;
526
527
        return $this;
528
    }
529
530
    /**
531
     * Display using display abstract.
532
     *
533
     * @param string $abstract
534
     * @param array  $arguments
535
     *
536
     * @return $this
537
     */
538
    public function displayUsing($abstract, $arguments = [])
539
    {
540
        $grid = $this->grid;
541
542
        $column = $this;
543
544 View Code Duplication
        return $this->display(function ($value) use ($grid, $column, $abstract, $arguments) {
545
            /** @var AbstractDisplayer $displayer */
546
            $displayer = new $abstract($value, $grid, $column, $this);
547
548
            return $displayer->display(...$arguments);
549
        });
550
    }
551
552
    /**
553
     * Display column using array value map.
554
     *
555
     * @param array $values
556
     * @param null  $default
557
     *
558
     * @return $this
559
     */
560 View Code Duplication
    public function using(array $values, $default = null)
561
    {
562
        return $this->display(function ($value) use ($values, $default) {
563
            if (is_null($value)) {
564
                return $default;
565
            }
566
567
            return Arr::get($values, $value, $default);
568
        });
569
    }
570
571
    /**
572
     * Replace output value with giving map.
573
     *
574
     * @param array $replacements
575
     *
576
     * @return $this
577
     */
578
    public function replace(array $replacements)
579
    {
580
        return $this->display(function ($value) use ($replacements) {
581
            if (isset($replacements[$value])) {
582
                return $replacements[$value];
583
            }
584
585
            return $value;
586
        });
587
    }
588
589
    /**
590
     * @param string|Closure $input
591
     * @param string $seperator
592
     *
593
     * @return $this
594
     */
595
    public function repeat($input, $seperator = '')
596
    {
597
        if (is_string($input)) {
598
            $input = function () use ($input) {
599
                return $input;
600
            };
601
        }
602
603
        if ($input instanceof Closure) {
604
            return $this->display(function ($value) use ($input, $seperator) {
605
                return join($seperator, array_fill(0, (int) $value, $input->call($this, [$value])));
606
            });
607
        }
608
609
        return $this;
610
    }
611
612
    /**
613
     * Render this column with the given view.
614
     *
615
     * @param string $view
616
     *
617
     * @return $this
618
     */
619
    public function view($view)
620
    {
621
        return $this->display(function ($value) use ($view) {
622
            $model = $this;
623
624
            return view($view, compact('model', 'value'))->render();
625
        });
626
    }
627
628
    /**
629
     * Hide this column by default.
630
     *
631
     * @return $this
632
     */
633
    public function hide()
634
    {
635
        $this->grid->hideColumns($this->getName());
636
637
        return $this;
638
    }
639
640
    /**
641
     * Add column to total-row.
642
     *
643
     * @param null $display
644
     *
645
     * @return $this
646
     */
647
    public function totalRow($display = null)
648
    {
649
        $this->grid->addTotalRow($this->name, $display);
0 ignored issues
show
$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...
650
651
        return $this;
652
    }
653
654
    /**
655
     * Convert file size to a human readable format like `100mb`.
656
     *
657
     * @return $this
658
     */
659
    public function filesize()
660
    {
661
        return $this->display(function ($value) {
662
            return file_size($value);
663
        });
664
    }
665
666
    /**
667
     * Display the fields in the email format as gavatar.
668
     *
669
     * @param int $size
670
     *
671
     * @return $this
672
     */
673
    public function gravatar($size = 30)
674
    {
675
        return $this->display(function ($value) use ($size) {
676
            $src = sprintf(
677
                'https://www.gravatar.com/avatar/%s?s=%d',
678
                md5(strtolower($value)),
679
                $size
680
            );
681
682
            return "<img src='$src' class='img img-circle'/>";
683
        });
684
    }
685
686
    /**
687
     * Display field as a loading icon.
688
     *
689
     * @param array $values
690
     * @param array $others
691
     *
692
     * @return $this
693
     */
694
    public function loading($values = [], $others = [])
695
    {
696
        return $this->display(function ($value) use ($values, $others) {
697
            $values = (array) $values;
698
699
            if (in_array($value, $values)) {
700
                return '<i class="fa fa-refresh fa-spin text-primary"></i>';
701
            }
702
703
            return Arr::get($others, $value, $value);
704
        });
705
    }
706
707
    /**
708
     * Display column as an font-awesome icon based on it's value.
709
     *
710
     * @param array  $setting
711
     * @param string $default
712
     *
713
     * @return $this
714
     */
715
    public function icon(array $setting, $default = '')
716
    {
717
        return $this->display(function ($value) use ($setting, $default) {
718
            $fa = '';
719
720
            if (isset($setting[$value])) {
721
                $fa = $setting[$value];
722
            } elseif ($default) {
723
                $fa = $default;
724
            }
725
726
            return "<i class=\"fa fa-{$fa}\"></i>";
727
        });
728
    }
729
730
    /**
731
     * Return a human readable format time.
732
     *
733
     * @param null $locale
734
     *
735
     * @return $this
736
     */
737
    public function diffForHumans($locale = null)
738
    {
739
        if ($locale) {
740
            Carbon::setLocale($locale);
741
        }
742
743
        return $this->display(function ($value) {
744
            return Carbon::parse($value)->diffForHumans();
745
        });
746
    }
747
748
    /**
749
     * Returns a string formatted according to the given format string.
750
     *
751
     * @param string $format
752
     *
753
     * @return $this
754
     */
755
    public function date($format)
756
    {
757
        return $this->display(function ($value) use ($format) {
758
            return date($format, strtotime($value));
759
        });
760
    }
761
762
    /**
763
     * Display column as boolean , `✓` for true, and `✗` for false.
764
     *
765
     * @param array $map
766
     * @param bool  $default
767
     *
768
     * @return $this
769
     */
770
    public function bool(array $map = [], $default = false)
771
    {
772
        return $this->display(function ($value) use ($map, $default) {
773
            $bool = empty($map) ? boolval($value) : Arr::get($map, $value, $default);
774
775
            return $bool ? '<i class="fa fa-check text-green"></i>' : '<i class="fa fa-close text-red"></i>';
776
        });
777
    }
778
779
    /**
780
     * Display column as a default value if empty.
781
     *
782
     * @param string $default
783
     * @return $this
784
     */
785
    public function default($default = '-')
786
    {
787
        return $this->display(function ($value) use ($default) {
788
            return $value ?: $default;
789
        });
790
    }
791
792
    /**
793
     * Display column using a grid row action.
794
     *
795
     * @param string $action
796
     *
797
     * @return $this
798
     */
799
    public function action($action)
800
    {
801
        if (!is_subclass_of($action, RowAction::class)) {
802
            throw new \InvalidArgumentException("Action class [$action] must be sub-class of [Encore\Admin\Actions\GridAction]");
803
        }
804
805
        $grid = $this->grid;
806
807
        return $this->display(function ($_, $column) use ($action, $grid) {
808
            /** @var RowAction $action */
809
            $action = new $action();
810
811
            return $action
812
                ->asColumn()
813
                ->setGrid($grid)
814
                ->setColumn($column)
815
                ->setRow($this);
816
        });
817
    }
818
819
    /**
820
     * Add a `dot` before column text.
821
     *
822
     * @param array  $options
823
     * @param string $default
824
     *
825
     * @return $this
826
     */
827
    public function dot($options = [], $default = '')
828
    {
829
        return $this->prefix(function ($_, $original) use ($options, $default) {
830
            if (is_null($original)) {
831
                $style = $default;
832
            } else {
833
                $style = Arr::get($options, $original, $default);
834
            }
835
836
            return "<span class=\"label-{$style}\" style='width: 8px;height: 8px;padding: 0;border-radius: 50%;display: inline-block;'></span>";
837
        }, '&nbsp;&nbsp;');
838
    }
839
840
    /**
841
     * @param string $selectable
842
     *
843
     * @return $this
844
     */
845 View Code Duplication
    public function belongsTo($selectable)
846
    {
847
        if (method_exists($selectable, 'display')) {
848
            $this->display($selectable::display());
849
        }
850
851
        return $this->displayUsing(Grid\Displayers\BelongsTo::class, [$selectable]);
852
    }
853
854
    /**
855
     * @param string $selectable
856
     *
857
     * @return $this
858
     */
859 View Code Duplication
    public function belongsToMany($selectable)
860
    {
861
        if (method_exists($selectable, 'display')) {
862
            $this->display($selectable::display());
863
        }
864
865
        return $this->displayUsing(Grid\Displayers\BelongsToMany::class, [$selectable]);
866
    }
867
868
    /**
869
     * Upload file.
870
     *
871
     * @return $this
872
     */
873
    public function upload()
874
    {
875
        return $this->displayUsing(Grid\Displayers\Upload::class);
876
    }
877
878
    /**
879
     * Upload many files.
880
     *
881
     * @return $this
882
     */
883
    public function uplaodMany()
884
    {
885
        return $this->displayUsing(Grid\Displayers\Upload::class, [true]);
886
    }
887
888
    /**
889
     * If has display callbacks.
890
     *
891
     * @return bool
892
     */
893
    protected function hasDisplayCallbacks()
894
    {
895
        return !empty($this->displayCallbacks);
896
    }
897
898
    /**
899
     * Call all of the "display" callbacks column.
900
     *
901
     * @param mixed $value
902
     * @param int   $key
903
     *
904
     * @return mixed
905
     */
906
    protected function callDisplayCallbacks($value, $key)
907
    {
908
        foreach ($this->displayCallbacks as $callback) {
909
            $previous = $value;
910
911
            $callback = $this->bindOriginalRowModel($callback, $key);
912
            $value = call_user_func_array($callback, [$value, $this]);
913
914
            if (($value instanceof static) &&
915
                ($last = array_pop($this->displayCallbacks))
916
            ) {
917
                $last = $this->bindOriginalRowModel($last, $key);
918
                $value = call_user_func($last, $previous);
919
            }
920
        }
921
922
        return $value;
923
    }
924
925
    /**
926
     * Set original grid data to column.
927
     *
928
     * @param Closure $callback
929
     * @param int     $key
930
     *
931
     * @return Closure
932
     */
933
    protected function bindOriginalRowModel(Closure $callback, $key)
934
    {
935
        $rowModel = static::$originalGridModels[$key];
936
937
        return $callback->bindTo($rowModel);
938
    }
939
940
    /**
941
     * Fill all data to every column.
942
     *
943
     * @param array $data
944
     *
945
     * @return mixed
946
     */
947
    public function fill(array $data)
948
    {
949
        foreach ($data as $key => &$row) {
950
            $this->original = $value = Arr::get($row, $this->name);
951
952
            $value = $this->htmlEntityEncode($value);
953
954
            Arr::set($row, $this->name, $value);
955
956
            if ($this->isDefinedColumn()) {
957
                $this->useDefinedColumn();
958
            }
959
960
            if ($this->hasDisplayCallbacks()) {
961
                $value = $this->callDisplayCallbacks($this->original, $key);
962
                Arr::set($row, $this->name, $value);
963
            }
964
        }
965
966
        return $data;
967
    }
968
969
    /**
970
     * If current column is a defined column.
971
     *
972
     * @return bool
973
     */
974
    protected function isDefinedColumn()
975
    {
976
        return array_key_exists($this->name, static::$defined);
977
    }
978
979
    /**
980
     * Use a defined column.
981
     *
982
     * @throws \Exception
983
     */
984
    protected function useDefinedColumn()
985
    {
986
        // clear all display callbacks.
987
        $this->displayCallbacks = [];
988
989
        $class = static::$defined[$this->name];
990
991
        if ($class instanceof Closure) {
992
            $this->display($class);
993
994
            return;
995
        }
996
997
        if (!class_exists($class) || !is_subclass_of($class, AbstractDisplayer::class)) {
998
            throw new \Exception("Invalid column definition [$class]");
999
        }
1000
1001
        $grid = $this->grid;
1002
        $column = $this;
1003
1004
        $this->display(function ($value) use ($grid, $column, $class) {
1005
            /** @var AbstractDisplayer $definition */
1006
            $definition = new $class($value, $grid, $column, $this);
1007
1008
            return $definition->display();
1009
        });
1010
    }
1011
1012
    /**
1013
     * Convert characters to HTML entities recursively.
1014
     *
1015
     * @param array|string $item
1016
     *
1017
     * @return mixed
1018
     */
1019
    protected function htmlEntityEncode($item)
1020
    {
1021
        if (is_array($item)) {
1022
            array_walk_recursive($item, function (&$value) {
1023
                $value = htmlentities($value);
1024
            });
1025
        } else {
1026
            $item = htmlentities($item);
1027
        }
1028
1029
        return $item;
1030
    }
1031
1032
    /**
1033
     * Find a displayer to display column.
1034
     *
1035
     * @param string $abstract
1036
     * @param array  $arguments
1037
     *
1038
     * @return $this
1039
     */
1040
    protected function resolveDisplayer($abstract, $arguments)
1041
    {
1042
        if (array_key_exists($abstract, static::$displayers)) {
1043
            return $this->callBuiltinDisplayer(static::$displayers[$abstract], $arguments);
1044
        }
1045
1046
        return $this->callSupportDisplayer($abstract, $arguments);
1047
    }
1048
1049
    /**
1050
     * Call Illuminate/Support displayer.
1051
     *
1052
     * @param string $abstract
1053
     * @param array  $arguments
1054
     *
1055
     * @return $this
1056
     */
1057
    protected function callSupportDisplayer($abstract, $arguments)
1058
    {
1059
        return $this->display(function ($value) use ($abstract, $arguments) {
1060
            if (is_array($value) || $value instanceof Arrayable) {
1061
                return call_user_func_array([collect($value), $abstract], $arguments);
1062
            }
1063
1064
            if (is_string($value)) {
1065
                return call_user_func_array([Str::class, $abstract], array_merge([$value], $arguments));
1066
            }
1067
1068
            return $value;
1069
        });
1070
    }
1071
1072
    /**
1073
     * Call Builtin displayer.
1074
     *
1075
     * @param string $abstract
1076
     * @param array  $arguments
1077
     *
1078
     * @return $this
1079
     */
1080
    protected function callBuiltinDisplayer($abstract, $arguments)
1081
    {
1082
        if ($abstract instanceof Closure) {
1083
            return $this->display(function ($value) use ($abstract, $arguments) {
1084
                return $abstract->call($this, ...array_merge([$value], $arguments));
1085
            });
1086
        }
1087
1088
        if (class_exists($abstract) && is_subclass_of($abstract, AbstractDisplayer::class)) {
1089
            $grid = $this->grid;
1090
            $column = $this;
1091
1092 View Code Duplication
            return $this->display(function ($value) use ($abstract, $grid, $column, $arguments) {
1093
                /** @var AbstractDisplayer $displayer */
1094
                $displayer = new $abstract($value, $grid, $column, $this);
1095
1096
                return $displayer->display(...$arguments);
1097
            });
1098
        }
1099
1100
        return $this;
1101
    }
1102
1103
    /**
1104
     * Passes through all unknown calls to builtin displayer or supported displayer.
1105
     *
1106
     * Allow fluent calls on the Column object.
1107
     *
1108
     * @param string $method
1109
     * @param array  $arguments
1110
     *
1111
     * @return $this
1112
     */
1113
    public function __call($method, $arguments)
1114
    {
1115
        if ($this->isRelation() && !$this->relationColumn) {
1116
            $this->name = "{$this->relation}.$method";
1117
            $this->label = $this->formatLabel($arguments[0] ?? null);
1118
1119
            $this->relationColumn = $method;
1120
1121
            return $this;
1122
        }
1123
1124
        return $this->resolveDisplayer($method, $arguments);
1125
    }
1126
}
1127