Completed
Push — master ( 82be35...1537c0 )
by Song
02:28
created

src/Form/Field.php (1 issue)

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\Form;
4
5
use Closure;
6
use Encore\Admin\Admin;
7
use Encore\Admin\Form;
8
use Encore\Admin\Widgets\Form as WidgetForm;
9
use Illuminate\Contracts\Support\Arrayable;
10
use Illuminate\Contracts\Support\Renderable;
11
use Illuminate\Support\Arr;
12
use Illuminate\Support\Str;
13
use Illuminate\Support\Traits\Macroable;
14
15
/**
16
 * Class Field.
17
 */
18
class Field implements Renderable
19
{
20
    use Macroable;
21
22
    const FILE_DELETE_FLAG = '_file_del_';
23
    const FILE_SORT_FLAG = '_file_sort_';
24
25
    /**
26
     * Element id.
27
     *
28
     * @var array|string
29
     */
30
    protected $id;
31
32
    /**
33
     * Element value.
34
     *
35
     * @var mixed
36
     */
37
    protected $value;
38
39
    /**
40
     * Data of all original columns of value.
41
     *
42
     * @var mixed
43
     */
44
    protected $data;
45
46
    /**
47
     * Field original value.
48
     *
49
     * @var mixed
50
     */
51
    protected $original;
52
53
    /**
54
     * Field default value.
55
     *
56
     * @var mixed
57
     */
58
    protected $default;
59
60
    /**
61
     * Element label.
62
     *
63
     * @var string
64
     */
65
    protected $label = '';
66
67
    /**
68
     * Column name.
69
     *
70
     * @var string|array
71
     */
72
    protected $column = '';
73
74
    /**
75
     * Form element name.
76
     *
77
     * @var string
78
     */
79
    protected $elementName = [];
80
81
    /**
82
     * Form element classes.
83
     *
84
     * @var array
85
     */
86
    protected $elementClass = [];
87
88
    /**
89
     * Variables of elements.
90
     *
91
     * @var array
92
     */
93
    protected $variables = [];
94
95
    /**
96
     * Options for specify elements.
97
     *
98
     * @var array
99
     */
100
    protected $options = [];
101
102
    /**
103
     * Checked for specify elements.
104
     *
105
     * @var array
106
     */
107
    protected $checked = [];
108
109
    /**
110
     * Validation rules.
111
     *
112
     * @var array|\Closure
113
     */
114
    protected $rules = [];
115
116
    /**
117
     * The validation rules for creation.
118
     *
119
     * @var array|\Closure
120
     */
121
    public $creationRules = [];
122
123
    /**
124
     * The validation rules for updates.
125
     *
126
     * @var array|\Closure
127
     */
128
    public $updateRules = [];
129
130
    /**
131
     * @var \Closure
132
     */
133
    protected $validator;
134
135
    /**
136
     * Validation messages.
137
     *
138
     * @var array
139
     */
140
    protected $validationMessages = [];
141
142
    /**
143
     * Css required by this field.
144
     *
145
     * @var array
146
     */
147
    protected static $css = [];
148
149
    /**
150
     * Js required by this field.
151
     *
152
     * @var array
153
     */
154
    protected static $js = [];
155
156
    /**
157
     * Script for field.
158
     *
159
     * @var string
160
     */
161
    protected $script = '';
162
163
    /**
164
     * Element attributes.
165
     *
166
     * @var array
167
     */
168
    protected $attributes = [];
169
170
    /**
171
     * Parent form.
172
     *
173
     * @var Form
174
     */
175
    protected $form = null;
176
177
    /**
178
     * View for field to render.
179
     *
180
     * @var string
181
     */
182
    protected $view = '';
183
184
    /**
185
     * Help block.
186
     *
187
     * @var array
188
     */
189
    protected $help = [];
190
191
    /**
192
     * Key for errors.
193
     *
194
     * @var mixed
195
     */
196
    protected $errorKey;
197
198
    /**
199
     * Placeholder for this field.
200
     *
201
     * @var string|array
202
     */
203
    protected $placeholder;
204
205
    /**
206
     * Width for label and field.
207
     *
208
     * @var array
209
     */
210
    protected $width = [
211
        'label' => 2,
212
        'field' => 8,
213
    ];
214
215
    /**
216
     * If the form horizontal layout.
217
     *
218
     * @var bool
219
     */
220
    protected $horizontal = true;
221
222
    /**
223
     * column data format.
224
     *
225
     * @var \Closure
226
     */
227
    protected $customFormat = null;
228
229
    /**
230
     * @var bool
231
     */
232
    protected $display = true;
233
234
    /**
235
     * @var array
236
     */
237
    protected $labelClass = [];
238
239
    /**
240
     * @var array
241
     */
242
    protected $groupClass = [];
243
244
    /**
245
     * @var \Closure
246
     */
247
    protected $callback;
248
249
    /**
250
     * @var bool
251
     */
252
    public $isJsonType = false;
253
254
    /**
255
     * Field constructor.
256
     *
257
     * @param       $column
258
     * @param array $arguments
259
     */
260
    public function __construct($column = '', $arguments = [])
261
    {
262
        $this->column = $this->formatColumn($column);
263
        $this->label = $this->formatLabel($arguments);
264
        $this->id = $this->formatId($column);
265
    }
266
267
    /**
268
     * Get assets required by this field.
269
     *
270
     * @return array
271
     */
272
    public static function getAssets()
273
    {
274
        return [
275
            'css' => static::$css,
276
            'js'  => static::$js,
277
        ];
278
    }
279
280
    /**
281
     * Format the field column name.
282
     *
283
     * @param string $column
284
     *
285
     * @return mixed|string
286
     */
287
    protected function formatColumn($column = '')
288
    {
289 View Code Duplication
        if (Str::contains($column, '->')) {
290
            $this->isJsonType = true;
291
292
            $column = str_replace('->', '.', $column);
293
        }
294
295
        return $column;
296
    }
297
298
    /**
299
     * Format the field element id.
300
     *
301
     * @param string|array $column
302
     *
303
     * @return string|array
304
     */
305
    protected function formatId($column)
306
    {
307
        return str_replace('.', '_', $column);
308
    }
309
310
    /**
311
     * Format the label value.
312
     *
313
     * @param array $arguments
314
     *
315
     * @return string
316
     */
317
    protected function formatLabel($arguments = []): string
318
    {
319
        $column = is_array($this->column) ? current($this->column) : $this->column;
320
321
        $label = $arguments[0] ?? ucfirst($column);
322
323
        return str_replace(['.', '_', '->'], ' ', $label);
324
    }
325
326
    /**
327
     * Format the name of the field.
328
     *
329
     * @param string $column
330
     *
331
     * @return array|mixed|string
332
     */
333
    protected function formatName($column)
334
    {
335
        if (is_string($column)) {
336 View Code Duplication
            if (Str::contains($column, '->')) {
337
                $name = explode('->', $column);
338
            } else {
339
                $name = explode('.', $column);
340
            }
341
342
            if (count($name) === 1) {
343
                return $name[0];
344
            }
345
346
            $html = array_shift($name);
347
            foreach ($name as $piece) {
348
                $html .= "[$piece]";
349
            }
350
351
            return $html;
352
        }
353
354
        if (is_array($this->column)) {
355
            $names = [];
356
            foreach ($this->column as $key => $name) {
357
                $names[$key] = $this->formatName($name);
358
            }
359
360
            return $names;
361
        }
362
363
        return '';
364
    }
365
366
    /**
367
     * Set form element name.
368
     *
369
     * @param string $name
370
     *
371
     * @return $this
372
     *
373
     * @author Edwin Hui
374
     */
375
    public function setElementName($name): self
376
    {
377
        $this->elementName = $name;
378
379
        return $this;
380
    }
381
382
    /**
383
     * Fill data to the field.
384
     *
385
     * @param array $data
386
     *
387
     * @return void
388
     */
389 View Code Duplication
    public function fill($data)
390
    {
391
        $this->data = $data;
392
393
        if (is_array($this->column)) {
394
            foreach ($this->column as $key => $column) {
395
                $this->value[$key] = Arr::get($data, $column);
396
            }
397
398
            return;
399
        }
400
401
        $this->value = Arr::get($data, $this->column);
402
403
        $this->formatValue();
404
    }
405
406
    /**
407
     * Format value by passing custom formater.
408
     */
409
    protected function formatValue()
410
    {
411
        if (isset($this->customFormat) && $this->customFormat instanceof \Closure) {
412
            $this->value = call_user_func($this->customFormat, $this->value);
413
        }
414
    }
415
416
    /**
417
     * custom format form column data when edit.
418
     *
419
     * @param \Closure $call
420
     *
421
     * @return $this
422
     */
423
    public function customFormat(\Closure $call): self
424
    {
425
        $this->customFormat = $call;
426
427
        return $this;
428
    }
429
430
    /**
431
     * Set original value to the field.
432
     *
433
     * @param array $data
434
     *
435
     * @return void
436
     */
437 View Code Duplication
    public function setOriginal($data)
438
    {
439
        if (is_array($this->column)) {
440
            foreach ($this->column as $key => $column) {
441
                $this->original[$key] = Arr::get($data, $column);
442
            }
443
444
            return;
445
        }
446
447
        $this->original = Arr::get($data, $this->column);
448
    }
449
450
    /**
451
     * @param Form $form
452
     *
453
     * @return $this
454
     */
455
    public function setForm(Form $form = null)
456
    {
457
        $this->form = $form;
458
459
        return $this;
460
    }
461
462
    /**
463
     * Set Widget/Form as field parent.
464
     *
465
     * @param WidgetForm $form
466
     *
467
     * @return $this
468
     */
469
    public function setWidgetForm(WidgetForm $form)
470
    {
471
        $this->form = $form;
472
473
        return $this;
474
    }
475
476
    /**
477
     * Set width for field and label.
478
     *
479
     * @param int $field
480
     * @param int $label
481
     *
482
     * @return $this
483
     */
484
    public function setWidth($field = 8, $label = 2): self
485
    {
486
        $this->width = [
487
            'label' => $label,
488
            'field' => $field,
489
        ];
490
491
        return $this;
492
    }
493
494
    /**
495
     * Set the field options.
496
     *
497
     * @param array $options
498
     *
499
     * @return $this
500
     */
501 View Code Duplication
    public function options($options = [])
502
    {
503
        if ($options instanceof Arrayable) {
504
            $options = $options->toArray();
505
        }
506
507
        $this->options = array_merge($this->options, $options);
508
509
        return $this;
510
    }
511
512
    /**
513
     * Set the field option checked.
514
     *
515
     * @param array $checked
516
     *
517
     * @return $this
518
     */
519 View Code Duplication
    public function checked($checked = [])
520
    {
521
        if ($checked instanceof Arrayable) {
522
            $checked = $checked->toArray();
523
        }
524
525
        $this->checked = array_merge($this->checked, $checked);
526
527
        return $this;
528
    }
529
530
    /**
531
     * Add `required` attribute to current field if has required rule,
532
     * except file and image fields.
533
     *
534
     * @param array $rules
535
     */
536
    protected function addRequiredAttribute($rules)
537
    {
538
        if (!is_array($rules)) {
539
            return;
540
        }
541
542
        if (!in_array('required', $rules, true)) {
543
            return;
544
        }
545
546
        $this->setLabelClass(['asterisk']);
547
548
        // Only text field has `required` attribute.
549
        if (!$this instanceof Form\Field\Text) {
550
            return;
551
        }
552
553
        //do not use required attribute with tabs
554
        if ($this->form && $this->form->getTab()) {
555
            return;
556
        }
557
558
        $this->required();
559
    }
560
561
    /**
562
     * If has `required` rule, add required attribute to this field.
563
     */
564
    protected function addRequiredAttributeFromRules()
565
    {
566
        if ($this->data === null) {
567
            // Create page
568
            $rules = $this->creationRules ?: $this->rules;
569
        } else {
570
            // Update page
571
            $rules = $this->updateRules ?: $this->rules;
572
        }
573
574
        $this->addRequiredAttribute($rules);
575
    }
576
577
    /**
578
     * Format validation rules.
579
     *
580
     * @param array|string $rules
581
     *
582
     * @return array
583
     */
584
    protected function formatRules($rules): array
585
    {
586
        if (is_string($rules)) {
587
            $rules = array_filter(explode('|', $rules));
588
        }
589
590
        return array_filter((array) $rules);
591
    }
592
593
    /**
594
     * @param string|array|Closure $input
595
     * @param string|array         $original
596
     *
597
     * @return array|Closure
598
     */
599
    protected function mergeRules($input, $original)
600
    {
601
        if ($input instanceof Closure) {
602
            $rules = $input;
603
        } else {
604
            if (!empty($original)) {
605
                $original = $this->formatRules($original);
606
            }
607
608
            $rules = array_merge($original, $this->formatRules($input));
609
        }
610
611
        return $rules;
612
    }
613
614
    /**
615
     * Set the validation rules for the field.
616
     *
617
     * @param array|callable|string $rules
618
     * @param array                 $messages
619
     *
620
     * @return $this
621
     */
622 View Code Duplication
    public function rules($rules = null, $messages = []): self
623
    {
624
        $this->rules = $this->mergeRules($rules, $this->rules);
625
626
        $this->setValidationMessages('default', $messages);
627
628
        return $this;
629
    }
630
631
    /**
632
     * Set the update validation rules for the field.
633
     *
634
     * @param array|callable|string $rules
635
     * @param array                 $messages
636
     *
637
     * @return $this
638
     */
639 View Code Duplication
    public function updateRules($rules = null, $messages = []): self
640
    {
641
        $this->updateRules = $this->mergeRules($rules, $this->updateRules);
642
643
        $this->setValidationMessages('update', $messages);
644
645
        return $this;
646
    }
647
648
    /**
649
     * Set the creation validation rules for the field.
650
     *
651
     * @param array|callable|string $rules
652
     * @param array                 $messages
653
     *
654
     * @return $this
655
     */
656
    public function creationRules($rules = null, $messages = []): self
657
    {
658
        $this->creationRules = $this->mergeRules($rules, $this->creationRules);
659
660
        $this->setValidationMessages('creation', $messages);
661
662
        return $this;
663
    }
664
665
    /**
666
     * Set validation messages for column.
667
     *
668
     * @param string $key
669
     * @param array  $messages
670
     *
671
     * @return $this
672
     */
673
    public function setValidationMessages($key, array $messages): self
674
    {
675
        $this->validationMessages[$key] = $messages;
676
677
        return $this;
678
    }
679
680
    /**
681
     * Get validation messages for the field.
682
     *
683
     * @return array|mixed
684
     */
685
    public function getValidationMessages()
686
    {
687
        // Default validation message.
688
        $messages = $this->validationMessages['default'] ?? [];
689
690
        if (request()->isMethod('POST')) {
691
            $messages = $this->validationMessages['creation'] ?? $messages;
692
        } elseif (request()->isMethod('PUT')) {
693
            $messages = $this->validationMessages['update'] ?? $messages;
694
        }
695
696
        return $messages;
697
    }
698
699
    /**
700
     * Get field validation rules.
701
     *
702
     * @return string
703
     */
704
    protected function getRules()
705
    {
706
        if (request()->isMethod('POST')) {
707
            $rules = $this->creationRules ?: $this->rules;
708
        } elseif (request()->isMethod('PUT')) {
709
            $rules = $this->updateRules ?: $this->rules;
710
        } else {
711
            $rules = $this->rules;
712
        }
713
714
        if ($rules instanceof \Closure) {
715
            $rules = $rules->call($this, $this->form);
716
        }
717
718
        if (is_string($rules)) {
719
            $rules = array_filter(explode('|', $rules));
720
        }
721
722
        if (!$this->form || !$this->form instanceof Form) {
723
            return $rules;
724
        }
725
726
        if (!$id = $this->form->model()->getKey()) {
727
            return $rules;
728
        }
729
730
        if (is_array($rules)) {
731
            foreach ($rules as &$rule) {
732
                if (is_string($rule)) {
733
                    $rule = str_replace('{{id}}', $id, $rule);
734
                }
735
            }
736
        }
737
738
        return $rules;
739
    }
740
741
    /**
742
     * Remove a specific rule by keyword.
743
     *
744
     * @param string $rule
745
     *
746
     * @return void
747
     */
748
    protected function removeRule($rule)
749
    {
750
        if (is_array($this->rules)) {
751
            array_delete($this->rules, $rule);
752
753
            return;
754
        }
755
756
        if (!is_string($this->rules)) {
757
            return;
758
        }
759
760
        $pattern = "/{$rule}[^\|]?(\||$)/";
761
        $this->rules = preg_replace($pattern, '', $this->rules, -1);
762
    }
763
764
    /**
765
     * Set field validator.
766
     *
767
     * @param callable $validator
768
     *
769
     * @return $this
770
     */
771
    public function validator(callable $validator): self
772
    {
773
        $this->validator = $validator;
774
775
        return $this;
776
    }
777
778
    /**
779
     * Get key for error message.
780
     *
781
     * @return string|array
782
     */
783
    public function getErrorKey()
784
    {
785
        return $this->errorKey ?: $this->column;
786
    }
787
788
    /**
789
     * Set key for error message.
790
     *
791
     * @param string $key
792
     *
793
     * @return $this
794
     */
795
    public function setErrorKey($key): self
796
    {
797
        $this->errorKey = $key;
798
799
        return $this;
800
    }
801
802
    /**
803
     * Set or get value of the field.
804
     *
805
     * @param null $value
806
     *
807
     * @return mixed
808
     */
809
    public function value($value = null)
810
    {
811
        if ($value === null) {
812
            return $this->value ?? $this->getDefault();
813
        }
814
815
        $this->value = $value;
816
817
        return $this;
818
    }
819
820
    /**
821
     * Set or get data.
822
     *
823
     * @param array $data
824
     *
825
     * @return mixed
826
     */
827
    public function data(array $data = null)
828
    {
829
        if ($data === null) {
830
            return $this->data;
831
        }
832
833
        $this->data = $data;
834
835
        return $this;
836
    }
837
838
    /**
839
     * Set default value for field.
840
     *
841
     * @param $default
842
     *
843
     * @return $this
844
     */
845
    public function default($default): self
846
    {
847
        $this->default = $default;
848
849
        return $this;
850
    }
851
852
    /**
853
     * Get default value.
854
     *
855
     * @return mixed
856
     */
857
    public function getDefault()
858
    {
859
        if ($this->default instanceof \Closure) {
860
            return call_user_func($this->default, $this->form);
861
        }
862
863
        return $this->default;
864
    }
865
866
    /**
867
     * Set help block for current field.
868
     *
869
     * @param string $text
870
     * @param string $icon
871
     *
872
     * @return $this
873
     */
874
    public function help($text = '', $icon = 'fa-info-circle'): self
875
    {
876
        $this->help = compact('text', 'icon');
877
878
        return $this;
879
    }
880
881
    /**
882
     * Get column of the field.
883
     *
884
     * @return string|array
885
     */
886
    public function column()
887
    {
888
        return $this->column;
889
    }
890
891
    /**
892
     * Get label of the field.
893
     *
894
     * @return string
895
     */
896
    public function label(): string
897
    {
898
        return $this->label;
899
    }
900
901
    /**
902
     * Get original value of the field.
903
     *
904
     * @return mixed
905
     */
906
    public function original()
907
    {
908
        return $this->original;
909
    }
910
911
    /**
912
     * Get validator for this field.
913
     *
914
     * @param array $input
915
     *
916
     * @return bool|\Illuminate\Contracts\Validation\Validator|mixed
917
     */
918
    public function getValidator(array $input)
919
    {
920
        if ($this->validator) {
921
            return $this->validator->call($this, $input);
922
        }
923
924
        $rules = $attributes = [];
925
926
        if (!$fieldRules = $this->getRules()) {
927
            return false;
928
        }
929
930
        if (is_string($this->column)) {
931
            if (!Arr::has($input, $this->column)) {
932
                return false;
933
            }
934
935
            $input = $this->sanitizeInput($input, $this->column);
936
937
            $rules[$this->column] = $fieldRules;
938
            $attributes[$this->column] = $this->label;
939
        }
940
941
        if (is_array($this->column)) {
942
            foreach ($this->column as $key => $column) {
943
                if (!array_key_exists($column, $input)) {
944
                    continue;
945
                }
946
                $input[$column.$key] = Arr::get($input, $column);
947
                $rules[$column.$key] = $fieldRules;
948
                $attributes[$column.$key] = $this->label."[$column]";
949
            }
950
        }
951
952
        return \validator($input, $rules, $this->getValidationMessages(), $attributes);
953
    }
954
955
    /**
956
     * Sanitize input data.
957
     *
958
     * @param array  $input
959
     * @param string $column
960
     *
961
     * @return array
962
     */
963
    protected function sanitizeInput($input, $column)
964
    {
965
        if ($this instanceof Field\MultipleSelect) {
966
            $value = Arr::get($input, $column);
967
            Arr::set($input, $column, array_filter($value));
968
        }
969
970
        return $input;
971
    }
972
973
    /**
974
     * Add html attributes to elements.
975
     *
976
     * @param array|string $attribute
977
     * @param mixed        $value
978
     *
979
     * @return $this
980
     */
981
    public function attribute($attribute, $value = null): self
982
    {
983
        if (is_array($attribute)) {
984
            $this->attributes = array_merge($this->attributes, $attribute);
985
        } else {
986
            $this->attributes[$attribute] = (string) $value;
987
        }
988
989
        return $this;
990
    }
991
992
    /**
993
     * Remove html attributes from elements.
994
     *
995
     * @param array|string $attribute
996
     *
997
     * @return $this
998
     */
999
    public function removeAttribute($attribute): self
1000
    {
1001
        Arr::forget($this->attributes, $attribute);
1002
1003
        return $this;
1004
    }
1005
1006
    /**
1007
     * Set Field style.
1008
     *
1009
     * @param string $attr
1010
     * @param string $value
1011
     *
1012
     * @return $this
1013
     */
1014
    public function style($attr, $value): self
1015
    {
1016
        return $this->attribute('style', "{$attr}: {$value}");
1017
    }
1018
1019
    /**
1020
     * Set Field width.
1021
     *
1022
     * @param string $width
1023
     *
1024
     * @return $this
1025
     */
1026
    public function width($width): self
1027
    {
1028
        return $this->style('width', $width);
1029
    }
1030
1031
    /**
1032
     * Specifies a regular expression against which to validate the value of the input.
1033
     *
1034
     * @param string $regexp
1035
     *
1036
     * @return $this
1037
     */
1038
    public function pattern($regexp): self
1039
    {
1040
        return $this->attribute('pattern', $regexp);
1041
    }
1042
1043
    /**
1044
     * set the input filed required.
1045
     *
1046
     * @param bool $isLabelAsterisked
1047
     *
1048
     * @return $this
1049
     */
1050
    public function required($isLabelAsterisked = true): self
1051
    {
1052
        if ($isLabelAsterisked) {
1053
            $this->setLabelClass(['asterisk']);
1054
        }
1055
1056
        return $this->attribute('required', true);
1057
    }
1058
1059
    /**
1060
     * Set the field automatically get focus.
1061
     *
1062
     * @return $this
1063
     */
1064
    public function autofocus(): self
1065
    {
1066
        return $this->attribute('autofocus', true);
1067
    }
1068
1069
    /**
1070
     * Set the field as readonly mode.
1071
     *
1072
     * @return $this
1073
     */
1074
    public function readonly()
1075
    {
1076
        return $this->attribute('readonly', true);
1077
    }
1078
1079
    /**
1080
     * Set field as disabled.
1081
     *
1082
     * @return $this
1083
     */
1084
    public function disable(): self
1085
    {
1086
        return $this->attribute('disabled', true);
1087
    }
1088
1089
    /**
1090
     * Set field placeholder.
1091
     *
1092
     * @param string $placeholder
1093
     *
1094
     * @return $this
1095
     */
1096
    public function placeholder($placeholder = ''): self
1097
    {
1098
        $this->placeholder = $placeholder;
1099
1100
        return $this;
1101
    }
1102
1103
    /**
1104
     * Get placeholder.
1105
     *
1106
     * @return mixed
1107
     */
1108
    public function getPlaceholder()
1109
    {
1110
        return $this->placeholder ?: trans('admin.input').' '.$this->label;
1111
    }
1112
1113
    /**
1114
     * Add a divider after this field.
1115
     *
1116
     * @return $this
1117
     */
1118
    public function divider()
1119
    {
1120
        $this->form->divider();
1121
1122
        return $this;
1123
    }
1124
1125
    /**
1126
     * Prepare for a field value before update or insert.
1127
     *
1128
     * @param $value
1129
     *
1130
     * @return mixed
1131
     */
1132
    public function prepare($value)
1133
    {
1134
        return $value;
1135
    }
1136
1137
    /**
1138
     * Format the field attributes.
1139
     *
1140
     * @return string
1141
     */
1142 View Code Duplication
    protected function formatAttributes(): string
1143
    {
1144
        $html = [];
1145
1146
        foreach ($this->attributes as $name => $value) {
1147
            $html[] = $name.'="'.e($value).'"';
1148
        }
1149
1150
        return implode(' ', $html);
1151
    }
1152
1153
    /**
1154
     * @return $this
1155
     */
1156
    public function disableHorizontal(): self
1157
    {
1158
        $this->horizontal = false;
1159
1160
        return $this;
1161
    }
1162
1163
    /**
1164
     * @return array
1165
     */
1166
    public function getViewElementClasses(): array
1167
    {
1168
        if ($this->horizontal) {
1169
            return [
1170
                'label'      => "col-sm-{$this->width['label']} {$this->getLabelClass()}",
1171
                'field'      => "col-sm-{$this->width['field']}",
1172
                'form-group' => $this->getGroupClass(true),
1173
            ];
1174
        }
1175
1176
        return ['label' => $this->getLabelClass(), 'field' => '', 'form-group' => ''];
1177
    }
1178
1179
    /**
1180
     * Set form element class.
1181
     *
1182
     * @param string|array $class
1183
     *
1184
     * @return $this
1185
     */
1186
    public function setElementClass($class): self
1187
    {
1188
        $this->elementClass = array_merge($this->elementClass, (array) $class);
1189
1190
        return $this;
1191
    }
1192
1193
    /**
1194
     * Get element class.
1195
     *
1196
     * @return array
1197
     */
1198
    public function getElementClass(): array
1199
    {
1200
        if (!$this->elementClass) {
1201
            $name = $this->elementName ?: $this->formatName($this->column);
1202
1203
            $this->elementClass = (array) str_replace(['[', ']'], '_', $name);
1204
        }
1205
1206
        return $this->elementClass;
1207
    }
1208
1209
    /**
1210
     * Get element class string.
1211
     *
1212
     * @return mixed
1213
     */
1214 View Code Duplication
    public function getElementClassString()
1215
    {
1216
        $elementClass = $this->getElementClass();
1217
1218
        if (Arr::isAssoc($elementClass)) {
1219
            $classes = [];
1220
1221
            foreach ($elementClass as $index => $class) {
1222
                $classes[$index] = is_array($class) ? implode(' ', $class) : $class;
1223
            }
1224
1225
            return $classes;
1226
        }
1227
1228
        return implode(' ', $elementClass);
1229
    }
1230
1231
    /**
1232
     * Get element class selector.
1233
     *
1234
     * @return string|array
1235
     */
1236 View Code Duplication
    public function getElementClassSelector()
1237
    {
1238
        $elementClass = $this->getElementClass();
1239
1240
        if (Arr::isAssoc($elementClass)) {
1241
            $classes = [];
1242
1243
            foreach ($elementClass as $index => $class) {
1244
                $classes[$index] = '.'.(is_array($class) ? implode('.', $class) : $class);
1245
            }
1246
1247
            return $classes;
1248
        }
1249
1250
        return '.'.implode('.', $elementClass);
1251
    }
1252
1253
    /**
1254
     * Add the element class.
1255
     *
1256
     * @param $class
1257
     *
1258
     * @return $this
1259
     */
1260
    public function addElementClass($class): self
1261
    {
1262
        if (is_array($class) || is_string($class)) {
1263
            $this->elementClass = array_unique(array_merge($this->elementClass, (array) $class));
1264
        }
1265
1266
        return $this;
1267
    }
1268
1269
    /**
1270
     * Remove element class.
1271
     *
1272
     * @param $class
1273
     *
1274
     * @return $this
1275
     */
1276
    public function removeElementClass($class): self
1277
    {
1278
        $delClass = [];
1279
1280
        if (is_string($class) || is_array($class)) {
1281
            $delClass = (array) $class;
1282
        }
1283
1284
        foreach ($delClass as $del) {
1285
            if (($key = array_search($del, $this->elementClass, true)) !== false) {
1286
                unset($this->elementClass[$key]);
1287
            }
1288
        }
1289
1290
        return $this;
1291
    }
1292
1293
    /**
1294
     * Set form group class.
1295
     *
1296
     * @param string|array $class
1297
     *
1298
     * @return $this
1299
     */
1300
    public function setGroupClass($class): self
1301
    {
1302
        if (is_array($class)) {
1303
            $this->groupClass = array_merge($this->groupClass, $class);
1304
        } else {
1305
            $this->groupClass[] = $class;
1306
        }
1307
1308
        return $this;
1309
    }
1310
1311
    /**
1312
     * Get element class.
1313
     *
1314
     * @param bool $default
1315
     *
1316
     * @return string
1317
     */
1318
    protected function getGroupClass($default = false): string
1319
    {
1320
        return ($default ? 'form-group ' : '').implode(' ', array_filter($this->groupClass));
1321
    }
1322
1323
    /**
1324
     * reset field className.
1325
     *
1326
     * @param string $className
1327
     * @param string $resetClassName
1328
     *
1329
     * @return $this
1330
     */
1331
    public function resetElementClassName(string $className, string $resetClassName): self
1332
    {
1333
        if (($key = array_search($className, $this->getElementClass())) !== false) {
1334
            $this->elementClass[$key] = $resetClassName;
1335
        }
1336
1337
        return $this;
1338
    }
1339
1340
    /**
1341
     * Add variables to field view.
1342
     *
1343
     * @param array $variables
1344
     *
1345
     * @return $this
1346
     */
1347
    public function addVariables(array $variables = []): self
1348
    {
1349
        $this->variables = array_merge($this->variables, $variables);
1350
1351
        return $this;
1352
    }
1353
1354
    /**
1355
     * @return string
1356
     */
1357
    public function getLabelClass(): string
1358
    {
1359
        return implode(' ', $this->labelClass);
1360
    }
1361
1362
    /**
1363
     * @param array $labelClass
1364
     *
1365
     * @return self
1366
     */
1367
    public function setLabelClass(array $labelClass): self
1368
    {
1369
        $this->labelClass = $labelClass;
1370
1371
        return $this;
1372
    }
1373
1374
    /**
1375
     * Get the view variables of this field.
1376
     *
1377
     * @return array
1378
     */
1379
    public function variables(): array
1380
    {
1381
        return array_merge($this->variables, [
1382
            'id'          => $this->id,
1383
            'name'        => $this->elementName ?: $this->formatName($this->column),
1384
            'help'        => $this->help,
1385
            'class'       => $this->getElementClassString(),
1386
            'value'       => $this->value(),
1387
            'label'       => $this->label,
1388
            'viewClass'   => $this->getViewElementClasses(),
1389
            'column'      => $this->column,
1390
            'errorKey'    => $this->getErrorKey(),
1391
            'attributes'  => $this->formatAttributes(),
1392
            'placeholder' => $this->getPlaceholder(),
1393
        ]);
1394
    }
1395
1396
    /**
1397
     * Get view of this field.
1398
     *
1399
     * @return string
1400
     */
1401
    public function getView(): string
1402
    {
1403
        if (!empty($this->view)) {
1404
            return $this->view;
1405
        }
1406
1407
        $class = explode('\\', static::class);
1408
1409
        return 'admin::form.'.strtolower(end($class));
1410
    }
1411
1412
    /**
1413
     * Set view of current field.
1414
     *
1415
     * @param string $view
1416
     *
1417
     * @return string
1418
     */
1419
    public function setView($view): self
1420
    {
1421
        $this->view = $view;
1422
1423
        return $this;
1424
    }
1425
1426
    /**
1427
     * Get script of current field.
1428
     *
1429
     * @return string
1430
     */
1431
    public function getScript(): string
1432
    {
1433
        return $this->script;
1434
    }
1435
1436
    /**
1437
     * Set script of current field.
1438
     *
1439
     * @param string $script
1440
     *
1441
     * @return $this
1442
     */
1443
    public function setScript($script): self
1444
    {
1445
        $this->script = $script;
1446
1447
        return $this;
1448
    }
1449
1450
    /**
1451
     * To set this field should render or not.
1452
     *
1453
     * @param bool $display
1454
     *
1455
     * @return $this
1456
     */
1457
    public function setDisplay(bool $display): self
1458
    {
1459
        $this->display = $display;
1460
1461
        return $this;
1462
    }
1463
1464
    /**
1465
     * If this field should render.
1466
     *
1467
     * @return bool
1468
     */
1469
    protected function shouldRender(): bool
1470
    {
1471
        if (!$this->display) {
1472
            return false;
1473
        }
1474
1475
        return true;
1476
    }
1477
1478
    /**
1479
     * @param \Closure $callback
1480
     *
1481
     * @return \Encore\Admin\Form\Field
1482
     */
1483
    public function with(Closure $callback): self
1484
    {
1485
        $this->callback = $callback;
1486
1487
        return $this;
1488
    }
1489
1490
    /**
1491
     * Render this filed.
1492
     *
1493
     * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View|string
1494
     */
1495
    public function render()
1496
    {
1497
        if (!$this->shouldRender()) {
1498
            return '';
1499
        }
1500
1501
        $this->addRequiredAttributeFromRules();
1502
1503
        if ($this->callback instanceof Closure) {
1504
            $this->value = $this->callback->call($this->form->model(), $this->value, $this);
1505
        }
1506
1507
        Admin::script($this->script);
1508
1509
        return view($this->getView(), $this->variables());
0 ignored issues
show
Bug Compatibility introduced by
The expression view($this->getView(), $this->variables()); of type Illuminate\View\View|Ill...\Contracts\View\Factory adds the type Illuminate\Contracts\View\Factory to the return on line 1509 which is incompatible with the return type declared by the interface Illuminate\Contracts\Support\Renderable::render of type string.
Loading history...
1510
    }
1511
1512
    /**
1513
     * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View|string
1514
     */
1515
    protected function fieldRender()
1516
    {
1517
        return self::render();
1518
    }
1519
1520
    /**
1521
     * @return string
1522
     */
1523
    public function __toString()
1524
    {
1525
        return $this->render()->render();
1526
    }
1527
}
1528