Completed
Pull Request — master (#3028)
by
unknown
03:24
created

Field::label()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 0
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Encore\Admin\Form;
4
5
use Encore\Admin\Admin;
6
use Encore\Admin\Form;
7
use Illuminate\Contracts\Support\Arrayable;
8
use Illuminate\Contracts\Support\Renderable;
9
use Illuminate\Support\Arr;
10
use Illuminate\Support\Facades\Validator;
11
use Illuminate\Support\Traits\Macroable;
12
13
/**
14
 * Class Field.
15
 */
16
class Field implements Renderable
17
{
18
    use Macroable;
19
20
    const FILE_DELETE_FLAG = '_file_del_';
21
22
    /**
23
     * Element id.
24
     *
25
     * @var array|string
26
     */
27
    protected $id;
28
29
    /**
30
     * Element value.
31
     *
32
     * @var mixed
33
     */
34
    protected $value;
35
36
    /**
37
     * Data of all original columns of value.
38
     *
39
     * @var mixed
40
     */
41
    protected $data;
42
43
    /**
44
     * Field original value.
45
     *
46
     * @var mixed
47
     */
48
    protected $original;
49
50
    /**
51
     * Field default value.
52
     *
53
     * @var mixed
54
     */
55
    protected $default;
56
57
    /**
58
     * Element label.
59
     *
60
     * @var string
61
     */
62
    protected $label = '';
63
64
    /**
65
     * Column name.
66
     *
67
     * @var string|array
68
     */
69
    protected $column = '';
70
71
    /**
72
     * Form element name.
73
     *
74
     * @var string
75
     */
76
    protected $elementName = [];
77
78
    /**
79
     * Form element classes.
80
     *
81
     * @var array
82
     */
83
    protected $elementClass = [];
84
85
    /**
86
     * Variables of elements.
87
     *
88
     * @var array
89
     */
90
    protected $variables = [];
91
92
    /**
93
     * Options for specify elements.
94
     *
95
     * @var array
96
     */
97
    protected $options = [];
98
99
    /**
100
     * Checked for specify elements.
101
     *
102
     * @var array
103
     */
104
    protected $checked = [];
105
106
    /**
107
     * Validation rules.
108
     *
109
     * @var string|\Closure
110
     */
111
    protected $rules = '';
112
113
    /**
114
     * @var callable
115
     */
116
    protected $validator;
117
118
    /**
119
     * Validation messages.
120
     *
121
     * @var array
122
     */
123
    protected $validationMessages = [];
124
125
    /**
126
     * Css required by this field.
127
     *
128
     * @var array
129
     */
130
    protected static $css = [];
131
132
    /**
133
     * Js required by this field.
134
     *
135
     * @var array
136
     */
137
    protected static $js = [];
138
139
    /**
140
     * Script for field.
141
     *
142
     * @var string
143
     */
144
    protected $script = '';
145
146
    /**
147
     * Element attributes.
148
     *
149
     * @var array
150
     */
151
    protected $attributes = [];
152
153
    /**
154
     * Parent form.
155
     *
156
     * @var Form
157
     */
158
    protected $form = null;
159
160
    /**
161
     * View for field to render.
162
     *
163
     * @var string
164
     */
165
    protected $view = '';
166
167
    /**
168
     * Help block.
169
     *
170
     * @var array
171
     */
172
    protected $help = [];
173
174
    /**
175
     * Key for errors.
176
     *
177
     * @var mixed
178
     */
179
    protected $errorKey;
180
181
    /**
182
     * Placeholder for this field.
183
     *
184
     * @var string|array
185
     */
186
    protected $placeholder;
187
188
    /**
189
     * Width for label and field.
190
     *
191
     * @var array
192
     */
193
    protected $width = [
194
        'label' => 2,
195
        'field' => 8,
196
    ];
197
198
    /**
199
     * If the form horizontal layout.
200
     *
201
     * @var bool
202
     */
203
    protected $horizontal = true;
204
205
    /**
206
     * column data format.
207
     *
208
     * @var \Closure
209
     */
210
    protected $customFormat = null;
211
212
    /**
213
     * @var bool
214
     */
215
    protected $display = true;
216
217
    /**
218
     * @var array
219
     */
220
    protected $labelClass = [];
221
222
    /**
223
     * Field constructor.
224
     *
225
     * @param       $column
226
     * @param array $arguments
227
     */
228
    public function __construct($column, $arguments = [])
229
    {
230
        $this->column = $column;
231
        $this->label = $this->formatLabel($arguments);
232
        $this->id = $this->formatId($column);
233
    }
234
235
    /**
236
     * Get assets required by this field.
237
     *
238
     * @return array
239
     */
240
    public static function getAssets()
241
    {
242
        return [
243
            'css' => static::$css,
244
            'js'  => static::$js,
245
        ];
246
    }
247
248
    /**
249
     * Format the field element id.
250
     *
251
     * @param string|array $column
252
     *
253
     * @return string|array
254
     */
255
    protected function formatId($column)
256
    {
257
        return str_replace('.', '_', $column);
258
    }
259
260
    /**
261
     * Format the label value.
262
     *
263
     * @param array $arguments
264
     *
265
     * @return string
266
     */
267
    protected function formatLabel($arguments = [])
268
    {
269
        $column = is_array($this->column) ? current($this->column) : $this->column;
270
271
        $label = isset($arguments[0]) ? $arguments[0] : ucfirst($column);
272
273
        return str_replace(['.', '_'], ' ', $label);
274
    }
275
276
    /**
277
     * Format the name of the field.
278
     *
279
     * @param string $column
280
     *
281
     * @return array|mixed|string
282
     */
283
    protected function formatName($column)
284
    {
285
        if (is_string($column)) {
286
            $name = explode('.', $column);
287
288
            if (count($name) == 1) {
289
                return $name[0];
290
            }
291
292
            $html = array_shift($name);
293
            foreach ($name as $piece) {
294
                $html .= "[$piece]";
295
            }
296
297
            return $html;
298
        }
299
300
        if (is_array($this->column)) {
301
            $names = [];
302
            foreach ($this->column as $key => $name) {
303
                $names[$key] = $this->formatName($name);
304
            }
305
306
            return $names;
307
        }
308
309
        return '';
310
    }
311
312
    /**
313
     * Set form element name.
314
     *
315
     * @param string $name
316
     *
317
     * @return $this
318
     *
319
     * @author Edwin Hui
320
     */
321
    public function setElementName($name)
322
    {
323
        $this->elementName = $name;
324
325
        return $this;
326
    }
327
328
    /**
329
     * Fill data to the field.
330
     *
331
     * @param array $data
332
     *
333
     * @return void
334
     */
335
    public function fill($data)
336
    {
337
        // Field value is already setted.
338
//        if (!is_null($this->value)) {
339
//            return;
340
//        }
341
342
        $this->data = $data;
343
344
        if (is_array($this->column)) {
345
            foreach ($this->column as $key => $column) {
346
                $this->value[$key] = array_get($data, $column);
347
            }
348
349
            return;
350
        }
351
352
        $this->value = array_get($data, $this->column);
353
        if (isset($this->customFormat) && $this->customFormat instanceof \Closure) {
354
            $this->value = call_user_func($this->customFormat, $this->value);
355
        }
356
    }
357
358
    /**
359
     * custom format form column data when edit.
360
     *
361
     * @param \Closure $call
362
     *
363
     * @return $this
364
     */
365
    public function customFormat(\Closure $call)
366
    {
367
        $this->customFormat = $call;
368
369
        return $this;
370
    }
371
372
    /**
373
     * Set original value to the field.
374
     *
375
     * @param array $data
376
     *
377
     * @return void
378
     */
379
    public function setOriginal($data)
380
    {
381
        if (is_array($this->column)) {
382
            foreach ($this->column as $key => $column) {
383
                $this->original[$key] = array_get($data, $column);
384
            }
385
386
            return;
387
        }
388
389
        $this->original = array_get($data, $this->column);
390
    }
391
392
    /**
393
     * @param Form $form
394
     *
395
     * @return $this
396
     */
397
    public function setForm(Form $form = null)
398
    {
399
        $this->form = $form;
400
401
        return $this;
402
    }
403
404
    /**
405
     * Set width for field and label.
406
     *
407
     * @param int $field
408
     * @param int $label
409
     *
410
     * @return $this
411
     */
412
    public function setWidth($field = 8, $label = 2)
413
    {
414
        $this->width = [
415
            'label' => $label,
416
            'field' => $field,
417
        ];
418
419
        return $this;
420
    }
421
422
    /**
423
     * Set the field options.
424
     *
425
     * @param array $options
426
     *
427
     * @return $this
428
     */
429 View Code Duplication
    public function options($options = [])
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
430
    {
431
        if ($options instanceof Arrayable) {
432
            $options = $options->toArray();
433
        }
434
435
        $this->options = array_merge($this->options, $options);
436
437
        return $this;
438
    }
439
440
    /**
441
     * Set the field option checked.
442
     *
443
     * @param array $checked
444
     *
445
     * @return $this
446
     */
447 View Code Duplication
    public function checked($checked = [])
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
448
    {
449
        if ($checked instanceof Arrayable) {
450
            $checked = $checked->toArray();
451
        }
452
453
        $this->checked = array_merge($this->checked, $checked);
454
455
        return $this;
456
    }
457
458
    /**
459
     * Get or set rules.
460
     *
461
     * @param null  $rules
462
     * @param array $messages
463
     *
464
     * @return $this
465
     */
466
    public function rules($rules = null, $messages = [])
467
    {
468
        if ($rules instanceof \Closure) {
469
            $this->rules = $rules;
470
        }
471
472
        if (is_array($rules)) {
473
            $thisRuleArr = array_filter(explode('|', $this->rules));
474
475
            $this->rules = array_merge($thisRuleArr, $rules);
0 ignored issues
show
Documentation Bug introduced by
It seems like array_merge($thisRuleArr, $rules) of type array is incompatible with the declared type string|object<Closure> of property $rules.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
476
            if (in_array('required', $this->rules)) $this->required();
477
        } elseif (is_string($rules)) {
478
            $rules = array_filter(explode('|', "{$this->rules}|$rules"));
479
480
            if (in_array('required', $rules)) $this->required();
481
            $this->rules = implode('|', $rules);
482
        }
483
484
        $this->validationMessages = $messages;
485
486
        return $this;
487
    }
488
489
    /**
490
     * Get field validation rules.
491
     *
492
     * @return string
493
     */
494
    protected function getRules()
495
    {
496
        if ($this->rules instanceof \Closure) {
497
            return $this->rules->call($this, $this->form);
498
        }
499
500
        return $this->rules;
501
    }
502
503
    /**
504
     * Remove a specific rule by keyword.
505
     *
506
     * @param string $rule
507
     *
508
     * @return void
509
     */
510
    protected function removeRule($rule)
511
    {
512
        if (!is_string($this->rules)) {
513
            return;
514
        }
515
516
        $pattern = "/{$rule}[^\|]?(\||$)/";
517
        $this->rules = preg_replace($pattern, '', $this->rules, -1);
518
    }
519
520
    /**
521
     * Set field validator.
522
     *
523
     * @param callable $validator
524
     *
525
     * @return $this
526
     */
527
    public function validator(callable $validator)
528
    {
529
        $this->validator = $validator;
530
531
        return $this;
532
    }
533
534
    /**
535
     * Get key for error message.
536
     *
537
     * @return string
538
     */
539
    public function getErrorKey()
540
    {
541
        return $this->errorKey ?: $this->column;
542
    }
543
544
    /**
545
     * Set key for error message.
546
     *
547
     * @param string $key
548
     *
549
     * @return $this
550
     */
551
    public function setErrorKey($key)
552
    {
553
        $this->errorKey = $key;
554
555
        return $this;
556
    }
557
558
    /**
559
     * Set or get value of the field.
560
     *
561
     * @param null $value
562
     *
563
     * @return mixed
564
     */
565 View Code Duplication
    public function value($value = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
566
    {
567
        if (is_null($value)) {
568
            return is_null($this->value) ? $this->getDefault() : $this->value;
569
        }
570
571
        $this->value = $value;
572
573
        return $this;
574
    }
575
576
    /**
577
     * Set or get data.
578
     *
579
     * @param array $data
580
     *
581
     * @return $this
582
     */
583
    public function data(array $data = null)
584
    {
585
        if (is_null($data)) {
586
            return $this->data;
587
        }
588
589
        $this->data = $data;
590
591
        return $this;
592
    }
593
594
    /**
595
     * Set default value for field.
596
     *
597
     * @param $default
598
     *
599
     * @return $this
600
     */
601
    public function default($default)
602
    {
603
        $this->default = $default;
604
605
        return $this;
606
    }
607
608
    /**
609
     * Get default value.
610
     *
611
     * @return mixed
612
     */
613
    public function getDefault()
614
    {
615
        if ($this->default instanceof \Closure) {
616
            return call_user_func($this->default, $this->form);
617
        }
618
619
        return $this->default;
620
    }
621
622
    /**
623
     * Set help block for current field.
624
     *
625
     * @param string $text
626
     * @param string $icon
627
     *
628
     * @return $this
629
     */
630
    public function help($text = '', $icon = 'fa-info-circle')
631
    {
632
        $this->help = compact('text', 'icon');
633
634
        return $this;
635
    }
636
637
    /**
638
     * Get column of the field.
639
     *
640
     * @return string|array
641
     */
642
    public function column()
643
    {
644
        return $this->column;
645
    }
646
647
    /**
648
     * Get label of the field.
649
     *
650
     * @return string
651
     */
652
    public function label()
653
    {
654
        return $this->label;
655
    }
656
657
    /**
658
     * Get original value of the field.
659
     *
660
     * @return mixed
661
     */
662
    public function original()
663
    {
664
        return $this->original;
665
    }
666
667
    /**
668
     * Get validator for this field.
669
     *
670
     * @param array $input
671
     *
672
     * @return bool|Validator
673
     */
674
    public function getValidator(array $input)
675
    {
676
        if ($this->validator) {
677
            return $this->validator->call($this, $input);
678
        }
679
680
        $rules = $attributes = [];
681
682
        if (!$fieldRules = $this->getRules()) {
683
            return false;
684
        }
685
686
        if (is_string($this->column)) {
687
            if (!array_has($input, $this->column)) {
688
                return false;
689
            }
690
691
            $input = $this->sanitizeInput($input, $this->column);
692
693
            $rules[$this->column] = $fieldRules;
694
            $attributes[$this->column] = $this->label;
695
        }
696
697
        if (is_array($this->column)) {
698
            foreach ($this->column as $key => $column) {
699
                if (!array_key_exists($column, $input)) {
700
                    continue;
701
                }
702
                $input[$column.$key] = array_get($input, $column);
703
                $rules[$column.$key] = $fieldRules;
704
                $attributes[$column.$key] = $this->label."[$column]";
705
            }
706
        }
707
708
        return Validator::make($input, $rules, $this->validationMessages, $attributes);
0 ignored issues
show
Bug Best Practice introduced by
The return type of return \Illuminate\Suppo...Messages, $attributes); (Illuminate\Contracts\Validation\Validator) is incompatible with the return type documented by Encore\Admin\Form\Field::getValidator of type boolean|Illuminate\Support\Facades\Validator.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
709
    }
710
711
    /**
712
     * Sanitize input data.
713
     *
714
     * @param array  $input
715
     * @param string $column
716
     *
717
     * @return array
718
     */
719
    protected function sanitizeInput($input, $column)
720
    {
721
        if ($this instanceof Field\MultipleSelect) {
722
            $value = array_get($input, $column);
723
            array_set($input, $column, array_filter($value));
724
        }
725
726
        return $input;
727
    }
728
729
    /**
730
     * Add html attributes to elements.
731
     *
732
     * @param array|string $attribute
733
     * @param mixed        $value
734
     *
735
     * @return $this
736
     */
737
    public function attribute($attribute, $value = null)
738
    {
739
        if (is_array($attribute)) {
740
            $this->attributes = array_merge($this->attributes, $attribute);
741
        } else {
742
            $this->attributes[$attribute] = (string) $value;
743
        }
744
745
        return $this;
746
    }
747
748
    /**
749
     * Specifies a regular expression against which to validate the value of the input.
750
     *
751
     * @param string $regexp
752
     *
753
     * @return Field
754
     */
755
    public function pattern($regexp)
756
    {
757
        return $this->attribute('pattern', $regexp);
758
    }
759
760
    /**
761
     * set the input filed required.
762
     *
763
     * @param bool $isLabelAsterisked
764
     *
765
     * @return Field
766
     */
767
    public function required($isLabelAsterisked = true)
768
    {
769
        if ($isLabelAsterisked) {
770
            $this->setLabelClass(['asterisk']);
771
        }
772
773
        return $this->attribute('required', true);
774
    }
775
776
    /**
777
     * Set the field automatically get focus.
778
     *
779
     * @return Field
780
     */
781
    public function autofocus()
782
    {
783
        return $this->attribute('autofocus', true);
784
    }
785
786
    /**
787
     * Set the field as readonly mode.
788
     *
789
     * @return Field
790
     */
791
    public function readOnly()
792
    {
793
        return $this->attribute('readonly', true);
794
    }
795
796
    /**
797
     * Set field as disabled.
798
     *
799
     * @return Field
800
     */
801
    public function disable()
802
    {
803
        return $this->attribute('disabled', true);
804
    }
805
806
    /**
807
     * Set field placeholder.
808
     *
809
     * @param string $placeholder
810
     *
811
     * @return Field
812
     */
813
    public function placeholder($placeholder = '')
814
    {
815
        $this->placeholder = $placeholder;
816
817
        return $this;
818
    }
819
820
    /**
821
     * Get placeholder.
822
     *
823
     * @return string
824
     */
825
    public function getPlaceholder()
826
    {
827
        return $this->placeholder ?: trans('admin.input').' '.$this->label;
828
    }
829
830
    /**
831
     * Prepare for a field value before update or insert.
832
     *
833
     * @param $value
834
     *
835
     * @return mixed
836
     */
837
    public function prepare($value)
838
    {
839
        return $value;
840
    }
841
842
    /**
843
     * Format the field attributes.
844
     *
845
     * @return string
846
     */
847
    protected function formatAttributes()
848
    {
849
        $html = [];
850
851
        foreach ($this->attributes as $name => $value) {
852
            $html[] = $name.'="'.e($value).'"';
853
        }
854
855
        return implode(' ', $html);
856
    }
857
858
    /**
859
     * @return $this
860
     */
861
    public function disableHorizontal()
862
    {
863
        $this->horizontal = false;
864
865
        return $this;
866
    }
867
868
    /**
869
     * @return array
870
     */
871
    public function getViewElementClasses()
872
    {
873
        if ($this->horizontal) {
874
            return [
875
                'label'      => "col-sm-{$this->width['label']} {$this->getLabelClass()}",
876
                'field'      => "col-sm-{$this->width['field']}",
877
                'form-group' => 'form-group ',
878
            ];
879
        }
880
881
        return ['label' => "{$this->getLabelClass()}", 'field' => '', 'form-group' => ''];
882
    }
883
884
    /**
885
     * Set form element class.
886
     *
887
     * @param string|array $class
888
     *
889
     * @return $this
890
     */
891
    public function setElementClass($class)
892
    {
893
        $this->elementClass = array_merge($this->elementClass, (array) $class);
894
895
        return $this;
896
    }
897
898
    /**
899
     * Get element class.
900
     *
901
     * @return array
902
     */
903
    protected function getElementClass()
904
    {
905
        if (!$this->elementClass) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->elementClass of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
906
            $name = $this->elementName ?: $this->formatName($this->column);
0 ignored issues
show
Bug introduced by
It seems like $this->column can also be of type array; however, Encore\Admin\Form\Field::formatName() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
907
908
            $this->elementClass = (array) str_replace(['[', ']'], '_', $name);
909
        }
910
911
        return $this->elementClass;
912
    }
913
914
    /**
915
     * Get element class string.
916
     *
917
     * @return mixed
918
     */
919 View Code Duplication
    protected function getElementClassString()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
920
    {
921
        $elementClass = $this->getElementClass();
922
923
        if (Arr::isAssoc($elementClass)) {
924
            $classes = [];
925
926
            foreach ($elementClass as $index => $class) {
927
                $classes[$index] = is_array($class) ? implode(' ', $class) : $class;
928
            }
929
930
            return $classes;
931
        }
932
933
        return implode(' ', $elementClass);
934
    }
935
936
    /**
937
     * Get element class selector.
938
     *
939
     * @return string|array
940
     */
941 View Code Duplication
    protected function getElementClassSelector()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
942
    {
943
        $elementClass = $this->getElementClass();
944
945
        if (Arr::isAssoc($elementClass)) {
946
            $classes = [];
947
948
            foreach ($elementClass as $index => $class) {
949
                $classes[$index] = '.'.(is_array($class) ? implode('.', $class) : $class);
950
            }
951
952
            return $classes;
953
        }
954
955
        return '.'.implode('.', $elementClass);
956
    }
957
958
    /**
959
     * Add the element class.
960
     *
961
     * @param $class
962
     *
963
     * @return $this
964
     */
965
    public function addElementClass($class)
966
    {
967
        if (is_array($class) || is_string($class)) {
968
            $this->elementClass = array_merge($this->elementClass, (array) $class);
969
970
            $this->elementClass = array_unique($this->elementClass);
971
        }
972
973
        return $this;
974
    }
975
976
    /**
977
     * Remove element class.
978
     *
979
     * @param $class
980
     *
981
     * @return $this
982
     */
983
    public function removeElementClass($class)
984
    {
985
        $delClass = [];
986
987
        if (is_string($class) || is_array($class)) {
988
            $delClass = (array) $class;
989
        }
990
991
        foreach ($delClass as $del) {
992
            if (($key = array_search($del, $this->elementClass))) {
993
                unset($this->elementClass[$key]);
994
            }
995
        }
996
997
        return $this;
998
    }
999
1000
    /**
1001
     * Add variables to field view.
1002
     *
1003
     * @param array $variables
1004
     *
1005
     * @return $this
1006
     */
1007
    protected function addVariables(array $variables = [])
1008
    {
1009
        $this->variables = array_merge($this->variables, $variables);
1010
1011
        return $this;
1012
    }
1013
1014
    /**
1015
     * @return string
1016
     */
1017
    public function getLabelClass()
1018
    : string
1019
    {
1020
        return implode(' ', $this->labelClass);
1021
    }
1022
1023
    /**
1024
     * @param array $labelClass
1025
     *
1026
     * @return self
1027
     */
1028
    public function setLabelClass(array $labelClass)
1029
    : self
1030
    {
1031
        $this->labelClass = $labelClass;
1032
1033
        return $this;
1034
    }
1035
1036
    /**
1037
     * Get the view variables of this field.
1038
     *
1039
     * @return array
1040
     */
1041
    public function variables()
1042
    {
1043
        return array_merge($this->variables, [
1044
            'id'          => $this->id,
1045
            'name'        => $this->elementName ?: $this->formatName($this->column),
0 ignored issues
show
Bug introduced by
It seems like $this->column can also be of type array; however, Encore\Admin\Form\Field::formatName() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
1046
            'help'        => $this->help,
1047
            'class'       => $this->getElementClassString(),
1048
            'value'       => $this->value(),
1049
            'label'       => $this->label,
1050
            'viewClass'   => $this->getViewElementClasses(),
1051
            'column'      => $this->column,
1052
            'errorKey'    => $this->getErrorKey(),
1053
            'attributes'  => $this->formatAttributes(),
1054
            'placeholder' => $this->getPlaceholder(),
1055
        ]);
1056
    }
1057
1058
    /**
1059
     * Get view of this field.
1060
     *
1061
     * @return string
1062
     */
1063
    public function getView()
1064
    {
1065
        if (!empty($this->view)) {
1066
            return $this->view;
1067
        }
1068
1069
        $class = explode('\\', get_called_class());
1070
1071
        return 'admin::form.'.strtolower(end($class));
1072
    }
1073
1074
    /**
1075
     * Get script of current field.
1076
     *
1077
     * @return string
1078
     */
1079
    public function getScript()
1080
    {
1081
        return $this->script;
1082
    }
1083
1084
    /**
1085
     * Set script of current field.
1086
     *
1087
     * @return self
1088
     */
1089
    public function setScript($script)
1090
    {
1091
        $this->script = $script;
1092
1093
        return $this;
1094
    }
1095
1096
    /**
1097
     * To set this field should render or not.
1098
     *
1099
     * @return self
1100
     */
1101
    public function setDisplay(bool $display)
1102
    {
1103
        $this->display = $display;
1104
1105
        return $this;
1106
    }
1107
1108
    /**
1109
     * If this field should render.
1110
     *
1111
     * @return bool
1112
     */
1113
    protected function shouldRender()
1114
    {
1115
        if (!$this->display) {
1116
            return false;
1117
        }
1118
1119
        return true;
1120
    }
1121
1122
    /**
1123
     * Render this filed.
1124
     *
1125
     * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View|string
1126
     */
1127
    public function render()
1128
    {
1129
        if (!$this->shouldRender()) {
1130
            return '';
1131
        }
1132
1133
        Admin::script($this->script);
1134
1135
        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 1135 which is incompatible with the return type declared by the interface Illuminate\Contracts\Support\Renderable::render of type string.
Loading history...
1136
    }
1137
1138
    /**
1139
     * @return string
1140
     */
1141
    public function __toString()
1142
    {
1143
        return $this->render()->render();
0 ignored issues
show
Bug introduced by
The method render does only exist in Illuminate\View\View, but not in Illuminate\Contracts\View\Factory.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
1144
    }
1145
}
1146