Completed
Push — master ( 3264d1...cd483f )
by Song
12s
created

Field::setElementClass()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 1
dl 0
loc 6
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Encore\Admin\Form;
4
5
use Encore\Admin\Admin;
6
use Encore\Admin\Form;
7
use Illuminate\Contracts\Support\Arrayable;
8
use Illuminate\Contracts\Support\Renderable;
9
use Illuminate\Support\Arr;
10
use Illuminate\Support\Facades\Validator;
11
use Illuminate\Support\Traits\Macroable;
12
13
/**
14
 * Class Field.
15
 */
16
class Field implements Renderable
17
{
18
    use Macroable;
19
20
    const FILE_DELETE_FLAG = '_file_del_';
21
22
    /**
23
     * Element id.
24
     *
25
     * @var array|string
26
     */
27
    protected $id;
28
29
    /**
30
     * Element value.
31
     *
32
     * @var mixed
33
     */
34
    protected $value;
35
36
    /**
37
     * Field original value.
38
     *
39
     * @var mixed
40
     */
41
    protected $original;
42
43
    /**
44
     * Field default value.
45
     *
46
     * @var mixed
47
     */
48
    protected $default;
49
50
    /**
51
     * Element label.
52
     *
53
     * @var string
54
     */
55
    protected $label = '';
56
57
    /**
58
     * Column name.
59
     *
60
     * @var string|array
61
     */
62
    protected $column = '';
63
64
    /**
65
     * Form element name.
66
     *
67
     * @var string
68
     */
69
    protected $elementName = [];
70
71
    /**
72
     * Form element classes.
73
     *
74
     * @var array
75
     */
76
    protected $elementClass = [];
77
78
    /**
79
     * Variables of elements.
80
     *
81
     * @var array
82
     */
83
    protected $variables = [];
84
85
    /**
86
     * Options for specify elements.
87
     *
88
     * @var array
89
     */
90
    protected $options = [];
91
92
    /**
93
     * 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
     * @var array
205
     */
206
    protected $labelClass = [];
207
208
    /**
209
     * Field constructor.
210
     *
211
     * @param       $column
212
     * @param array $arguments
213
     */
214
    public function __construct($column, $arguments = [])
215
    {
216
        $this->column = $column;
217
        $this->label = $this->formatLabel($arguments);
218
        $this->id = $this->formatId($column);
219
    }
220
221
    /**
222
     * Get assets required by this field.
223
     *
224
     * @return array
225
     */
226
    public static function getAssets()
227
    {
228
        return [
229
            'css' => static::$css,
230
            'js'  => static::$js,
231
        ];
232
    }
233
234
    /**
235
     * Format the field element id.
236
     *
237
     * @param string|array $column
238
     *
239
     * @return string|array
240
     */
241
    protected function formatId($column)
242
    {
243
        return str_replace('.', '_', $column);
244
    }
245
246
    /**
247
     * Format the label value.
248
     *
249
     * @param array $arguments
250
     *
251
     * @return string
252
     */
253
    protected function formatLabel($arguments = [])
254
    {
255
        $column = is_array($this->column) ? current($this->column) : $this->column;
256
257
        $label = isset($arguments[0]) ? $arguments[0] : ucfirst($column);
258
259
        return str_replace(['.', '_'], ' ', $label);
260
    }
261
262
    /**
263
     * Format the name of the field.
264
     *
265
     * @param string $column
266
     *
267
     * @return array|mixed|string
268
     */
269
    protected function formatName($column)
270
    {
271
        if (is_string($column)) {
272
            $name = explode('.', $column);
273
274
            if (count($name) == 1) {
275
                return $name[0];
276
            }
277
278
            $html = array_shift($name);
279
            foreach ($name as $piece) {
280
                $html .= "[$piece]";
281
            }
282
283
            return $html;
284
        }
285
286
        if (is_array($this->column)) {
287
            $names = [];
288
            foreach ($this->column as $key => $name) {
289
                $names[$key] = $this->formatName($name);
290
            }
291
292
            return $names;
293
        }
294
295
        return '';
296
    }
297
298
    /**
299
     * Set form element name.
300
     *
301
     * @param string $name
302
     *
303
     * @return $this
304
     *
305
     * @author Edwin Hui
306
     */
307
    public function setElementName($name)
308
    {
309
        $this->elementName = $name;
310
311
        return $this;
312
    }
313
314
    /**
315
     * Fill data to the field.
316
     *
317
     * @param array $data
318
     *
319
     * @return void
320
     */
321
    public function fill($data)
322
    {
323
        // Field value is already setted.
324
//        if (!is_null($this->value)) {
325
//            return;
326
//        }
327
328
        if (is_array($this->column)) {
329
            foreach ($this->column as $key => $column) {
330
                $this->value[$key] = array_get($data, $column);
331
            }
332
333
            return;
334
        }
335
336
        $this->value = array_get($data, $this->column);
337
        if (isset($this->customFormat) && $this->customFormat instanceof \Closure) {
338
            $this->value = call_user_func($this->customFormat, $this->value);
339
        }
340
    }
341
342
    /**
343
     * custom format form column data when edit.
344
     *
345
     * @param Closure $call
346
     *
347
     * @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...
348
     */
349
    public function customFormat(\Closure $call)
350
    {
351
        $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...
352
    }
353
354
    /**
355
     * Set original value to the field.
356
     *
357
     * @param array $data
358
     *
359
     * @return void
360
     */
361
    public function setOriginal($data)
362
    {
363
        if (is_array($this->column)) {
364
            foreach ($this->column as $key => $column) {
365
                $this->original[$key] = array_get($data, $column);
366
            }
367
368
            return;
369
        }
370
371
        $this->original = array_get($data, $this->column);
372
    }
373
374
    /**
375
     * @param Form $form
376
     *
377
     * @return $this
378
     */
379
    public function setForm(Form $form = null)
380
    {
381
        $this->form = $form;
382
383
        return $this;
384
    }
385
386
    /**
387
     * Set width for field and label.
388
     *
389
     * @param int $field
390
     * @param int $label
391
     *
392
     * @return $this
393
     */
394
    public function setWidth($field = 8, $label = 2)
395
    {
396
        $this->width = [
397
            'label' => $label,
398
            'field' => $field,
399
        ];
400
401
        return $this;
402
    }
403
404
    /**
405
     * Set the field options.
406
     *
407
     * @param array $options
408
     *
409
     * @return $this
410
     */
411 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...
412
    {
413
        if ($options instanceof Arrayable) {
414
            $options = $options->toArray();
415
        }
416
417
        $this->options = array_merge($this->options, $options);
418
419
        return $this;
420
    }
421
422
    /**
423
     * Get or set rules.
424
     *
425
     * @param null  $rules
426
     * @param array $messages
427
     *
428
     * @return $this
429
     */
430
    public function rules($rules = null, $messages = [])
431
    {
432
        if ($rules instanceof \Closure) {
433
            $this->rules = $rules;
434
        }
435
436
        if (is_array($rules)) {
437
            $thisRuleArr = array_filter(explode('|', $this->rules));
438
439
            $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...
440
        } elseif (is_string($rules)) {
441
            $rules = array_filter(explode('|', "{$this->rules}|$rules"));
442
443
            $this->rules = implode('|', $rules);
444
        }
445
446
        $this->validationMessages = $messages;
447
448
        return $this;
449
    }
450
451
    /**
452
     * Get field validation rules.
453
     *
454
     * @return string
455
     */
456
    protected function getRules()
457
    {
458
        if ($this->rules instanceof \Closure) {
459
            return $this->rules->call($this, $this->form);
460
        }
461
462
        return $this->rules;
463
    }
464
465
    /**
466
     * Remove a specific rule by keyword.
467
     *
468
     * @param string $rule
469
     *
470
     * @return void
471
     */
472
    protected function removeRule($rule)
473
    {
474
        if (!is_string($this->rules)) {
475
            return;
476
        }
477
478
        $pattern = "/{$rule}[^\|]?(\||$)/";
479
        $this->rules = preg_replace($pattern, '', $this->rules, -1);
480
    }
481
482
    /**
483
     * Set field validator.
484
     *
485
     * @param callable $validator
486
     *
487
     * @return $this
488
     */
489
    public function validator(callable $validator)
490
    {
491
        $this->validator = $validator;
492
493
        return $this;
494
    }
495
496
    /**
497
     * Get key for error message.
498
     *
499
     * @return string
500
     */
501
    public function getErrorKey()
502
    {
503
        return $this->errorKey ?: $this->column;
504
    }
505
506
    /**
507
     * Set key for error message.
508
     *
509
     * @param string $key
510
     *
511
     * @return $this
512
     */
513
    public function setErrorKey($key)
514
    {
515
        $this->errorKey = $key;
516
517
        return $this;
518
    }
519
520
    /**
521
     * Set or get value of the field.
522
     *
523
     * @param null $value
524
     *
525
     * @return mixed
526
     */
527 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...
528
    {
529
        if (is_null($value)) {
530
            return is_null($this->value) ? $this->getDefault() : $this->value;
531
        }
532
533
        $this->value = $value;
534
535
        return $this;
536
    }
537
538
    /**
539
     * Set default value for field.
540
     *
541
     * @param $default
542
     *
543
     * @return $this
544
     */
545
    public function default($default)
546
    {
547
        $this->default = $default;
548
549
        return $this;
550
    }
551
552
    /**
553
     * Get default value.
554
     *
555
     * @return mixed
556
     */
557
    public function getDefault()
558
    {
559
        if ($this->default instanceof \Closure) {
560
            return call_user_func($this->default, $this->form);
561
        }
562
563
        return $this->default;
564
    }
565
566
    /**
567
     * Set help block for current field.
568
     *
569
     * @param string $text
570
     * @param string $icon
571
     *
572
     * @return $this
573
     */
574
    public function help($text = '', $icon = 'fa-info-circle')
575
    {
576
        $this->help = compact('text', 'icon');
577
578
        return $this;
579
    }
580
581
    /**
582
     * Get column of the field.
583
     *
584
     * @return string|array
585
     */
586
    public function column()
587
    {
588
        return $this->column;
589
    }
590
591
    /**
592
     * Get label of the field.
593
     *
594
     * @return string
595
     */
596
    public function label()
597
    {
598
        return $this->label;
599
    }
600
601
    /**
602
     * Get original value of the field.
603
     *
604
     * @return mixed
605
     */
606
    public function original()
607
    {
608
        return $this->original;
609
    }
610
611
    /**
612
     * Get validator for this field.
613
     *
614
     * @param array $input
615
     *
616
     * @return bool|Validator
617
     */
618
    public function getValidator(array $input)
619
    {
620
        if ($this->validator) {
621
            return $this->validator->call($this, $input);
622
        }
623
624
        $rules = $attributes = [];
625
626
        if (!$fieldRules = $this->getRules()) {
627
            return false;
628
        }
629
630
        if (is_string($this->column)) {
631
            if (!array_has($input, $this->column)) {
632
                return false;
633
            }
634
635
            $input = $this->sanitizeInput($input, $this->column);
636
637
            $rules[$this->column] = $fieldRules;
638
            $attributes[$this->column] = $this->label;
639
        }
640
641
        if (is_array($this->column)) {
642
            foreach ($this->column as $key => $column) {
643
                if (!array_key_exists($column, $input)) {
644
                    continue;
645
                }
646
                $input[$column.$key] = array_get($input, $column);
647
                $rules[$column.$key] = $fieldRules;
648
                $attributes[$column.$key] = $this->label."[$column]";
649
            }
650
        }
651
652
        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...
653
    }
654
655
    /**
656
     * Sanitize input data.
657
     *
658
     * @param array  $input
659
     * @param string $column
660
     *
661
     * @return array
662
     */
663
    protected function sanitizeInput($input, $column)
664
    {
665
        if ($this instanceof Field\MultipleSelect) {
666
            $value = array_get($input, $column);
667
            array_set($input, $column, array_filter($value));
668
        }
669
670
        return $input;
671
    }
672
673
    /**
674
     * Add html attributes to elements.
675
     *
676
     * @param array|string $attribute
677
     * @param mixed        $value
678
     *
679
     * @return $this
680
     */
681
    public function attribute($attribute, $value = null)
682
    {
683
        if (is_array($attribute)) {
684
            $this->attributes = array_merge($this->attributes, $attribute);
685
        } else {
686
            $this->attributes[$attribute] = (string) $value;
687
        }
688
689
        return $this;
690
    }
691
692
693
    /**
694
     * Set the field automatically get focus.
695
     *
696
     * @return Field
697
     */
698
    public function autofocus()
699
    {
700
        return $this->attribute('autofocus', true);
701
    }
702
703
704
    /**
705
     * Set the field as readonly mode.
706
     *
707
     * @return Field
708
     */
709
    public function readOnly()
710
    {
711
        return $this->attribute('readonly', true);
712
    }
713
714
    /**
715
     * Set field as disabled.
716
     *
717
     * @return Field
718
     */
719
    public function disable()
720
    {
721
        return $this->attribute('disabled', true);
722
    }
723
724
    /**
725
     * Set field placeholder.
726
     *
727
     * @param string $placeholder
728
     *
729
     * @return Field
730
     */
731
    public function placeholder($placeholder = '')
732
    {
733
        $this->placeholder = $placeholder;
734
735
        return $this;
736
    }
737
738
    /**
739
     * Get placeholder.
740
     *
741
     * @return string
742
     */
743
    public function getPlaceholder()
744
    {
745
        return $this->placeholder ?: trans('admin.input').' '.$this->label;
746
    }
747
748
    /**
749
     * Prepare for a field value before update or insert.
750
     *
751
     * @param $value
752
     *
753
     * @return mixed
754
     */
755
    public function prepare($value)
756
    {
757
        return $value;
758
    }
759
760
    /**
761
     * Format the field attributes.
762
     *
763
     * @return string
764
     */
765
    protected function formatAttributes()
766
    {
767
        $html = [];
768
769
        foreach ($this->attributes as $name => $value) {
770
            $html[] = $name.'="'.e($value).'"';
771
        }
772
773
        return implode(' ', $html);
774
    }
775
776
    /**
777
     * @return $this
778
     */
779
    public function disableHorizontal()
780
    {
781
        $this->horizontal = false;
782
783
        return $this;
784
    }
785
786
    /**
787
     * @return array
788
     */
789
    public function getViewElementClasses()
790
    {
791
        if ($this->horizontal) {
792
            return [
793
                'label'      => "col-sm-{$this->width['label']} {$this->getLabelClass()}",
794
                'field'      => "col-sm-{$this->width['field']}",
795
                'form-group' => 'form-group ',
796
            ];
797
        }
798
799
        return ['label' => "{$this->getLabelClass()}", 'field' => '', 'form-group' => ''];
800
    }
801
802
    /**
803
     * Set form element class.
804
     *
805
     * @param string|array $class
806
     *
807
     * @return $this
808
     */
809
    public function setElementClass($class)
810
    {
811
        $this->elementClass = (array) $class;
812
813
        return $this;
814
    }
815
816
    /**
817
     * Get element class.
818
     *
819
     * @return array
820
     */
821
    protected function getElementClass()
822
    {
823
        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...
824
            $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...
825
826
            $this->elementClass = (array) str_replace(['[', ']'], '_', $name);
827
        }
828
829
        return $this->elementClass;
830
    }
