Completed
Push — master ( 3ef35a...151460 )
by Song
03:41
created

Field::addRequiredAttribute()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
nc 3
nop 1
dl 0
loc 14
rs 9.7998
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
    const FILE_SORT_FLAG = '_file_sort_';
22
23
    /**
24
     * Element id.
25
     *
26
     * @var array|string
27
     */
28
    protected $id;
29
30
    /**
31
     * Element value.
32
     *
33
     * @var mixed
34
     */
35
    protected $value;
36
37
    /**
38
     * Data of all original columns of value.
39
     *
40
     * @var mixed
41
     */
42
    protected $data;
43
44
    /**
45
     * Field original value.
46
     *
47
     * @var mixed
48
     */
49
    protected $original;
50
51
    /**
52
     * Field default value.
53
     *
54
     * @var mixed
55
     */
56
    protected $default;
57
58
    /**
59
     * Element label.
60
     *
61
     * @var string
62
     */
63
    protected $label = '';
64
65
    /**
66
     * Column name.
67
     *
68
     * @var string|array
69
     */
70
    protected $column = '';
71
72
    /**
73
     * Form element name.
74
     *
75
     * @var string
76
     */
77
    protected $elementName = [];
78
79
    /**
80
     * Form element classes.
81
     *
82
     * @var array
83
     */
84
    protected $elementClass = [];
85
86
    /**
87
     * Variables of elements.
88
     *
89
     * @var array
90
     */
91
    protected $variables = [];
92
93
    /**
94
     * Options for specify elements.
95
     *
96
     * @var array
97
     */
98
    protected $options = [];
99
100
    /**
101
     * Checked for specify elements.
102
     *
103
     * @var array
104
     */
105
    protected $checked = [];
106
107
    /**
108
     * Validation rules.
109
     *
110
     * @var string|\Closure
111
     */
112
    protected $rules = '';
113
114
    /**
115
     * @var callable
116
     */
117
    protected $validator;
118
119
    /**
120
     * Validation messages.
121
     *
122
     * @var array
123
     */
124
    protected $validationMessages = [];
125
126
    /**
127
     * Css required by this field.
128
     *
129
     * @var array
130
     */
131
    protected static $css = [];
132
133
    /**
134
     * Js required by this field.
135
     *
136
     * @var array
137
     */
138
    protected static $js = [];
139
140
    /**
141
     * Script for field.
142
     *
143
     * @var string
144
     */
145
    protected $script = '';
146
147
    /**
148
     * Element attributes.
149
     *
150
     * @var array
151
     */
152
    protected $attributes = [];
153
154
    /**
155
     * Parent form.
156
     *
157
     * @var Form
158
     */
159
    protected $form = null;
160
161
    /**
162
     * View for field to render.
163
     *
164
     * @var string
165
     */
166
    protected $view = '';
167
168
    /**
169
     * Help block.
170
     *
171
     * @var array
172
     */
173
    protected $help = [];
174
175
    /**
176
     * Key for errors.
177
     *
178
     * @var mixed
179
     */
180
    protected $errorKey;
181
182
    /**
183
     * Placeholder for this field.
184
     *
185
     * @var string|array
186
     */
187
    protected $placeholder;
188
189
    /**
190
     * Width for label and field.
191
     *
192
     * @var array
193
     */
194
    protected $width = [
195
        'label' => 2,
196
        'field' => 8,
197
    ];
198
199
    /**
200
     * If the form horizontal layout.
201
     *
202
     * @var bool
203
     */
204
    protected $horizontal = true;
205
206
    /**
207
     * column data format.
208
     *
209
     * @var \Closure
210
     */
211
    protected $customFormat = null;
212
213
    /**
214
     * @var bool
215
     */
216
    protected $display = true;
217
218
    /**
219
     * @var array
220
     */
221
    protected $labelClass = [];
222
223
    /**
224
     * @var array
225
     */
226
    protected $groupClass = [];
227
228
    /**
229
     * Field constructor.
230
     *
231
     * @param       $column
232
     * @param array $arguments
233
     */
234
    public function __construct($column, $arguments = [])
235
    {
236
        $this->column = $column;
237
        $this->label = $this->formatLabel($arguments);
238
        $this->id = $this->formatId($column);
239
    }
240
241
    /**
242
     * Get assets required by this field.
243
     *
244
     * @return array
245
     */
246
    public static function getAssets()
247
    {
248
        return [
249
            'css' => static::$css,
250
            'js'  => static::$js,
251
        ];
252
    }
