Completed
Pull Request — master (#2499)
by
unknown
02:32
created

Field::attribute()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
nc 2
nop 2
dl 0
loc 10
rs 9.9332
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
     * Field original value.
38
     *
39
     * @var mixed
40
     */
41
    protected $original;
42
43
    /**
44
     * Field default value.
45
     *
46
     * @var mixed
47
     */
48
    protected $default;
49
50
    /**
51
     * Element label.
52
     *
53
     * @var string
54
     */
55
    protected $label = '';
56
57
    /**
58
     * Column name.
59
     *
60
     * @var string|array
61
     */
62
    protected $column = '';
63
64
    /**
65
     * Form element name.
66
     *
67
     * @var string
68
     */
69
    protected $elementName = [];
70
71
    /**
72
     * Form element classes.
73
     *
74
     * @var array
75
     */
76
    protected $elementClass = [];
77
78
    /**
79
     * Variables of elements.
80
     *
81
     * @var array
82
     */
83
    protected $variables = [];
84
85
    /**
86
     * Options for specify elements.
87
     *
88
     * @var array
89
     */
90
    protected $options = [];
91
92
    /**
93
     * Checked for specify elements.
94
     *
95
     * @var array
96
     */
97
    protected $checked = [];
98
99
    /**
100
     * Validation rules.
101
     *
102
     * @var string|\Closure
103
     */
104
    protected $rules = '';
105
106
    /**
107
     * @var callable
108
     */
109
    protected $validator;
110
111
    /**
112
     * Validation messages.
113
     *
114
     * @var array
115
     */
116
    protected $validationMessages = [];
117
118
    /**
119
     * Css required by this field.
120
     *
121
     * @var array
122
     */
123
    protected static $css = [];
124
125
    /**
126
     * Js required by this field.
127
     *
128
     * @var array
129
     */
130
    protected static $js = [];
131
132
    /**
133
     * Script for field.
134
     *
135
     * @var string
136
     */
137
    protected $script = '';
138
139
    /**
140
     * Element attributes.
141
     *
142
     * @var array
143
     */
144
    protected $attributes = [];
145
146
    /**
147
     * Parent form.
148
     *
149
     * @var Form
150
     */
151
    protected $form = null;
152
153
    /**
154
     * View for field to render.
155
     *
156
     * @var string
157
     */
158
    protected $view = '';
159
160
    /**
161
     * Help block.
162
     *
163
     * @var array
164
     */
165
    protected $help = [];
166
167
    /**
168
     * Key for errors.
169
     *
170
     * @var mixed
171
     */
172
    protected $errorKey;
173
174
    /**
175
     * Placeholder for this field.
176
     *
177
     * @var string|array
178
     */
179
    protected $placeholder;
180
181
    /**
182
     * Width for label and field.
183
     *
184
     * @var array
185
     */
186
    protected $width = [
187
        'label' => 2,
188
        'field' => 8,
189
    ];
190
191
    /**
192
     * If the form horizontal layout.
193
     *
194
     * @var bool
195
     */
196
    protected $horizontal = true;
197
198
    /**
199
     * column data format.
200
     *
201
     * @var \Closure
202
     */
203
    protected $customFormat = null;
204
205
    /**
206
     * @var bool
207
     */
208
    protected $display = true;
209
210
    /**
211
     * @var array
212
     */
213
    protected $labelClass = [];
214
215
    /**
216
     * Field constructor.
217
     *
218
     * @param       $column
219
     * @param array $arguments
220
     */
221
    public function __construct($column, $arguments = [])
222
    {
223
        $this->column = $column;
224
        $this->label = $this->formatLabel($arguments);
225
        $this->id = $this->formatId($column);
226
    }
227
228
    /**
229
     * Get assets required by this field.
230
     *
231
     * @return array
232
     */
233
    public static function getAssets()
234
    {
235
        return [
236
            'css' => static::$css,
237
            'js'  => static::$js,
238
        ];
239
    }
240
241
    /**
242
     * Format the field element id.
243
     *
244
     * @param string|array $column
245
     *
246
     * @return string|array
247
     */
248
    protected function formatId($column)
249
    {
250
        return str_replace('.', '_', $column);
251
    }
252
253
    /**
254
     * Format the label value.
255
     *
256
     * @param array $arguments
257
     *
258
     * @return string
259
     */
260
    protected function formatLabel($arguments = [])
261
    {
262
        $column = is_array($this->column) ? current($this->column) : $this->column;
263
264
        $label = isset($arguments[0]) ? $arguments[0] : ucfirst($column);
265
266
        return str_replace(['.', '_'], ' ', $label);
267
    }
268
269
    /**
270
     * Format the name of the field.
271
     *
272
     * @param string $column
273
     *
274
     * @return array|mixed|string
275
     */
276
    protected function formatName($column)
277
    {
278
        if (is_string($column)) {
279
            $name = explode('.', $column);
280
281
            if (count($name) == 1) {
282
                return $name[0];
283
            }
284
285
            $html = array_shift($name);
286
            foreach ($name as $piece) {
287
                $html .= "[$piece]";
288
            }
289
290
            return $html;
291
        }
292
293
        if (is_array($this->column)) {
294
            $names = [];
295
            foreach ($this->column as $key => $name) {
296
                $names[$key] = $this->formatName($name);
297
            }
298
299
            return $names;
300
        }
301
302
        return '';
303
    }
304
305
    /**
306
     * Set form element name.
307
     *
308
     * @param string $name
309
     *
310
     * @return $this
311
     *
312
     * @author Edwin Hui
313
     */
314
    public function setElementName($name)
315
    {
316
        $this->elementName = $name;
317
318
        return $this;
319
    }
320
321
    /**
322
     * Fill data to the field.
323
     *
324
     * @param array $data
325
     *
326
     * @return void
327
     */
328
    public function fill($data)
329
    {
330
        // Field value is already setted.
331
//        if (!is_null($this->value)) {
332
//            return;
333
//        }
334
335
        if (is_array($this->column)) {
336
            foreach ($this->column as $key => $column) {
337
                $this->value[$key] = array_get($data, $column);
338
            }
339
340
            return;
341
        }
342
343
        $this->value = array_get($data, $this->column);
344
345
        # en: Solving the associated model data does not display data on the edit page..
346
        # zh:解决关联模型数据在编辑页面是没显示数据
347
        $arr =  explode('.', $this->column);
348
        if(!$this->value && count($arr)>1) {
349
            $oarr = array_get($arr,0);
350
            if($oarr){
351
                $b = str_split($oarr);
352
                $c='';
353
                foreach ($b as $key=>$v){
354
                    if( preg_match('/^[A-Z]+$/',$v) ){
355
                        if($c){
356
                            $c = $c.'_'.strtolower($v);
357
                        }else{
358
                            $c = $c.strtolower($v);
359
                        }
360
                    }else{
361
                        $c = $c.$v;
362
                    }
363
                }
364
            }
365
366
            $iarr = array_get( $data, $c);
0 ignored issues
show
Bug introduced by
The variable $c does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
367
368
            $this->value = is_array( $iarr ) ? array_get( $iarr, array_get( $arr, 1)): null;
369
        }
370
371
        if (isset($this->customFormat) && $this->customFormat instanceof \Closure) {
372
            $this->value = call_user_func($this->customFormat, $this->value);
373
        }
374
    }
375
376
    /**
377
     * custom format form column data when edit.
378
     *
379
     * @param \Closure $call
380
     *
381
     * @return $this
382
     */
383
    public function customFormat(\Closure $call)
384
    {
385
        $this->customFormat = $call;
386
387
        return $this;
388
    }
389
390
    /**
391
     * Set original value to the field.
392
     *
393
     * @param array $data
394
     *
395
     * @return void
396
     */
397
    public function setOriginal($data)
398
    {
399
        if (is_array($this->column)) {
400
            foreach ($this->column as $key => $column) {
401
                $this->original[$key] = array_get($data, $column);
402
            }
403
404
            return;
405
        }
406
407
        $this->original = array_get($data, $this->column);
408
    }
409
410
    /**
411
     * @param Form $form
412
     *
413
     * @return $this
414
     */
415
    public function setForm(Form $form = null)
416
    {
417
        $this->form = $form;
418
419
        return $this;
420
    }
421
422
    /**
423
     * Set width for field and label.
424
     *
425
     * @param int $field
426
     * @param int $label
427
     *
428
     * @return $this
429
     */
430
    public function setWidth($field = 8, $label = 2)
431
    {
432
        $this->width = [
433
            'label' => $label,
434
            'field' => $field,
435
        ];
436
437
        return $this;
438
    }
439
440
    /**
441
     * Set the field options.
442
     *
443
     * @param array $options
444
     *
445
     * @return $this
446
     */
447 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...
448
    {
449
        if ($options instanceof Arrayable) {
450
            $options = $options->toArray();
451
        }
452
453
        $this->options = array_merge($this->options, $options);
454
455
        return $this;
456
    }
457
458
    /**
459
     * Set the field option checked.
460
     *
461
     * @param array $checked
462
     *
463
     * @return $this
464
     */
465 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...
466
    {
467
        if ($checked instanceof Arrayable) {
468
            $checked = $checked->toArray();
469
        }
470
471
        $this->checked = array_merge($this->checked, $checked);
472
473
        return $this;
474
    }
475
476
    /**
477
     * Get or set rules.
478
     *
479
     * @param null  $rules
480
     * @param array $messages
481
     *
482
     * @return $this
483
     */
484
    public function rules($rules = null, $messages = [])
485
    {
486
        if ($rules instanceof \Closure) {
487
            $this->rules = $rules;
488
        }
489
490
        if (is_array($rules)) {
491
            $thisRuleArr = array_filter(explode('|', $this->rules));
492
493
            $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...
494
        } elseif (is_string($rules)) {
495
            $rules = array_filter(explode('|', "{$this->rules}|$rules"));
496
497
            $this->rules = implode('|', $rules);
498
        }
499
500
        $this->validationMessages = $messages;
501
502
        return $this;
503
    }
504
505
    /**
506
     * Get field validation rules.
507
     *
508
     * @return string
509
     */
510
    protected function getRules()
511
    {
512
        if ($this->rules instanceof \Closure) {
513
            return $this->rules->call($this, $this->form);
514
        }
515
516
        return $this->rules;
517
    }
518
519
    /**
520
     * Remove a specific rule by keyword.
521
     *
522
     * @param string $rule
523
     *
524
     * @return void
525
     */
526
    protected function removeRule($rule)
527
    {
528
        if (!is_string($this->rules)) {
529
            return;
530
        }
531
532
        $pattern = "/{$rule}[^\|]?(\||$)/";
533
        $this->rules = preg_replace($pattern, '', $this->rules, -1);
534
    }
535
536
    /**
537
     * Set field validator.
538
     *
539
     * @param callable $validator
540
     *
541
     * @return $this
542
     */
543
    public function validator(callable $validator)
544
    {
545
        $this->validator = $validator;
546
547
        return $this;
548
    }
549
550
    /**
551
     * Get key for error message.
552
     *
553
     * @return string
554
     */
555
    public function getErrorKey()
556
    {
557
        return $this->errorKey ?: $this->column;
558
    }
559
560
    /**
561
     * Set key for error message.
562
     *
563
     * @param string $key
564
     *
565
     * @return $this
566
     */
567
    public function setErrorKey($key)
568
    {
569
        $this->errorKey = $key;
570
571
        return $this;
572
    }
573
574
    /**
575
     * Set or get value of the field.
576
     *
577
     * @param null $value
578
     *
579
     * @return mixed
580
     */
581 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...
582
    {
583
        if (is_null($value)) {
584
            return is_null($this->value) ? $this->getDefault() : $this->value;
585
        }
586
587
        $this->value = $value;
588
589
        return $this;
590
    }
591
592
    /**
593
     * Set default value for field.
594
     *
595
     * @param $default
596
     *
597
     * @return $this
598
     */
599
    public function default($default)
600
    {
601
        $this->default = $default;
602
603
        return $this;
604
    }
605
606
    /**
607
     * Get default value.
608
     *
609
     * @return mixed
610
     */
611
    public function getDefault()
612
    {
613
        if ($this->default instanceof \Closure) {
614
            return call_user_func($this->default, $this->form);
615
        }
616
617
        return $this->default;
618
    }
619
620
    /**
621
     * Set help block for current field.
622
     *
623
     * @param string $text
624
     * @param string $icon
625
     *
626
     * @return $this
627
     */
628
    public function help($text = '', $icon = 'fa-info-circle')
629
    {
630
        $this->help = compact('text', 'icon');
631
632
        return $this;
633
    }
634
635
    /**
636
     * Get column of the field.
637
     *
638
     * @return string|array
639
     */
640
    public function column()
641
    {
642
        return $this->column;
643
    }
644
645
    /**
646
     * Get label of the field.
647
     *
648
     * @return string
649
     */
650
    public function label()
651
    {
652
        return $this->label;
653
    }
654
655
    /**
656
     * Get original value of the field.
657
     *
658
     * @return mixed
659
     */
660
    public function original()
661
    {
662
        return $this->original;
663
    }
664
665
    /**
666
     * Get validator for this field.
667
     *
668
     * @param array $input
669
     *
670
     * @return bool|Validator
671
     */
672
    public function getValidator(array $input)
673
    {
674
        if ($this->validator) {
675
            return $this->validator->call($this, $input);
676
        }
677
678
        $rules = $attributes = [];
679
680
        if (!$fieldRules = $this->getRules()) {
681
            return false;
682
        }
683
684
        if (is_string($this->column)) {
685
            if (!array_has($input, $this->column)) {
686
                return false;
687
            }
688
689
            $input = $this->sanitizeInput($input, $this->column);
690
691
            $rules[$this->column] = $fieldRules;
692
            $attributes[$this->column] = $this->label;
693
        }
694
695
        if (is_array($this->column)) {
696
            foreach ($this->column as $key => $column) {
697
                if (!array_key_exists($column, $input)) {
698
                    continue;
699
                }
700
                $input[$column.$key] = array_get($input, $column);
701
                $rules[$column.$key] = $fieldRules;
702
                $attributes[$column.$key] = $this->label."[$column]";
703
            }
704
        }
705
706
        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...
707
    }
708
709
    /**
710
     * Sanitize input data.
711
     *
712
     * @param array  $input
713
     * @param string $column
714
     *
715
     * @return array
716
     */
717
    protected function sanitizeInput($input, $column)
718
    {
719
        if ($this instanceof Field\MultipleSelect) {
720
            $value = array_get($input, $column);
721
            array_set($input, $column, array_filter($value));
722
        }
723
724
        return $input;
725
    }
726
727
    /**
728
     * Add html attributes to elements.
729
     *
730
     * @param array|string $attribute
731
     * @param mixed        $value
732
     *
733
     * @return $this
734
     */
735
    public function attribute($attribute, $value = null)
736
    {
737
        if (is_array($attribute)) {
738
            $this->attributes = array_merge($this->attributes, $attribute);
739
        } else {
740
            $this->attributes[$attribute] = (string) $value;
741
        }
742
743
        return $this;
744
    }
745
    
746
    /**
747
     * Specifies a regular expression against which to validate the value of the input.
748
     * 
749
     * @param string $regexp
750
     * 
751
     * @return Field
752
     */
753
    public function pattern($regexp)
754
    {
755
        return $this->attribute('pattern', $regexp);
756
    }
757
758
    /**
759
     * Set the field automatically get focus.
760
     *
761
     * @return Field
762
     */
763
    public function autofocus()
764
    {
765
        return $this->attribute('autofocus', true);
766
    }
767
768
    /**
769
     * Set the field as readonly mode.
770
     *
771
     * @return Field
772
     */
773
    public function readOnly()
774
    {
775
        return $this->attribute('readonly', true);
776
    }
777
778
    /**
779
     * Set field as disabled.
780
     *
781
     * @return Field
782
     */
783
    public function disable()
784
    {
785
        return $this->attribute('disabled', true);
786
    }
787
788
    /**
789
     * Set field placeholder.
790
     *
791
     * @param string $placeholder
792
     *
793
     * @return Field
794
     */
795
    public function placeholder($placeholder = '')
796
    {
797
        $this->placeholder = $placeholder;
798
799
        return $this;
800
    }
801
802
    /**
803
     * Get placeholder.
804
     *
805
     * @return string
806
     */
807
    public function getPlaceholder()
808
    {
809
        return $this->placeholder ?: trans('admin.input').' '.$this->label;
810
    }
811
812
    /**
813
     * Prepare for a field value before update or insert.
814
     *
815
     * @param $value
816
     *
817
     * @return mixed
818
     */
819
    public function prepare($value)
820
    {
821
        return $value;
822
    }
823
824
    /**
825
     * Format the field attributes.
826
     *
827
     * @return string
828
     */
829
    protected function formatAttributes()
830
    {
831
        $html = [];
832
833
        foreach ($this->attributes as $name => $value) {
834
            $html[] = $name.'="'.e($value).'"';
835
        }
836
837
        return implode(' ', $html);
838
    }
839
840
    /**
841
     * @return $this
842
     */
843
    public function disableHorizontal()
844
    {
845
        $this->horizontal = false;
846
847
        return $this;
848
    }
849
850
    /**
851
     * @return array
852
     */
853
    public function getViewElementClasses()
854
    {
855
        if ($this->horizontal) {
856
            return [
857
                'label'      => "col-sm-{$this->width['label']} {$this->getLabelClass()}",
858
                'field'      => "col-sm-{$this->width['field']}",
859
                'form-group' => 'form-group ',
860
            ];
861
        }
862
863
        return ['label' => "{$this->getLabelClass()}", 'field' => '', 'form-group' => ''];
864
    }
865
866
    /**
867
     * Set form element class.
868
     *
869
     * @param string|array $class
870
     *
871
     * @return $this
872
     */
873
    public function setElementClass($class)
874
    {
875
        $this->elementClass = (array) $class;
876
877
        return $this;
878
    }
879
880
    /**
881
     * Get element class.
882
     *
883
     * @return array
884
     */
885
    protected function getElementClass()
886
    {
887
        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...
888
            $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...
889
890
            $this->elementClass = (array) str_replace(['[', ']'], '_', $name);
891
        }
892
893
        return $this->elementClass;
894
    }