831
832
    /**
833
     * Get element class string.
834
     *
835
     * @return mixed
836
     */
837 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...
838
    {
839
        $elementClass = $this->getElementClass();
840
841
        if (Arr::isAssoc($elementClass)) {
842
            $classes = [];
843
844
            foreach ($elementClass as $index => $class) {
845
                $classes[$index] = is_array($class) ? implode(' ', $class) : $class;
846
            }
847
848
            return $classes;
849
        }
850
851
        return implode(' ', $elementClass);
852
    }
853
854
    /**
855
     * Get element class selector.
856
     *
857
     * @return string
858
     */
859 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...
860
    {
861
        $elementClass = $this->getElementClass();
862
863
        if (Arr::isAssoc($elementClass)) {
864
            $classes = [];
865
866
            foreach ($elementClass as $index => $class) {
867
                $classes[$index] = '.'.(is_array($class) ? implode('.', $class) : $class);
868
            }
869
870
            return $classes;
871
        }
872
873
        return '.'.implode('.', $elementClass);
874
    }
875
876
    /**
877
     * Add the element class.
878
     *
879
     * @param $class
880
     *
881
     * @return $this
882
     */
883
    public function addElementClass($class)
884
    {
885
        if (is_array($class) || is_string($class)) {
886
            $this->elementClass = array_merge($this->elementClass, (array) $class);
887
888
            $this->elementClass = array_unique($this->elementClass);
889
        }
890
891
        return $this;
892
    }
