Completed
Pull Request — master (#2175)
by m
03:47
created

Field::getElementClassString()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 16

Duplication

Lines 16
Ratio 100 %

Importance

Changes 0
Metric Value
cc 4
nc 4
nop 0
dl 16
loc 16
rs 9.7333
c 0
b 0
f 0
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 16 and the first side effect is on line 976.

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
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
     * Validation rules.
94
     *
95
     * @var string|\Closure
96
     */
97
    protected $rules = '';
98
99
    /**
100
     * @var callable
101
     */
102
    protected $validator;
103
104
    /**
105
     * Validation messages.
106
     *
107
     * @var array
108
     */
109
    protected $validationMessages = [];
110
111
    /**
112
     * Css required by this field.
113
     *
114
     * @var array
115
     */
116
    protected static $css = [];
117
118
    /**
119
     * Js required by this field.
120
     *
121
     * @var array
122
     */
123
    protected static $js = [];
124
125
    /**
126
     * Script for field.
127
     *
128
     * @var string
129
     */
130
    protected $script = '';
131
132
    /**
133
     * Element attributes.
134
     *
135
     * @var array
136
     */
137
    protected $attributes = [];
138
139
    /**
140
     * Parent form.
141
     *
142
     * @var Form
143
     */
144
    protected $form = null;
145
146
    /**
147
     * View for field to render.
148
     *
149
     * @var string
150
     */
151
    protected $view = '';
152
153
    /**
154
     * Help block.
155
     *
156
     * @var array
157
     */
158
    protected $help = [];
159
160
    /**
161
     * Key for errors.
162
     *
163
     * @var mixed
164
     */
165
    protected $errorKey;
166
167
    /**
168
     * Placeholder for this field.
169
     *
170
     * @var string|array
171
     */
172
    protected $placeholder;
173
174
    /**
175
     * Width for label and field.
176
     *
177
     * @var array
178
     */
179
    protected $width = [
180
        'label' => 2,
181
        'field' => 8,
182
    ];
183
184
    /**
185
     * If the form horizontal layout.
186
     *
187
     * @var bool
188
     */
189
    protected $horizontal = true;
190
191
    /**
192
     * @var bool
193
     */
194
    protected $display = true;
195
196
    /**
197
     * @var array
198
     */
199
    protected $labelClass = [];
200
201
    /**
202
     * Field constructor.
203
     *
204
     * @param $column
205
     * @param array $arguments
206
     */
207
    public function __construct($column, $arguments = [])
208
    {
209
        $this->column = $column;
210
        $this->label = $this->formatLabel($arguments);
211
        $this->id = $this->formatId($column);
212
    }
213
214
    /**
215
     * Get assets required by this field.
216
     *
217
     * @return array
218
     */
219
    public static function getAssets()
220
    {
221
        return [
222
            'css' => static::$css,
223
            'js'  => static::$js,
224
        ];
225
    }
226
227
    /**
228
     * Format the field element id.
229
     *
230
     * @param string|array $column
231
     *
232
     * @return string|array
233
     */
234
    protected function formatId($column)
235
    {
236
        return str_replace('.', '_', $column);
237
    }
238
239
    /**
240
     * Format the label value.
241
     *
242
     * @param array $arguments
243
     *
244
     * @return string
245
     */
246
    protected function formatLabel($arguments = [])
247
    {
248
        $column = is_array($this->column) ? current($this->column) : $this->column;
249
250
        $label = isset($arguments[0]) ? $arguments[0] : ucfirst($column);
251
252
        return str_replace(['.', '_'], ' ', $label);
253
    }
254
255
    /**
256
     * Format the name of the field.
257
     *
258
     * @param string $column
259
     *
260
     * @return array|mixed|string
261
     */
262
    protected function formatName($column)
263
    {
264
        if (is_string($column)) {
265
            $name = explode('.', $column);
266
267
            if (count($name) == 1) {
268
                return $name[0];
269
            }
270
271
            $html = array_shift($name);
272
            foreach ($name as $piece) {
273
                $html .= "[$piece]";
274
            }
275
276
            return $html;
277
        }
278
279
        if (is_array($this->column)) {
280
            $names = [];
281
            foreach ($this->column as $key => $name) {
282
                $names[$key] = $this->formatName($name);
283
            }
284
285
            return $names;
286
        }
287
288
        return '';
289
    }
290
291
    /**
292
     * Set form element name.
293
     *
294
     * @param string $name
295
     *
296
     * @return $this
297
     *
298
     * @author Edwin Hui
299
     */
300
    public function setElementName($name)
301
    {
302
        $this->elementName = $name;
303
304
        return $this;
305
    }
306
307
    /**
308
     * Fill data to the field.
309
     *
310
     * @param array $data
311
     *
312
     * @return void
313
     */
314 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...
315
    {
316
        // 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...
317
//        if (!is_null($this->value)) {
318
//            return;
319
//        }
320
321
        if (is_array($this->column)) {
322
            foreach ($this->column as $key => $column) {
323
                $this->value[$key] = array_get($data, $column);
324
            }
325
326
            return;
327
        }
328
329
        $this->value = array_get($data, $this->column);
330
    }
331
332
    /**
333
     * Set original value to the field.
334
     *
335
     * @param array $data
336
     *
337
     * @return void
338
     */
339 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...
340
    {
341
        if (is_array($this->column)) {
342
            foreach ($this->column as $key => $column) {
343
                $this->original[$key] = array_get($data, $column);
344
            }
345
346
            return;
347
        }
348
349
        $this->original = array_get($data, $this->column);
350
    }
351
352
    /**
353
     * @param Form $form
354
     *
355
     * @return $this
356
     */
357
    public function setForm(Form $form = null)
358
    {
359
        $this->form = $form;
360
361
        return $this;
362
    }
363
364
    /**
365
     * Set width for field and label.
366
     *
367
     * @param int $field
368
     * @param int $label
369
     *
370
     * @return $this
371
     */
372
    public function setWidth($field = 8, $label = 2)
373
    {
374
        $this->width = [
375
            'label' => $label,
376
            'field' => $field,
377
        ];
378
379
        return $this;
380
    }
381
382
    /**
383
     * Set the field options.
384
     *
385
     * @param array $options
386
     *
387
     * @return $this
388
     */
389 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...
390
    {
391
        if ($options instanceof Arrayable) {
392
            $options = $options->toArray();
393
        }
394
395
        $this->options = array_merge($this->options, $options);
396
397
        return $this;
398
    }
399
400
    /**
401
     * Get or set rules.
402
     *
403
     * @param null  $rules
404
     * @param array $messages
405
     *
406
     * @return $this
407
     */
408
    public function rules($rules = null, $messages = [])
409
    {
410
        if ($rules instanceof \Closure) {
411
            $this->rules = $rules;
412
        }
413
414
        if (is_array($rules)) {
415
            $thisRuleArr = array_filter(explode('|', $this->rules));
416
417
            $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...
418
        } elseif (is_string($rules)) {
419
            $rules = array_filter(explode('|', "{$this->rules}|$rules"));
420
421
            $this->rules = implode('|', $rules);
422
        }
423
424
        $this->validationMessages = $messages;
425
426
        return $this;
427
    }
428
429
    /**
430
     * Get field validation rules.
431
     *
432
     * @return string
433
     */
434
    protected function getRules()
435
    {
436
        if ($this->rules instanceof \Closure) {
437
            return $this->rules->call($this, $this->form);
438
        }
439
440
        return $this->rules;
441
    }
442
443
    /**
444
     * Remove a specific rule.
445
     *
446
     * @param string $rule
447
     *
448
     * @return void
449
     */
450
    protected function removeRule($rule)
451
    {
452
        $this->rules = str_replace($rule, '', $this->rules);
453
    }
454
455
    /**
456
     * Set field validator.
457
     *
458
     * @param callable $validator
459
     *
460
     * @return $this
461
     */
462
    public function validator(callable $validator)
463
    {
464
        $this->validator = $validator;
465
466
        return $this;
467
    }
468
469
    /**
470
     * Get key for error message.
471
     *
472
     * @return string
473
     */
474
    public function getErrorKey()
475
    {
476
        return $this->errorKey ?: $this->column;
477
    }
478
479
    /**
480
     * Set key for error message.
481
     *
482
     * @param string $key
483
     *
484
     * @return $this
485
     */
486
    public function setErrorKey($key)
487
    {
488
        $this->errorKey = $key;
489
490
        return $this;
491
    }
492
493
    /**
494
     * Set or get value of the field.
495
     *
496
     * @param null $value
497
     *
498
     * @return mixed
499
     */
500 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...
501
    {
502
        if (is_null($value)) {
503
            return is_null($this->value) ? $this->getDefault() : $this->value;
504
        }
505
506
        $this->value = $value;
507
508
        return $this;
509
    }
510
511
    /**
512
     * Set default value for field.
513
     *
514
     * @param $default
515
     *
516
     * @return $this
517
     */
518
    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...
519
    {
520
        $this->default = $default;
521
522
        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...
523
    }
524
525
    /**
526
     * Get default value.
527
     *
528
     * @return mixed
529
     */
530
    public function getDefault()
531
    {
532
        if ($this->default instanceof \Closure) {
533
            return call_user_func($this->default, $this->form);
534
        }
535
536
        return $this->default;
537
    }
538
539
    /**
540
     * Set help block for current field.
541
     *
542
     * @param string $text
543
     * @param string $icon
544
     *
545
     * @return $this
546
     */
547
    public function help($text = '', $icon = 'fa-info-circle')
548
    {
549
        $this->help = compact('text', 'icon');
550
551
        return $this;
552
    }
553
554
    /**
555
     * Get column of the field.
556
     *
557
     * @return string|array
558
     */
559
    public function column()
560
    {
561
        return $this->column;
562
    }
563
564
    /**
565
     * Get label of the field.
566
     *
567
     * @return string
568
     */
569
    public function label()
570
    {
571
        return $this->label;
572
    }
573
574
    /**
575
     * Get original value of the field.
576
     *
577
     * @return mixed
578
     */
579
    public function original()
580
    {
581
        return $this->original;
582
    }
583
584
    /**
585
     * Get validator for this field.
586
     *
587
     * @param array $input
588
     *
589
     * @return bool|Validator
590
     */
591
    public function getValidator(array $input)
592
    {
593
        if ($this->validator) {
594
            return $this->validator->call($this, $input);
595
        }
596
597
        $rules = $attributes = [];
598
599
        if (!$fieldRules = $this->getRules()) {
600
            return false;
601
        }
602
603
        if (is_string($this->column)) {
604
            if (!array_has($input, $this->column)) {
605
                return false;
606
            }
607
608
            $input = $this->sanitizeInput($input, $this->column);
609
610
            $rules[$this->column] = $fieldRules;
611
            $attributes[$this->column] = $this->label;
612
        }
613
614
        if (is_array($this->column)) {
615
            foreach ($this->column as $key => $column) {
616
                if (!array_key_exists($column, $input)) {
617
                    continue;
618
                }
619
                $input[$column.$key] = array_get($input, $column);
620
                $rules[$column.$key] = $fieldRules;
621
                $attributes[$column.$key] = $this->label."[$column]";
622
            }
623
        }
624
625
        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...
626
    }
627
628
    /**
629
     * Sanitize input data.
630
     *
631
     * @param array  $input
632
     * @param string $column
633
     *
634
     * @return array
635
     */
636
    protected function sanitizeInput($input, $column)
637
    {
638
        if ($this instanceof Field\MultipleSelect) {
639
            $value = array_get($input, $column);
640
            array_set($input, $column, array_filter($value));
641
        }
642
643
        return $input;
644
    }
645
646
    /**
647
     * Add html attributes to elements.
648
     *
649
     * @param array|string $attribute
650
     * @param mixed        $value
651
     *
652
     * @return $this
653
     */
654
    public function attribute($attribute, $value = null)
655
    {
656
        if (is_array($attribute)) {
657
            $this->attributes = array_merge($this->attributes, $attribute);
658
        } else {
659
            $this->attributes[$attribute] = (string) $value;
660
        }
661
662
        return $this;
663
    }
664
665
    /**
666
     * Set the field as readonly mode.
667
     *
668
     * @return Field
669
     */
670
    public function readOnly()
671
    {
672
        return $this->attribute('disabled', true);
673
    }
674
675
    /**
676
     * Set field placeholder.
677
     *
678
     * @param string $placeholder
679
     *
680
     * @return Field
681
     */
682
    public function placeholder($placeholder = '')
683
    {
684
        $this->placeholder = $placeholder;
685
686
        return $this;
687
    }
688
689
    /**
690
     * Get placeholder.
691
     *
692
     * @return string
693
     */
694
    public function getPlaceholder()
695
    {
696
        return $this->placeholder ?: trans('admin.input').' '.$this->label;
697
    }
698
699
    /**
700
     * Prepare for a field value before update or insert.
701
     *
702
     * @param $value
703
     *
704
     * @return mixed
705
     */
706
    public function prepare($value)
707
    {
708
        return $value;
709
    }
710
711
    /**
712
     * Format the field attributes.
713
     *
714
     * @return string
715
     */
716
    protected function formatAttributes()
717
    {
718
        $html = [];
719
720
        foreach ($this->attributes as $name => $value) {
721
            $html[] = $name.'="'.e($value).'"';
722
        }
723
724
        return implode(' ', $html);
725
    }
726
727
    /**
728
     * @return $this
729
     */
730
    public function disableHorizontal()
731
    {
732
        $this->horizontal = false;
733
734
        return $this;
735
    }
736
737
    /**
738
     * @return array
739
     */
740
    public function getViewElementClasses()
741
    {
742
        if ($this->horizontal) {
743
            return [
744
                'label'      => "col-sm-{$this->width['label']} {$this->getLabelClass()}",
745
                'field'      => "col-sm-{$this->width['field']}",
746
                'form-group' => 'form-group ',
747
            ];
748
        }
749
750
        return ['label' => "{$this->getLabelClass()}", 'field' => '', 'form-group' => ''];
751
    }
752
753
    /**
754
     * Set form element class.
755
     *
756
     * @param string|array $class
757
     *
758
     * @return $this
759
     */
760
    public function setElementClass($class)
761
    {
762
        $this->elementClass = (array) $class;
763
764
        return $this;
765
    }
766
767
    /**
768
     * Get element class.
769
     *
770
     * @return array
771
     */
772
    protected function getElementClass()
773
    {
774
        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...
775
            $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...
776
777
            $this->elementClass = (array) str_replace(['[', ']'], '_', $name);
778
        }
779
780
        return $this->elementClass;
781
    }
