Completed
Push — master ( 7f32db...90310f )
by Song
02:46
created

Field   D

Complexity

Total Complexity 93

Size/Duplication

Total Lines 909
Duplicated Lines 8.36 %

Coupling/Cohesion

Components 3
Dependencies 2

Importance

Changes 0
Metric Value
dl 76
loc 909
rs 4
c 0
b 0
f 0
wmc 93
lcom 3
cbo 2

45 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 1
A getAssets() 0 7 1
A formatId() 0 4 1
A formatLabel() 0 8 3
B formatName() 0 28 6
A setElementName() 0 6 1
A fill() 12 17 3
A setOriginal() 12 12 3
A setForm() 0 6 1
A setWidth() 0 9 1
A options() 10 10 2
A getRules() 0 8 2
A removeRule() 0 4 1
A validator() 0 6 1
A getErrorKey() 0 4 2
A setErrorKey() 0 6 1
A value() 10 10 3
A default() 0 6 1
A getDefault() 0 8 2
A help() 0 6 1
A column() 0 4 1
A label() 0 4 1
A original() 0 4 1
C getValidator() 0 36 8
A sanitizeInput() 0 9 2
A attribute() 0 10 2
A readOnly() 0 4 1
A placeholder() 0 6 1
A getPlaceholder() 0 4 2
A prepare() 0 4 1
A formatAttributes() 0 10 2
A disableHorizontal() 0 6 1
A getViewElementClasses() 0 12 2
A setElementClass() 0 6 1
A getElementClass() 0 10 3
A getElementClassString() 16 16 4
A getElementClassSelector() 16 16 4
A addElementClass() 0 10 3
B removeElementClass() 0 16 5
A variables() 0 16 2
A getView() 0 10 2
A getScript() 0 4 1
A render() 0 6 1
A __toString() 0 4 1
A rules() 0 20 4

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like Field often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Field, and based on these observations, apply Extract Interface, too.

1
<?php
0 ignored issues
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 15 and the first side effect is on line 923.

The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.

The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.

To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.

Loading history...
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
12
/**
13
 * Class Field.
14
 */