893
894
    /**
895
     * Remove element class.
896
     *
897
     * @param $class
898
     *
899
     * @return $this
900
     */
901
    public function removeElementClass($class)
902
    {
903
        $delClass = [];
904
905
        if (is_string($class) || is_array($class)) {
906
            $delClass = (array) $class;
907
        }
908
909
        foreach ($delClass as $del) {
910
            if (($key = array_search($del, $this->elementClass))) {
911
                unset($this->elementClass[$key]);
912
            }
913
        }
914
915
        return $this;
916
    }
917
918
    /**
919
     * Add variables to field view.
920
     *
921
     * @param array $variables
922
     *
923
     * @return $this
924
     */
925
    protected function addVariables(array $variables = [])
926
    {
927
        $this->variables = array_merge($this->variables, $variables);
928
929
        return $this;
930
    }
931
932
    /**
933
     * @return string
934
     */
935
    public function getLabelClass()
936
    : string
937
    {
938
        return implode(' ', $this->labelClass);
939
    }
940
941
    /**
942
     * @param array $labelClass
943
     *
944
     * @return self
945
     */
946
    public function setLabelClass(array $labelClass)
947
    : self
948
    {
949
        $this->labelClass = $labelClass;
950
951
        return $this;
952
    }
953
954
    /**
955
     * Get the view variables of this field.
956
     *
957
     * @return array
958
     */