782
783
    /**
784
     * Get element class string.
785
     *
786
     * @return mixed
787
     */
788 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...
789
    {
790
        $elementClass = $this->getElementClass();
791
792
        if (Arr::isAssoc($elementClass)) {
793
            $classes = [];
794
795
            foreach ($elementClass as $index => $class) {
796
                $classes[$index] = is_array($class) ? implode(' ', $class) : $class;
797
            }
798
799
            return $classes;
800
        }
801
802
        return implode(' ', $elementClass);
803
    }
804
805
    /**
806
     * Get element class selector.
807
     *
808
     * @return string
809
     */
810 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...
811
    {
812
        $elementClass = $this->getElementClass();
813
814
        if (Arr::isAssoc($elementClass)) {
815
            $classes = [];
816
817
            foreach ($elementClass as $index => $class) {
818
                $classes[$index] = '.'.(is_array($class) ? implode('.', $class) : $class);
819
            }
820
821
            return $classes;
822
        }
823
824
        return '.'.implode('.', $elementClass);
825
    }
826
827
    /**
828
     * Add the element class.
829
     *
830
     * @param $class
831
     *
832
     * @return $this
833
     */
834
    public function addElementClass($class)
835
    {
836
        if (is_array($class) || is_string($class)) {
837
            $this->elementClass = array_merge($this->elementClass, (array) $class);
838
839
            $this->elementClass = array_unique($this->elementClass);
840
        }
841
842
        return $this;
843
    }
