Completed
Push — master ( 012343...f524a9 )
by jxlwqq
05:18 queued 02:33
created

src/Form/Field.php (2 issues)

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|WidgetForm
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
        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
            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()
0 ignored issues
show
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...
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()
0 ignored issues
show
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...
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
     * @param bool  $replace
1365
     *
1366
     * @return self
1367
     */
1368
    public function setLabelClass(array $labelClass, $replace = false): self
1369
    {
1370
        $this->labelClass = $replace ? $labelClass : array_merge($this->labelClass, $labelClass);
1371
1372
        return $this;
1373
    }
1374
1375
    /**
1376
     * Get the view variables of this field.
1377
     *
1378
     * @return array
1379
     */
1380
    public function variables(): array
1381
    {
1382
        return array_merge($this->variables, [
1383
            'id'          => $this->id,
1384
            'name'        => $this->elementName ?: $this->formatName($this->column),
1385
            'help'        => $this->help,
1386
            'class'       => $this->getElementClassString(),
1387
            'value'       => $this->value(),
1388
            'label'       => $this->label,
1389
            'viewClass'   => $this->getViewElementClasses(),
1390
            'column'      => $this->column,
1391
            'errorKey'    => $this->getErrorKey(),
1392
            'attributes'  => $this->formatAttributes(),
1393
            'placeholder' => $this->getPlaceholder(),
1394
        ]);
1395
    }
1396
1397
    /**
1398
     * Get view of this field.
1399
     *
1400
     * @return string
1401
     */
1402
    public function getView(): string
1403
    {
1404
        if (!empty($this->view)) {
1405
            return $this->view;
1406
        }
1407
1408
        $class = explode('\\', static::class);
1409
1410
        return 'admin::form.'.strtolower(end($class));
1411
    }
1412
1413
    /**
1414
     * Set view of current field.
1415
     *
1416
     * @param string $view
1417
     *
1418
     * @return string
1419
     */
1420
    public function setView($view): self
1421
    {
1422
        $this->view = $view;
1423
1424
        return $this;
1425
    }
1426
1427
    /**
1428
     * Get script of current field.
1429
     *
1430
     * @return string
1431
     */
1432
    public function getScript(): string
1433
    {
1434
        return $this->script;
1435
    }
1436
1437
    /**
1438
     * Set script of current field.
1439
     *
1440
     * @param string $script
1441
     *
1442
     * @return $this
1443
     */
1444
    public function setScript($script): self
1445
    {
1446
        $this->script = $script;
1447
1448
        return $this;
1449
    }
1450
1451
    /**
1452
     * To set this field should render or not.
1453
     *
1454
     * @param bool $display
1455
     *
1456
     * @return $this
1457
     */
1458
    public function setDisplay(bool $display): self
1459
    {
1460
        $this->display = $display;
1461
1462
        return $this;
1463
    }
1464
1465
    /**
1466
     * If this field should render.
1467
     *
1468
     * @return bool
1469
     */
1470
    protected function shouldRender(): bool
1471
    {
1472
        if (!$this->display) {
1473
            return false;
1474
        }
1475
1476
        return true;
1477
    }
1478
1479
    /**
1480
     * @param \Closure $callback
1481
     *
1482
     * @return \Encore\Admin\Form\Field
1483
     */
1484
    public function with(Closure $callback): self
1485
    {
1486
        $this->callback = $callback;
1487
1488
        return $this;
1489
    }
1490
1491
    /**
1492
     * Render this filed.
1493
     *
1494
     * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View|string
1495
     */
1496
    public function render()
1497
    {
1498
        if (!$this->shouldRender()) {
1499
            return '';
1500
        }
1501
1502
        $this->addRequiredAttributeFromRules();
1503
1504
        if ($this->callback instanceof Closure) {
1505
            $this->value = $this->callback->call($this->form->model(), $this->value, $this);
1506
        }
1507
1508
        Admin::script($this->script);
1509
1510
        return Admin::component($this->getView(), $this->variables());
1511
    }
1512
1513
    /**
1514
     * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View|string
1515
     */
1516
    protected function fieldRender(array $variables = [])
1517
    {
1518
        if (!empty($variables)) {
1519
            $this->addVariables($variables);
1520
        }
1521
1522
        return self::render();
1523
    }
1524
1525
    /**
1526
     * @return string
1527
     */
1528
    public function __toString()
1529
    {
1530
        return $this->render()->render();
1531
    }
1532
}
1533