959
    public function variables()
960
    {
961
        return array_merge($this->variables, [
962
            'id'          => $this->id,
963
            '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...
964
            'help'        => $this->help,
965
            'class'       => $this->getElementClassString(),
966
            'value'       => $this->value(),
967
            'label'       => $this->label,
968
            'viewClass'   => $this->getViewElementClasses(),
969
            'column'      => $this->column,
970
            'errorKey'    => $this->getErrorKey(),
971
            'attributes'  => $this->formatAttributes(),
972
            'placeholder' => $this->getPlaceholder(),
973
        ]);
974
    }
975
976
    /**
977
     * Get view of this field.
978
     *
979
     * @return string
980
     */
981
    public function getView()
982
    {
983
        if (!empty($this->view)) {
984
            return $this->view;
985
        }
986
987
        $class = explode('\\', get_called_class());
988
989
        return 'admin::form.'.strtolower(end($class));
990
    }
991
992
    /**
993
     * Get script of current field.
994
     *
995
     * @return string
996
     */
997
    public function getScript()
998
    {
999
        return $this->script;
1000
    }
1001
1002
    /**
1003
     * Render this filed.
1004
     *
1005
     * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
1006
     */
1007
    public function render()
1008
    {
1009
        if (!$this->display) {
1010
            return '';
1011
        }
1012
1013
        Admin::script($this->script);
1014
1015
        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 1015 which is incompatible with the return type declared by the interface Illuminate\Contracts\Support\Renderable::render of type string.
Loading history...
1016
    }
1017
1018
    /**
1019
     * @return string
1020
     */
1021
    public function __toString()
1022
    {
1023
        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...
1024
    }
1025
}
1026