253
254
    /**
255
     * Format the field element id.
256
     *
257
     * @param string|array $column
258
     *
259
     * @return string|array
260
     */
261
    protected function formatId($column)
262
    {
263
        return str_replace('.', '_', $column);
264
    }
265
266
    /**
267
     * Format the label value.
268
     *
269
     * @param array $arguments
270
     *
271
     * @return string
272
     */
273
    protected function formatLabel($arguments = [])
274
    {
275
        $column = is_array($this->column) ? current($this->column) : $this->column;
276
277
        $label = isset($arguments[0]) ? $arguments[0] : ucfirst($column);
278
279
        return str_replace(['.', '_'], ' ', $label);
280
    }
281
282
    /**
283
     * Format the name of the field.
284
     *
285
     * @param string $column
286
     *
287
     * @return array|mixed|string
288
     */
289
    protected function formatName($column)
290
    {
291
        if (is_string($column)) {
292
            $name = explode('.', $column);
293
294
            if (count($name) == 1) {
295
                return $name[0];
296
            }
297
298
            $html = array_shift($name);
299
            foreach ($name as $piece) {
300
                $html .= "[$piece]";
301
            }
302
303
            return $html;
304
        }
305
306
        if (is_array($this->column)) {
307
            $names = [];
308
            foreach ($this->column as $key => $name) {
309
                $names[$key] = $this->formatName($name);
310
            }
311
312
            return $names;
313
        }
314
315
        return '';
316
    }
317
318
    /**
319
     * Set form element name.
320
     *
321
     * @param string $name
322
     *
323
     * @return $this
324
     *
325
     * @author Edwin Hui
326
     */
327
    public function setElementName($name)
328
    {
329
        $this->elementName = $name;
330
331
        return $this;
332
    }
333
334
    /**
335
     * Fill data to the field.
336
     *
337
     * @param array $data
338
     *
339
     * @return void
340
     */
341
    public function fill($data)
342
    {
343
        // Field value is already setted.
344
//        if (!is_null($this->value)) {
345
//            return;
346
//        }
347
348
        $this->data = $data;
349
350
        if (is_array($this->column)) {
351
            foreach ($this->column as $key => $column) {
352
                $this->value[$key] = Arr::get($data, $column);
353
            }
354
355
            return;
356
        }
357
358
        $this->value = Arr::get($data, $this->column);
359
        if (isset($this->customFormat) && $this->customFormat instanceof \Closure) {
360
            $this->value = call_user_func($this->customFormat, $this->value);
361
        }
362
    }
363
364
    /**
365
     * custom format form column data when edit.
366
     *
367
     * @param \Closure $call
368
     *
369
     * @return $this
370
     */
371
    public function customFormat(\Closure $call)
372
    {
373
        $this->customFormat = $call;
374
375
        return $this;
376
    }
377
378
    /**
379
     * Set original value to the field.
380
     *
381
     * @param array $data
382
     *
383
     * @return void
384
     */
385
    public function setOriginal($data)
386
    {
387
        if (is_array($this->column)) {
388
            foreach ($this->column as $key => $column) {
389
                $this->original[$key] = Arr::get($data, $column);
390
            }
391
392
            return;
393
        }
394
395
        $this->original = Arr::get($data, $this->column);
396
    }
397
398
    /**
399
     * @param Form $form
400
     *
401
     * @return $this
402
     */
403
    public function setForm(Form $form = null)
404
    {
405
        $this->form = $form;
406
407
        return $this;
408
    }
409
410
    /**
411
     * Set width for field and label.
412
     *
413
     * @param int $field
414
     * @param int $label
415
     *
416
     * @return $this
417
     */
418
    public function setWidth($field = 8, $label = 2)
419
    {
420
        $this->width = [
421
            'label' => $label,
422
            'field' => $field,
423
        ];
424
425
        return $this;
426
    }
427
428
    /**
429
     * Set the field options.
430
     *
431
     * @param array $options
432
     *
433
     * @return $this
434
     */
435 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...
436
    {
437
        if ($options instanceof Arrayable) {
438
            $options = $options->toArray();
439
        }
440
441
        $this->options = array_merge($this->options, $options);
442
443
        return $this;
444
    }
445
446
    /**
447
     * Set the field option checked.
448
     *
449
     * @param array $checked
450
     *
451
     * @return $this
452
     */