15
class Field implements Renderable
16
{
17
    const FILE_DELETE_FLAG = '_file_del_';
18
19
    /**
20
     * Element id.
21
     *
22
     * @var array|string
23
     */
24
    protected $id;
25
26
    /**
27
     * Element value.
28
     *
29
     * @var mixed
30
     */
31
    protected $value;
32
33
    /**
34
     * Field original value.
35
     *
36
     * @var mixed
37
     */
38
    protected $original;
39
40
    /**
41
     * Field default value.
42
     *
43
     * @var mixed
44
     */
45
    protected $default;
46
47
    /**
48
     * Element label.
49
     *
50
     * @var string
51
     */
52
    protected $label = '';
53
54
    /**
55
     * Column name.
56
     *
57
     * @var string|array
58
     */
59
    protected $column = '';
60
61
    /**
62
     * Form element name.
63
     *
64
     * @var string
65
     */
66
    protected $elementName = [];
67
68
    /**
69
     * Form element classes.
70
     *
71
     * @var array
72
     */
73
    protected $elementClass = [];
74
75
    /**
76
     * Variables of elements.
77
     *
78
     * @var array
79
     */
80
    protected $variables = [];
81
82
    /**
83
     * Options for specify elements.
84
     *
85
     * @var array
86
     */
87
    protected $options = [];
88
89
    /**
90
     * Validation rules.
91
     *
92
     * @var string|\Closure
93
     */
94
    protected $rules = '';
95
96
    /**
97
     * @var callable
98
     */
99
    protected $validator;
100
101
    /**
102
     * Validation messages.
103
     *
104
     * @var array
105
     */
106
    protected $validationMessages = [];
107
108
    /**
109
     * Css required by this field.
110
     *
111
     * @var array
112
     */
113
    protected static $css = [];
114
115
    /**
116
     * Js required by this field.
117
     *
118
     * @var array
119
     */
120
    protected static $js = [];
121
122
    /**
123
     * Script for field.
124
     *
125
     * @var string
126
     */
127
    protected $script = '';
128
129
    /**
130
     * Element attributes.
131
     *
132
     * @var array
133
     */
134
    protected $attributes = [];
135
136
    /**
137
     * Parent form.
138
     *
139
     * @var Form
140
     */
141
    protected $form = null;
142
143
    /**
144
     * View for field to render.
145
     *
146
     * @var string
147
     */
148
    protected $view = '';
149
150
    /**
151
     * Help block.
152
     *
153
     * @var array
154
     */
155
    protected $help = [];
156
157
    /**
158
     * Key for errors.
159
     *
160
     * @var mixed
161
     */
162
    protected $errorKey;
163
164
    /**
165
     * Placeholder for this field.
166
     *
167
     * @var string|array
168
     */
169
    protected $placeholder;
170
171
    /**
172
     * Width for label and field.
173
     *
174
     * @var array
175
     */
176
    protected $width = [
177
        'label' => 2,
178
        'field' => 8,
179
    ];
180
181
    /**
182
     * If the form horizontal layout.
183
     *
184
     * @var bool
185
     */
186
    protected $horizontal = true;
187
188
    /**
189
     * Field constructor.
190
     *
191
     * @param $column
192
     * @param array $arguments
193
     */
194
    public function __construct($column, $arguments = [])
195
    {
196
        $this->column = $column;
197
        $this->label = $this->formatLabel($arguments);
198
        $this->id = $this->formatId($column);
199
    }
200
201
    /**
202
     * Get assets required by this field.
203
     *
204
     * @return array
205
     */
206
    public static function getAssets()
207
    {
208
        return [
209
            'css' => static::$css,
210
            'js'  => static::$js,
211
        ];
212
    }
213
214
    /**
215
     * Format the field element id.
216
     *
217
     * @param string|array $column
218
     *
219
     * @return string|array
220
     */
221
    protected function formatId($column)
222
    {
223
        return str_replace('.', '_', $column);
224
    }
225
226
    /**
227
     * Format the label value.
228
     *
229
     * @param array $arguments
230
     *
231
     * @return string
232
     */
233
    protected function formatLabel($arguments = [])
234
    {
235
        $column = is_array($this->column) ? current($this->column) : $this->column;
236
237
        $label = isset($arguments[0]) ? $arguments[0] : ucfirst($column);
238
239
        return str_replace(['.', '_'], ' ', $label);
240
    }
241
242
    /**
243
     * Format the name of the field.
244
     *
245
     * @param string $column
246
     *
247
     * @return array|mixed|string
248
     */
249
    protected function formatName($column)
250
    {
251
        if (is_string($column)) {
252
            $name = explode('.', $column);
253
254
            if (count($name) == 1) {
255
                return $name[0];
256
            }
257
258
            $html = array_shift($name);
259
            foreach ($name as $piece) {
260
                $html .= "[$piece]";
261
            }
262
263
            return $html;
264
        }
265
266
        if (is_array($this->column)) {
267
            $names = [];
268
            foreach ($this->column as $key => $name) {
269
                $names[$key] = $this->formatName($name);
270
            }
271
272
            return $names;
273
        }
274
275
        return '';
276
    }
277
278
    /**
279
     * Set form element name.
280
     *
281
     * @param string $name
282
     *
283
     * @return $this
284
     *
285
     * @author Edwin Hui
286
     */
287
    public function setElementName($name)
288
    {
289
        $this->elementName = $name;
290
291
        return $this;
292
    }
293
294
    /**
295
     * Fill data to the field.
296
     *
297
     * @param array $data
298
     *
299
     * @return void
300
     */
301 View Code Duplication
    public function fill($data)
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...
302
    {
303
        // Field value is already setted.
0 ignored issues
show
Unused Code Comprehensibility introduced by
37% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
304
//        if (!is_null($this->value)) {
305
//            return;
306
//        }
307
308
        if (is_array($this->column)) {
309
            foreach ($this->column as $key => $column) {
310
                $this->value[$key] = array_get($data, $column);
311
            }
312
313
            return;
314
        }
315
316
        $this->value = array_get($data, $this->column);
317
    }
318
319
    /**
320
     * Set original value to the field.
321
     *
322
     * @param array $data
323
     *
324
     * @return void
325
     */
326 View Code Duplication
    public function setOriginal($data)
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...
327
    {
328
        if (is_array($this->column)) {
329
            foreach ($this->column as $key => $column) {
330
                $this->original[$key] = array_get($data, $column);
331
            }
332
333
            return;
334
        }
335
336
        $this->original = array_get($data, $this->column);
337
    }
338
339
    /**
340
     * @param Form $form
341
     *
342
     * @return $this
343
     */
344
    public function setForm(Form $form = null)
345
    {
346
        $this->form = $form;
347
348
        return $this;
349
    }
350
351
    /**
352
     * Set width for field and label.
353
     *
354
     * @param int $field
355
     * @param int $label
356
     *
357
     * @return $this
358
     */
359
    public function setWidth($field = 8, $label = 2)
360
    {
361
        $this->width = [
362
            'label' => $label,
363
            'field' => $field,
364
        ];
365
366
        return $this;
367
    }
368
369
    /**
370
     * Set the field options.
371
     *
372
     * @param array $options
373
     *
374
     * @return $this
375
     */
376 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...
377
    {
378
        if ($options instanceof Arrayable) {
379
            $options = $options->toArray();
380
        }
381
382
        $this->options = array_merge($this->options, $options);
383
384
        return $this;
385
    }
386
387
    /**
388
     * Get or set rules.
389
     *
390
     * @param null  $rules
391
     * @param array $messages
392
     *
393
     * @return $this
394
     */
395
    public function rules($rules = null, $messages = [])
396
    {
397
        if ($rules instanceof \Closure) {
398
            $this->rules = $rules;
399
        }
400
401
        if (is_array($rules)) {
402
            $thisRuleArr = array_filter(explode('|', $this->rules));
403
404
            $this->rules = array_merge($thisRuleArr, explode('|', $this->rules));
0 ignored issues
show
Documentation Bug introduced by
It seems like array_merge($thisRuleArr...ode('|', $this->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...
405
        } else if (is_string($rules)) {
406
            $rules = array_filter(explode('|', "{$this->rules}|$rules"));
407
408
            $this->rules = implode('|', $rules);
409
        }
410
411
        $this->validationMessages = $messages;
412
413
        return $this;
414
    }
415
416
    /**
417
     * Get field validation rules.
418
     *
419
     * @return string
420
     */
421
    protected function getRules()
422
    {
423
        if ($this->rules instanceof \Closure) {
424
            return $this->rules->call($this, $this->form);
425
        }
426
427
        return $this->rules;
428
    }
429
430
    /**
431
     * Remove a specific rule.
432
     *
433
     * @param string $rule
434
     *
435
     * @return void
436
     */
437
    protected function removeRule($rule)
438
    {
439
        $this->rules = str_replace($rule, '', $this->rules);
440
    }
441
442
    /**
443
     * Set field validator.
444
     *
445
     * @param callable $validator
446
     *
447
     * @return $this
448
     */
449
    public function validator(callable $validator)
450
    {
451
        $this->validator = $validator;
452
453
        return $this;
454
    }
455
456
    /**
457
     * Get key for error message.
458
     *
459
     * @return string
460
     */
461
    public function getErrorKey()
462
    {
463
        return $this->errorKey ?: $this->column;
464
    }
465
466
    /**
467
     * Set key for error message.
468
     *
469
     * @param string $key
470
     *
471
     * @return $this
472
     */
473
    public function setErrorKey($key)
474
    {
475
        $this->errorKey = $key;
476
477
        return $this;
478
    }
479
480
    /**
481
     * Set or get value of the field.
482
     *
483
     * @param null $value
484
     *
485
     * @return mixed
486
     */
487 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...
488
    {
489
        if (is_null($value)) {
490
            return is_null($this->value) ? $this->getDefault() : $this->value;
491
        }
492
493
        $this->value = $value;
494
495
        return $this;
496
    }
497
498
    /**
499
     * Set default value for field.
500
     *
501
     * @param $default
502
     *
503
     * @return $this
504
     */
505
    public function default($default)
0 ignored issues
show
Coding Style introduced by
Possible parse error: non-abstract method defined as abstract
Loading history...
Coding Style introduced by
It is generally advisable to only define one property per statement.

Only declaring a single property per statement allows you to later on add doc comments more easily.

It is also recommended by PSR2, so it is a common style that many people expect.

Loading history...
506
    {
507
        $this->default = $default;
508
509
        return $this;
0 ignored issues
show
Coding Style introduced by
The visibility should be declared for property $this.

The PSR-2 coding standard requires that all properties in a class have their visibility explicitly declared. If you declare a property using

class A {
    var $property;
}

the property is implicitly global.

To learn more about the PSR-2, please see the PHP-FIG site on the PSR-2.

Loading history...
510
    }
511
512
    /**
513
     * Get default value.
514
     *
515
     * @return mixed
516
     */
517
    public function getDefault()
518
    {
519
        if ($this->default instanceof \Closure) {
520
            return call_user_func($this->default, $this->form);
521
        }
522
523
        return $this->default;
524
    }
525
526
    /**
527
     * Set help block for current field.
528
     *
529
     * @param string $text
530
     * @param string $icon
531
     *
532
     * @return $this
533
     */
534
    public function help($text = '', $icon = 'fa-info-circle')
535
    {
536
        $this->help = compact('text', 'icon');
537
538
        return $this;
539
    }
540
541
    /**
542
     * Get column of the field.
543
     *
544
     * @return string|array
545
     */
546
    public function column()
547
    {
548
        return $this->column;
549
    }
550
551
    /**
552
     * Get label of the field.
553
     *
554
     * @return string
555
     */
556
    public function label()
557
    {
558
        return $this->label;
559
    }
560
561
    /**
562
     * Get original value of the field.
563
     *
564
     * @return mixed
565
     */
566
    public function original()
567
    {
568
        return $this->original;
569
    }
570
571
    /**
572
     * Get validator for this field.
573
     *
574
     * @param array $input
575
     *
576
     * @return bool|Validator
577
     */
578
    public function getValidator(array $input)
579
    {
580
        if ($this->validator) {
581
            return $this->validator->call($this, $input);
582
        }
583
584
        $rules = $attributes = [];
585
586
        if (!$fieldRules = $this->getRules()) {
587
            return false;
588
        }
589
590
        if (is_string($this->column)) {
591
            if (!array_has($input, $this->column)) {
592
                return false;
593
            }
594
595
            $input = $this->sanitizeInput($input, $this->column);
596
597
            $rules[$this->column] = $fieldRules;
598
            $attributes[$this->column] = $this->label;
599
        }
600
601
        if (is_array($this->column)) {
602
            foreach ($this->column as $key => $column) {
603
                if (!array_key_exists($column, $input)) {
604
                    continue;
605
                }
606
                $input[$column.$key] = array_get($input, $column);
607
                $rules[$column.$key] = $fieldRules;
608
                $attributes[$column.$key] = $this->label."[$column]";
609
            }
610
        }
611
612
        return Validator::make($input, $rules, $this->validationMessages, $attributes);
613
    }
614
615
    /**
616
     * Sanitize input data.
617
     *
618
     * @param array  $input
619
     * @param string $column
620
     *
621
     * @return array
622
     */
623
    protected function sanitizeInput($input, $column)
624
    {
625
        if ($this instanceof Field\MultipleSelect) {
626
            $value = array_get($input, $column);
627
            array_set($input, $column, array_filter($value));
628
        }
629
630
        return $input;
631
    }
632
633
    /**
634
     * Add html attributes to elements.
635
     *
636
     * @param array|string $attribute
637
     * @param mixed        $value
638
     *
639
     * @return $this
640
     */
641
    public function attribute($attribute, $value = null)
642
    {
643
        if (is_array($attribute)) {
644
            $this->attributes = array_merge($this->attributes, $attribute);
645
        } else {
646
            $this->attributes[$attribute] = (string) $value;
647
        }
648
649
        return $this;
650
    }
651
652
    /**
653
     * Set the field as readonly mode.
654
     *
655
     * @return Field
656
     */
657
    public function readOnly()
658
    {
659
        return $this->attribute('disabled', true);
660
    }
661
662
    /**
663
     * Set field placeholder.
664
     *
665
     * @param string $placeholder
666
     *
667
     * @return Field
668
     */
669
    public function placeholder($placeholder = '')
670
    {
671
        $this->placeholder = $placeholder;
672
673
        return $this;
674
    }
675
676
    /**
677
     * Get placeholder.
678
     *
679
     * @return string
680
     */
681
    public function getPlaceholder()
682
    {
683
        return $this->placeholder ?: trans('admin.input').' '.$this->label;
684
    }
685
686
    /**
687
     * Prepare for a field value before update or insert.
688
     *
689
     * @param $value
690
     *
691
     * @return mixed
692
     */
693
    public function prepare($value)
694
    {
695
        return $value;
696
    }
697
698
    /**
699
     * Format the field attributes.
700
     *
701
     * @return string
702
     */
703
    protected function formatAttributes()
704
    {
705
        $html = [];
706
707
        foreach ($this->attributes as $name => $value) {
708
            $html[] = $name.'="'.e($value).'"';
709
        }
710
711
        return implode(' ', $html);
712
    }
713
714
    /**
715
     * @return $this
716
     */
717
    public function disableHorizontal()
718
    {
719
        $this->horizontal = false;
720
721
        return $this;
722
    }
723
724
    /**
725
     * @return array
726
     */
727
    public function getViewElementClasses()
728
    {
729
        if ($this->horizontal) {
730
            return [
731
                'label'      => "col-sm-{$this->width['label']}",
732
                'field'      => "col-sm-{$this->width['field']}",
733
                'form-group' => 'form-group ',
734
            ];
735
        }
736
737
        return ['label' => '', 'field' => '', 'form-group' => ''];
738
    }
739
740
    /**
741
     * Set form element class.
742
     *
743
     * @param string|array $class
744
     *
745
     * @return $this
746
     */
747
    public function setElementClass($class)
748
    {
749
        $this->elementClass = (array) $class;
750
751
        return $this;
752
    }
753
754
    /**
755
     * Get element class.
756
     *
757
     * @return array
758
     */
759
    protected function getElementClass()
760
    {
761
        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...
762
            $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...
763
764
            $this->elementClass = (array) str_replace(['[', ']'], '_', $name);
765
        }
766
767
        return $this->elementClass;
768
    }
769
770
    /**
771
     * Get element class string.
772
     *
773
     * @return mixed
774
     */
775 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...
776
    {
777
        $elementClass = $this->getElementClass();
778
779
        if (Arr::isAssoc($elementClass)) {
780
            $classes = [];
781
782
            foreach ($elementClass as $index => $class) {
783
                $classes[$index] = is_array($class) ? implode(' ', $class) : $class;
784
            }
785
786
            return $classes;
787
        }
788
789
        return implode(' ', $elementClass);
790
    }
791
792
    /**
793
     * Get element class selector.
794
     *
795
     * @return string
796
     */
797 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...
798
    {
799
        $elementClass = $this->getElementClass();
800
801
        if (Arr::isAssoc($elementClass)) {
802
            $classes = [];
803
804
            foreach ($elementClass as $index => $class) {
805
                $classes[$index] = '.'.(is_array($class) ? implode('.', $class) : $class);
806
            }
807
808
            return $classes;
809
        }
810
811
        return '.'.implode('.', $elementClass);
812
    }
813
814
    /**
815
     * Add the element class.
816
     *
817
     * @param $class
818
     *
819
     * @return $this
820
     */
821
    public function addElementClass($class)
822
    {
823
        if (is_array($class) || is_string($class)) {
824
            $this->elementClass = array_merge($this->elementClass, (array) $class);
825
826
            $this->elementClass = array_unique($this->elementClass);
827
        }
828
829
        return $this;
830
    }
831
832
    /**
833
     * Remove element class.
834
     *
835
     * @param $class
836
     *
837
     * @return $this
838
     */
839
    public function removeElementClass($class)
840
    {
841
        $delClass = [];
842
843
        if (is_string($class) || is_array($class)) {
844
            $delClass = (array) $class;
845
        }
846
847
        foreach ($delClass as $del) {
848
            if (($key = array_search($del, $this->elementClass))) {
849
                unset($this->elementClass[$key]);
850
            }
851
        }
852
853
        return $this;
854
    }
855
856
    /**
857
     * Get the view variables of this field.
858
     *
859
     * @return array
860
     */
861
    protected function variables()
862
    {
863
        return array_merge($this->variables, [
864
            'id'          => $this->id,
865
            '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...
866
            'help'        => $this->help,
867
            'class'       => $this->getElementClassString(),
868
            'value'       => $this->value(),
869
            'label'       => $this->label,
870
            'viewClass'   => $this->getViewElementClasses(),
871
            'column'      => $this->column,
872
            'errorKey'    => $this->getErrorKey(),
873
            'attributes'  => $this->formatAttributes(),
874
            'placeholder' => $this->getPlaceholder(),
875
        ]);
876
    }
877
878
    /**
879
     * Get view of this field.
880
     *
881
     * @return string
882
     */
883
    public function getView()
884
    {
885
        if (!empty($this->view)) {
886
            return $this->view;
887
        }
888
889
        $class = explode('\\', get_called_class());
890
891
        return 'admin::form.'.strtolower(end($class));
892
    }
893
894
    /**
895
     * Get script of current field.
896
     *
897
     * @return string
898
     */
899
    public function getScript()
900
    {
901
        return $this->script;
902
    }
903
904
    /**
905
     * Render this filed.
906
     *
907
     * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
908
     */
909
    public function render()
910
    {
911
        Admin::script($this->script);
912
913
        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 913 which is incompatible with the return type declared by the interface Illuminate\Contracts\Support\Renderable::render of type string.
Loading history...
914
    }
915
916
    /**
917
     * @return string
918
     */
919
    public function __toString()
920
    {
921
        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...
922
    }
923
}
924