895
896
    /**
897
     * Get element class string.
898
     *
899
     * @return mixed
900
     */
901 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...
902
    {
903
        $elementClass = $this->getElementClass();
904
905
        if (Arr::isAssoc($elementClass)) {
906
            $classes = [];
907
908
            foreach ($elementClass as $index => $class) {
909
                $classes[$index] = is_array($class) ? implode(' ', $class) : $class;
910
            }
911
912
            return $classes;
913
        }
914
915
        return implode(' ', $elementClass);
916
    }
917
918
    /**
919
     * Get element class selector.
920
     *
921
     * @return string|array
922
     */
923 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...
924
    {
925
        $elementClass = $this->getElementClass();
926
927
        if (Arr::isAssoc($elementClass)) {
928
            $classes = [];
929
930
            foreach ($elementClass as $index => $class) {
931
                $classes[$index] = '.'.(is_array($class) ? implode('.', $class) : $class);
932
            }
933
934
            return $classes;
935
        }
936
937
        return '.'.implode('.', $elementClass);
938
    }
939
940
    /**
941
     * Add the element class.
942
     *
943
     * @param $class
944
     *
945
     * @return $this
946
     */
947
    public function addElementClass($class)
948
    {
949
        if (is_array($class) || is_string($class)) {
950
            $this->elementClass = array_merge($this->elementClass, (array) $class);
951
952
            $this->elementClass = array_unique($this->elementClass);
953
        }
954
955
        return $this;
956
    }