453 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...
454
    {
455
        if ($checked instanceof Arrayable) {
456
            $checked = $checked->toArray();
457
        }
458
459
        $this->checked = array_merge($this->checked, $checked);
460
461
        return $this;
462
    }
463
464
    /**
465
     * Add `required` attribute to current field if has required rule,
466
     * except file and image fields.
467
     *
468
     * @param array $rules
469
     */
470
    protected function addRequiredAttribute($rules)
471
    {
472
        if (!in_array('required', $rules)) {
473
            return;
474
        }
475
476
        if ($this instanceof Form\Field\MultipleFile
477
            || $this instanceof Form\Field\File)
478
        {
479
            return;
480
        }
481
482
        $this->required();
483
    }
484
485
    /**
486
     * Get or set rules.
487
     *
488
     * @param null  $rules
489
     * @param array $messages
490
     *
491
     * @return $this
492
     */
493
    public function rules($rules = null, $messages = [])
494
    {
495
        if ($rules instanceof \Closure) {
496
            $this->rules = $rules;
497
        }
498
499
        if (is_array($rules)) {
500
            $thisRuleArr = array_filter(explode('|', $this->rules));
501
502
            $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...
503
504
            $this->addRequiredAttribute($this->rules);
505
506
        } elseif (is_string($rules)) {
507
            $rules = array_filter(explode('|', "{$this->rules}|$rules"));
508
509
            $this->addRequiredAttribute($rules);
510
511
            $this->rules = implode('|', $rules);
512
        }
513
514
        $this->validationMessages = $messages;
515
516
        return $this;
517
    }
518
519
    /**
520
     * Get field validation rules.
521
     *
522
     * @return string
523
     */
524
    protected function getRules()
525
    {
526
        if ($this->rules instanceof \Closure) {
527
            return $this->rules->call($this, $this->form);
528
        }
529
530
        return $this->rules;
531
    }
532
533
    /**
534
     * Remove a specific rule by keyword.
535
     *
536
     * @param string $rule
537
     *
538
     * @return void
539
     */
540
    protected function removeRule($rule)
541
    {
542
        if (!is_string($this->rules)) {
543
            return;
544
        }
545
546
        $pattern = "/{$rule}[^\|]?(\||$)/";
547
        $this->rules = preg_replace($pattern, '', $this->rules, -1);
548
    }
549
550
    /**
551
     * Set field validator.
552
     *
553
     * @param callable $validator
554
     *
555
     * @return $this
556
     */
557
    public function validator(callable $validator)
558
    {
559
        $this->validator = $validator;
560
561
        return $this;
562
    }
563
564
    /**
565
     * Get key for error message.
566
     *
567
     * @return string
568
     */
569
    public function getErrorKey()
570
    {
571
        return $this->errorKey ?: $this->column;
572
    }
573
574
    /**
575
     * Set key for error message.
576
     *
577
     * @param string $key
578
     *
579
     * @return $this
580
     */
581
    public function setErrorKey($key)
582
    {
583
        $this->errorKey = $key;
584
585
        return $this;
586
    }
587
588
    /**
589
     * Set or get value of the field.
590
     *
591
     * @param null $value
592
     *
593
     * @return mixed
594
     */
595 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...
596
    {
597
        if (is_null($value)) {
598
            return is_null($this->value) ? $this->getDefault() : $this->value;
599
        }
600
601
        $this->value = $value;
602
603
        return $this;
604
    }
605
606
    /**
607
     * Set or get data.
608
     *
609
     * @param array $data
610
     *
611
     * @return $this
612
     */
613
    public function data(array $data = null)
614
    {
615
        if (is_null($data)) {
616
            return $this->data;
617
        }
618
619
        $this->data = $data;
620
621
        return $this;
622
    }
623
624
    /**
625
     * Set default value for field.
626
     *
627
     * @param $default
628
     *
629
     * @return $this
630
     */
631
    public function default($default)
632
    {
633
        $this->default = $default;
634
635
        return $this;
636
    }
637
638
    /**
639
     * Get default value.
640
     *
641
     * @return mixed
642
     */
643
    public function getDefault()
644
    {
645
        if ($this->default instanceof \Closure) {
646
            return call_user_func($this->default, $this->form);
647
        }
648
649
        return $this->default;
650
    }
651
652
    /**
653
     * Set help block for current field.
654
     *
655
     * @param string $text
656
     * @param string $icon
657
     *
658
     * @return $this
659
     */
660
    public function help($text = '', $icon = 'fa-info-circle')