844
845
    /**
846
     * Remove element class.
847
     *
848
     * @param $class
849
     *
850
     * @return $this
851
     */
852
    public function removeElementClass($class)
853
    {
854
        $delClass = [];
855
856
        if (is_string($class) || is_array($class)) {
857
            $delClass = (array) $class;
858
        }
859
860
        foreach ($delClass as $del) {
861
            if (($key = array_search($del, $this->elementClass))) {
862
                unset($this->elementClass[$key]);
863
            }
864
        }
865
866
        return $this;
867
    }
868
869
    /**
870
     * Add variables to field view.
871
     *
872
     * @param array $variables
873
     *
874
     * @return $this
875
     */
876
    protected function addVariables(array $variables = [])
877
    {
878
        $this->variables = array_merge($this->variables, $variables);
879
880
        return $this;
881
    }
882
883
    /**
884
     * @return string
885
     */
886
    public function getLabelClass()
887
    : string
888
    {
889
        return implode(' ', $this->labelClass);
890
    }
891
892
    /**
893
     * @param array $labelClass
894
     *
895
     * @return Field
896
     */
897
    public function setLabelClass(array $labelClass)
898
    : Field
899
    {
900
        $this->labelClass = $labelClass;
901
902
        return $this;
903
    }
904
905
    /**
906
     * Get the view variables of this field.
907
     *
908
     * @return array
909
     */