957
958
    /**
959
     * Remove element class.
960
     *
961
     * @param $class
962
     *
963
     * @return $this
964
     */
965
    public function removeElementClass($class)
966
    {
967
        $delClass = [];
968
969
        if (is_string($class) || is_array($class)) {
970
            $delClass = (array) $class;
971
        }
972
973
        foreach ($delClass as $del) {
974
            if (($key = array_search($del, $this->elementClass))) {
975
                unset($this->elementClass[$key]);
976
            }
977
        }
978
979
        return $this;
980
    }
981
982
    /**
983
     * Add variables to field view.
984
     *
985
     * @param array $variables
986
     *
987
     * @return $this
988
     */
989
    protected function addVariables(array $variables = [])
990
    {
991
        $this->variables = array_merge($this->variables, $variables);
992
993
        return $this;
994
    }
995
996
    /**
997
     * @return string
998
     */
999
    public function getLabelClass()
1000
    : string
1001
    {
1002
        return implode(' ', $this->labelClass);
1003
    }
1004
1005
    /**
1006
     * @param array $labelClass
1007
     *
1008
     * @return self
1009
     */
1010
    public function setLabelClass(array $labelClass)
1011
    : self
1012
    {
1013
        $this->labelClass = $labelClass;
1014
1015
        return $this;
1016
    }