661
    {
662
        $this->help = compact('text', 'icon');
663
664
        return $this;
665
    }
666
667
    /**
668
     * Get column of the field.
669
     *
670
     * @return string|array
671
     */
672
    public function column()
673
    {
674
        return $this->column;
675
    }
676
677
    /**
678
     * Get label of the field.
679
     *
680
     * @return string
681
     */
682
    public function label()
683
    {
684
        return $this->label;
685
    }
686
687
    /**
688
     * Get original value of the field.
689
     *
690
     * @return mixed
691
     */
692
    public function original()
693
    {
694
        return $this->original;
695
    }
696
697
    /**
698
     * Get validator for this field.
699
     *
700
     * @param array $input
701
     *
702
     * @return bool|Validator
703
     */
704
    public function getValidator(array $input)
705
    {
706
        if ($this->validator) {
707
            return $this->validator->call($this, $input);
708
        }
709
710
        $rules = $attributes = [];
711
712
        if (!$fieldRules = $this->getRules()) {
713
            return false;
714
        }
715
716
        if (is_string($this->column)) {
717
            if (!Arr::has($input, $this->column)) {
718
                return false;
719
            }
720
721
            $input = $this->sanitizeInput($input, $this->column);
722
723
            $rules[$this->column] = $fieldRules;
724
            $attributes[$this->column] = $this->label;
725
        }
726
727
        if (is_array($this->column)) {
728
            foreach ($this->column as $key => $column) {
729
                if (!array_key_exists($column, $input)) {
730
                    continue;
731
                }
732
                $input[$column.$key] = Arr::get($input, $column);
733
                $rules[$column.$key] = $fieldRules;
734
                $attributes[$column.$key] = $this->label."[$column]";
735
            }
736
        }
737
738
        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...
739
    }
740
741
    /**
742
     * Sanitize input data.
743
     *
744
     * @param array  $input
745
     * @param string $column
746
     *
747
     * @return array
748
     */
749
    protected function sanitizeInput($input, $column)
750
    {
751
        if ($this instanceof Field\MultipleSelect) {
752
            $value = Arr::get($input, $column);
753
            Arr::set($input, $column, array_filter($value));
754
        }
755
756
        return $input;
757
    }
758
759
    /**
760
     * Add html attributes to elements.
761
     *
762
     * @param array|string $attribute
763
     * @param mixed        $value
764
     *
765
     * @return $this
766
     */
767
    public function attribute($attribute, $value = null)
768
    {
769
        if (is_array($attribute)) {
770
            $this->attributes = array_merge($this->attributes, $attribute);
771
        } else {
772
            $this->attributes[$attribute] = (string) $value;
773
        }
774
775
        return $this;
776
    }
777
778
    /**
779
     * Specifies a regular expression against which to validate the value of the input.
780
     *
781
     * @param string $regexp
782
     *
783
     * @return Field
784
     */
785
    public function pattern($regexp)
786
    {
787
        return $this->attribute('pattern', $regexp);
788
    }
789
790
    /**
791
     * set the input filed required.
792
     *
793
     * @param bool $isLabelAsterisked
794
     *
795
     * @return Field
796
     */
797
    public function required($isLabelAsterisked = true)
798
    {
799
        if ($isLabelAsterisked) {
800
            $this->setLabelClass(['asterisk']);
801
        }
802
803
        return $this->attribute('required', true);
804
    }
805
806
    /**
807
     * Set the field automatically get focus.
808
     *
809
     * @return Field
810
     */
811
    public function autofocus()
812
    {
813
        return $this->attribute('autofocus', true);
814
    }
815
816
    /**
817
     * Set the field as readonly mode.
818
     *
819
     * @return Field
820
     */
821
    public function readOnly()
822
    {
823
        return $this->attribute('readonly', true);
824
    }
825
826
    /**
827
     * Set field as disabled.
828
     *
829
     * @return Field
830
     */
831
    public function disable()
832
    {
833
        return $this->attribute('disabled', true);
834
    }
835
836
    /**
837
     * Set field placeholder.
838
     *
839
     * @param string $placeholder
840
     *
841
     * @return Field
842
     */
843
    public function placeholder($placeholder = '')
844
    {
845
        $this->placeholder = $placeholder;
846
847
        return $this;
848
    }
849
850
    /**
851
     * Get placeholder.
852
     *
853
     * @return string
854
     */
855
    public function getPlaceholder()
