Completed
Pull Request — master (#2153)
by
unknown
03:59
created

Field::fill()   B

Complexity

Conditions 5
Paths 4

Size

Total Lines 20
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 8
nc 4
nop 1
dl 0
loc 20
rs 8.8571
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 971.

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
     * column data format.
193
     *
194
     * @var Closure
195
     */
196
    protected $customFormat = null;
197
198
    /**
199
     * @var bool
200
     */
201
    protected $display = true;
202
203
    /**
204
     * Field constructor.
205
     *
206
     * @param $column
207
     * @param array $arguments
208
     */
209
    public function __construct($column, $arguments = [])
210
    {
211
        $this->column = $column;
212
        $this->label = $this->formatLabel($arguments);
213
        $this->id = $this->formatId($column);
214
    }
215
216
    /**
217
     * Get assets required by this field.
218
     *
219
     * @return array
220
     */
221
    public static function getAssets()
222
    {
223
        return [
224
            'css' => static::$css,
225
            'js'  => static::$js,
226
        ];
227
    }
228
229
    /**
230
     * Format the field element id.
231
     *
232
     * @param string|array $column
233
     *
234
     * @return string|array
235
     */
236
    protected function formatId($column)
237
    {
238
        return str_replace('.', '_', $column);
239
    }
240
241
    /**
242
     * Format the label value.
243
     *
244
     * @param array $arguments
245
     *
246
     * @return string
247
     */
248
    protected function formatLabel($arguments = [])
249
    {
250
        $column = is_array($this->column) ? current($this->column) : $this->column;
251
252
        $label = isset($arguments[0]) ? $arguments[0] : ucfirst($column);
253
254
        return str_replace(['.', '_'], ' ', $label);
255
    }
256
257
    /**
258
     * Format the name of the field.
259
     *
260
     * @param string $column
261
     *
262
     * @return array|mixed|string
263
     */
264
    protected function formatName($column)
265
    {
266
        if (is_string($column)) {
267
            $name = explode('.', $column);
268
269
            if (count($name) == 1) {
270
                return $name[0];
271
            }
272
273
            $html = array_shift($name);
274
            foreach ($name as $piece) {
275
                $html .= "[$piece]";
276
            }
277
278
            return $html;
279
        }
280
281
        if (is_array($this->column)) {
282
            $names = [];
283
            foreach ($this->column as $key => $name) {
284
                $names[$key] = $this->formatName($name);
285
            }
286
287
            return $names;
288
        }
289
290
        return '';
291
    }
292
293
    /**
294
     * Set form element name.
295
     *
296
     * @param string $name
297
     *
298
     * @return $this
299
     *
300
     * @author Edwin Hui
301
     */
302
    public function setElementName($name)
303
    {
304
        $this->elementName = $name;
305
306
        return $this;
307
    }
308
309
    /**
310
     * Fill data to the field.
311
     *
312
     * @param array $data
313
     *
314
     * @return void
315
     */
316
    public function fill($data)
317
    {
318
        // 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...
319
//        if (!is_null($this->value)) {
320
//            return;
321
//        }
322
323
        if (is_array($this->column)) {
324
            foreach ($this->column as $key => $column) {
325
                $this->value[$key] = array_get($data, $column);
326
            }
327
328
            return;
329
        }
330
331
        $this->value = array_get($data, $this->column);
332
        if (isset($this->customFormat) && $this->customFormat instanceof \Closure) {
333
            $this->value = call_user_func($this->customFormat, $this->value);
334
        }
335
    }
336
337
    /**
338
     * custom format form column data when edit.
339
     *
340
     * @param Closure $call
341
     *
342
     * @return [null]
0 ignored issues
show
Documentation introduced by
The doc-type [null] could not be parsed: Unknown type name "" at position 0. [(view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
343
     */
344
    public function customFormat(\Closure $call)
345
    {
346
        $this->customFormat = $call;
0 ignored issues
show
Documentation Bug introduced by
It seems like $call of type object<Closure> is incompatible with the declared type object<Encore\Admin\Form\Closure> of property $customFormat.

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