1017
1018
    /**
1019
     * Get the view variables of this field.
1020
     *
1021
     * @return array
1022
     */
1023
    public function variables()
1024
    {
1025
        return array_merge($this->variables, [
1026
            'id'          => $this->id,
1027
            '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...
1028
            'help'        => $this->help,
1029
            'class'       => $this->getElementClassString(),
1030
            'value'       => $this->value(),
1031
            'label'       => $this->label,
1032
            'viewClass'   => $this->getViewElementClasses(),
1033
            'column'      => $this->column,
1034
            'errorKey'    => $this->getErrorKey(),
1035
            'attributes'  => $this->formatAttributes(),
1036
            'placeholder' => $this->getPlaceholder(),
1037
        ]);
1038
    }
1039
1040
    /**
1041
     * Get view of this field.
1042
     *
1043
     * @return string
1044
     */
1045
    public function getView()
1046
    {
1047
        if (!empty($this->view)) {
1048
            return $this->view;
1049
        }
1050
1051
        $class = explode('\\', get_called_class());
1052
1053
        return 'admin::form.'.strtolower(end($class));
1054
    }
1055
1056
    /**
1057
     * Get script of current field.
1058
     *
1059
     * @return string
1060
     */
1061
    public function getScript()
1062
    {
1063
        return $this->script;
1064
    }
1065
1066
    /**
1067
     * If this field should render.
1068
     *
1069
     * @return bool
1070
     */
1071
    protected function shouldRender()
1072
    {
1073
        if (!$this->display) {
1074
            return false;
1075
        }
1076
1077
        return true;
1078
    }
1079
1080
    /**
1081
     * Render this filed.
1082
     *
1083
     * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View|string
1084
     */
1085
    public function render()
1086
    {
1087
        if (!$this->shouldRender()) {
1088
            return '';
1089
        }
1090
1091
        Admin::script($this->script);
1092
1093
        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 1093 which is incompatible with the return type declared by the interface Illuminate\Contracts\Support\Renderable::render of type string.
Loading history...
1094
    }
1095
1096
    /**
1097
     * @return string
1098
     */
1099
    public function __toString()
1100
    {
1101
        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...
1102
    }
1103
}
1104