856
    {
857
        return $this->placeholder ?: trans('admin.input').' '.$this->label;
858
    }
859
860
    /**
861
     * Prepare for a field value before update or insert.
862
     *
863
     * @param $value
864
     *
865
     * @return mixed
866
     */
867
    public function prepare($value)
868
    {
869
        return $value;
870
    }
871
872
    /**
873
     * Format the field attributes.
874
     *
875
     * @return string
876
     */
877
    protected function formatAttributes()
878
    {
879
        $html = [];
880
881
        foreach ($this->attributes as $name => $value) {
882
            $html[] = $name.'="'.e($value).'"';
883
        }
884
885
        return implode(' ', $html);
886
    }
887
888
    /**
889
     * @return $this
890
     */
891
    public function disableHorizontal()
892
    {
893
        $this->horizontal = false;
894
895
        return $this;
896
    }
897
898
    /**
899
     * @return array
900
     */
901
    public function getViewElementClasses()
902
    {
903
        if ($this->horizontal) {
904
            return [
905
                'label'      => "col-sm-{$this->width['label']} {$this->getLabelClass()}",
906
                'field'      => "col-sm-{$this->width['field']}",
907
                'form-group' => 'form-group ',
908
            ];
909
        }
910
911
        return ['label' => "{$this->getLabelClass()}", 'field' => '', 'form-group' => ''];
912
    }
913
914
    /**
915
     * Set form element class.
916
     *
917
     * @param string|array $class
918
     *
919
     * @return $this
920
     */
921
    public function setElementClass($class)
922
    {
923
        $this->elementClass = array_merge($this->elementClass, (array) $class);
924
925
        return $this;
926
    }
927
928
    /**
929
     * Get element class.
930
     *
931
     * @return array
932
     */
933
    protected function getElementClass()
934
    {
935
        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...
936
            $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...
937
938
            $this->elementClass = (array) str_replace(['[', ']'], '_', $name);
939
        }
940
941
        return $this->elementClass;
942
    }
943
944
    /**
945
     * Get element class string.
946
     *
947
     * @return mixed
948
     */
949 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...
950
    {
951
        $elementClass = $this->getElementClass();
952
953
        if (Arr::isAssoc($elementClass)) {
954
            $classes = [];
955
956
            foreach ($elementClass as $index => $class) {
957
                $classes[$index] = is_array($class) ? implode(' ', $class) : $class;
958
            }
959
960
            return $classes;
961
        }
962
963
        return implode(' ', $elementClass);
964
    }
965
966
    /**
967
     * Get element class selector.
968
     *
969
     * @return string|array
970
     */
971 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...
972
    {
973
        $elementClass = $this->getElementClass();
974
975
        if (Arr::isAssoc($elementClass)) {
976
            $classes = [];
977
978
            foreach ($elementClass as $index => $class) {
979
                $classes[$index] = '.'.(is_array($class) ? implode('.', $class) : $class);
980
            }
981
982
            return $classes;
983
        }
984
985
        return '.'.implode('.', $elementClass);
986
    }
987
988
    /**
989
     * Add the element class.
990
     *
991
     * @param $class
992
     *
993
     * @return $this
994
     */
995
    public function addElementClass($class)
996
    {
997
        if (is_array($class) || is_string($class)) {
998
            $this->elementClass = array_merge($this->elementClass, (array) $class);
999
1000
            $this->elementClass = array_unique($this->elementClass);
1001
        }
1002
1003
        return $this;
1004
    }
1005
1006
    /**
1007
     * Remove element class.
1008
     *
1009
     * @param $class
1010
     *
1011
     * @return $this
1012
     */
1013
    public function removeElementClass($class)
1014
    {
1015
        $delClass = [];
1016
1017
        if (is_string($class) || is_array($class)) {
1018
            $delClass = (array) $class;
1019
        }
1020
1021
        foreach ($delClass as $del) {
1022
            if (($key = array_search($del, $this->elementClass)) !== false) {
1023
                unset($this->elementClass[$key]);
1024
            }
1025
        }
1026
1027
        return $this;
1028
    }
1029
1030
    /**
1031
     * Set form group class.
1032
     *
1033
     * @param string|array $class
1034
     *
1035
     * @return $this
1036
     */
1037
    public function setGroupClass($class)
1038
    : self
1039
    {
1040
        array_push($this->groupClass, $class);
1041
1042
        return $this;
1043
    }
1044
1045
    /**
1046
     * Get element class.
1047
     *
1048
     * @return array
1049
     */