910
    protected function variables()
911
    {
912
        return array_merge($this->variables, [
913
            'id'          => $this->id,
914
            '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...
915
            'help'        => $this->help,
916
            'class'       => $this->getElementClassString(),
917
            'value'       => $this->value(),
918
            'label'       => $this->label,
919
            'viewClass'   => $this->getViewElementClasses(),
920
            'column'      => $this->column,
921
            'errorKey'    => $this->getErrorKey(),
922
            'attributes'  => $this->formatAttributes(),
923
            'placeholder' => $this->getPlaceholder(),
924
        ]);
925
    }
926
927
    /**
928
     * Get view of this field.
929
     *
930
     * @return string
931
     */
932
    public function getView()
933
    {
934
        if (!empty($this->view)) {
935
            return $this->view;
936
        }
937
938
        $class = explode('\\', get_called_class());
939
940
        return 'admin::form.'.strtolower(end($class));
941
    }
942
943
    /**
944
     * Get script of current field.
945
     *
946
     * @return string
947
     */
948
    public function getScript()
949
    {
950
        return $this->script;
951
    }
952
953
    /**
954
     * Render this filed.
955
     *
956
     * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
957
     */
958
    public function render()
959
    {
960
        if (!$this->display) {
961
            return '';
962
        }
963
964
        Admin::script($this->script);
965
966
        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 966 which is incompatible with the return type declared by the interface Illuminate\Contracts\Support\Renderable::render of type string.
Loading history...
967
    }
968
969
    /**
970
     * @return string
971
     */
972
    public function __toString()
973
    {
974
        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...
975
    }
976
}