1050
    protected function getGroupClass($default = false)
1051
    : string
1052
    {
1053
        return ($default ? 'form-group ' : '').implode(' ', array_filter($this->groupClass));
1054
    }
1055
1056
    /**
1057
     * reset field className.
1058
     *
1059
     * @param string $className
1060
     * @param string $resetClassName
1061
     *
1062
     * @return $this
1063
     */
1064
    public function resetElementClassName(string $className, string $resetClassName)
1065
    {
1066
        if (($key = array_search($className, $this->getElementClass())) !== false) {
1067
            $this->elementClass[$key] = $resetClassName;
1068
        }
1069
1070
        return $this;
1071
    }
1072
1073
    /**
1074
     * Add variables to field view.
1075
     *
1076
     * @param array $variables
1077
     *
1078
     * @return $this
1079
     */
1080
    protected function addVariables(array $variables = [])
1081
    {
1082
        $this->variables = array_merge($this->variables, $variables);
1083
1084
        return $this;
1085
    }
1086
1087
    /**
1088
     * @return string
1089
     */
1090
    public function getLabelClass()
1091
    : string
1092
    {
1093
        return implode(' ', $this->labelClass);
1094
    }
1095
1096
    /**
1097
     * @param array $labelClass
1098
     *
1099
     * @return self
1100
     */
1101
    public function setLabelClass(array $labelClass)
1102
    : self
1103
    {
1104
        $this->labelClass = $labelClass;
1105
1106
        return $this;
1107
    }
1108
1109
    /**
1110
     * Get the view variables of this field.
1111
     *
1112
     * @return array
1113
     */
1114
    public function variables()
1115
    {
1116
        return array_merge($this->variables, [
1117
            'id'          => $this->id,
1118
            '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...
1119
            'help'        => $this->help,
1120
            'class'       => $this->getElementClassString(),
1121
            'value'       => $this->value(),
1122
            'label'       => $this->label,
1123
            'viewClass'   => $this->getViewElementClasses(),
1124
            'column'      => $this->column,
1125
            'errorKey'    => $this->getErrorKey(),
1126
            'attributes'  => $this->formatAttributes(),
1127
            'placeholder' => $this->getPlaceholder(),
1128
        ]);
1129
    }
1130
1131
    /**
1132
     * Get view of this field.
1133
     *
1134
     * @return string
1135
     */
1136
    public function getView()
1137
    {
1138
        if (!empty($this->view)) {
1139
            return $this->view;
1140
        }
1141
1142
        $class = explode('\\', get_called_class());
1143
1144
        return 'admin::form.'.strtolower(end($class));
1145
    }
1146
1147
    /**
1148
     * Set view of current field.
1149
     *
1150
     * @return string
1151
     */
1152
    public function setView($view)
1153
    {
1154
        $this->view = $view;
1155
1156
        return $this;
1157
    }
1158
1159
    /**
1160
     * Get script of current field.
1161
     *
1162
     * @return string
1163
     */
1164
    public function getScript()
1165
    {
1166
        return $this->script;
1167
    }
1168
1169
    /**
1170
     * Set script of current field.
1171
     *
1172
     * @return self
1173
     */
1174
    public function setScript($script)
1175
    {
1176
        $this->script = $script;
1177
1178
        return $this;
1179
    }
1180
1181
    /**
1182
     * To set this field should render or not.
1183
     *
1184
     * @return self
1185
     */
1186
    public function setDisplay(bool $display)
1187
    {
1188
        $this->display = $display;
1189
1190
        return $this;
1191
    }
1192
1193
    /**
1194
     * If this field should render.
1195
     *
1196
     * @return bool
1197
     */
1198
    protected function shouldRender()
1199
    {
1200
        if (!$this->display) {
1201
            return false;
1202
        }
1203
1204
        return true;
1205
    }
1206
1207
    /**
1208
     * Render this filed.
1209
     *
1210
     * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View|string
1211
     */
1212
    public function render()
1213
    {
1214
        if (!$this->shouldRender()) {
1215
            return '';
1216
        }
1217
1218
        Admin::script($this->script);
1219
1220
        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 1220 which is incompatible with the return type declared by the interface Illuminate\Contracts\Support\Renderable::render of type string.
Loading history...
1221
    }
1222
1223
    /**
1224
     * @return string
1225
     */
1226
    public function __toString()
1227
    {
1228
        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...
1229
    }
1230
}
1231