Completed
Pull Request — master (#1706)
by
unknown
15:51 queued 09:31
created

Field::options()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 5

Duplication

Lines 10
Ratio 100 %

Importance

Changes 0
Metric Value
cc 2
eloc 5
nc 2
nop 1
dl 10
loc 10
rs 9.4285
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 15 and the first side effect is on line 1003.

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

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

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

Loading history...
2
3
namespace Encore\Admin\Form;
4
5
use Encore\Admin\Admin;
6
use Encore\Admin\Form;
7
use Illuminate\Contracts\Support\Arrayable;
8
use Illuminate\Contracts\Support\Renderable;
9
use Illuminate\Support\Arr;
10
use Illuminate\Support\Facades\Validator;
11
12
/**
13
 * Class Field.
14
 */
15
class Field implements Renderable
16
{
17
    const FILE_DELETE_FLAG = '_file_del_';
18
19
    /**
20
     * Element id.
21
     *
22
     * @var array|string
23
     */
24
    protected $id;
25
26
    /**
27
     * Element value.
28
     *
29
     * @var mixed
30
     */
31
    protected $value;
32
33
    /**
34
     * Field original value.
35
     *
36
     * @var mixed
37
     */
38
    protected $original;
39
40
    /**
41
     * Field default value.
42
     *
43
     * @var mixed
44
     */
45
    protected $default;
46
47
    /**
48
     * Element label.
49
     *
50
     * @var string
51
     */
52
    protected $label = '';
53
54
    /**
55
     * Column name.
56
     *
57
     * @var string|array
58
     */
59
    protected $column = '';
60
61
    /**
62
     * Form element name.
63
     *
64
     * @var string
65
     */
66
    protected $elementName = [];
67
68
    /**
69
     * Form element classes.
70
     *
71
     * @var array
72
     */
73
    protected $elementClass = [];
74
75
    /**
76
     * Variables of elements.
77
     *
78
     * @var array
79
     */
80
    protected $variables = [];
81
82
    /**
83
     * Options for specify elements.
84
     *
85
     * @var array
86
     */
87
    protected $options = [];
88
89
    /**
90
     * Validation rules.
91
     *
92
     * @var string|\Closure
93
     */
94
    protected $rules = '';
95
96
    /**
97
     * @var callable
98
     */
99
    protected $validator;
100
101
    /**
102
     * Validation messages.
103
     *
104
     * @var array
105
     */
106
    protected $validationMessages = [];
107
108
    /**
109
     * Css required by this field.
110
     *
111
     * @var array
112
     */
113
    protected static $css = [];
114
115
    /**
116
     * Js required by this field.
117
     *
118
     * @var array
119
     */
120
    protected static $js = [];
121
122
    /**
123
     * Script for field.
124
     *
125
     * @var string
126
     */
127
    protected $script = '';
128
129
    /**
130
     * Element attributes.
131
     *
132
     * @var array
133
     */
134
    protected $attributes = [];
135
136
    /**
137
     * Parent form.
138
     *
139
     * @var Form
140
     */
141
    protected $form = null;
142
143
    /**
144
     * View for field to render.
145
     *
146
     * @var string
147
     */
148
    protected $view = '';
149
150
    /**
151
     * Help block.
152
     *
153
     * @var array
154
     */
155
    protected $help = [];
156
157
    /**
158
     * Key for errors.
159
     *
160
     * @var mixed
161
     */
162
    protected $errorKey;
163
164
    /**
165
     * Placeholder for this field.
166
     *
167
     * @var string|array
168
     */
169
    protected $placeholder;
170
171
    /**
172
     * Width for label and field.
173
     *
174
     * @var array
175
     */
176
    protected $width = [
177
        'label' => 2,
178
        'field' => 8,
179
    ];
180
181
    /**
182
     * Set field width
183
     *
184
     * @var integer
185
     */
186
    protected $fieldWidth;
187
188
    /**
189
     * @var boolean
190
     */
191
    protected $labelNoWidth;
192
193
    /**
194
     * @var boolean
195
     */
196
    protected $controlLabel;
197
198
    /**
199
     * If the form horizontal layout.
200
     *
201
     * @var bool
202
     */
203
    protected $horizontal = true;
204
205
    /**
206
     * Field constructor.
207
     *
208
     * @param $column
209
     * @param array $arguments
210
     */
211
    public function __construct($column, $arguments = [])
212
    {
213
        $this->column = $column;
214
        $this->label = $this->formatLabel($arguments);
215
        $this->id = $this->formatId($column);
216
    }
217
218
    /**
219
     * Get assets required by this field.
220
     *
221
     * @return array
222
     */
223
    public static function getAssets()
224
    {
225
        return [
226
            'css' => static::$css,
227
            'js'  => static::$js,
228
        ];
229
    }
230
231
    /**
232
     * Format the field element id.
233
     *
234
     * @param string|array $column
235
     *
236
     * @return string|array
237
     */
238
    protected function formatId($column)
239
    {
240
        return str_replace('.', '_', $column);
241
    }
242
243
    /**
244
     * Format the label value.
245
     *
246
     * @param array $arguments
247
     *
248
     * @return string
249
     */
250
    protected function formatLabel($arguments = [])
251
    {
252
        $column = is_array($this->column) ? current($this->column) : $this->column;
253
254
        $label = isset($arguments[0]) ? $arguments[0] : ucfirst($column);
255
256
        return str_replace(['.', '_'], ' ', $label);
257
    }
258
259
    /**
260
     * Format the name of the field.
261
     *
262
     * @param string $column
263
     *
264
     * @return array|mixed|string
265
     */
266
    protected function formatName($column)
267
    {
268
        if (is_string($column)) {
269
            $name = explode('.', $column);
270
271
            if (count($name) == 1) {
272
                return $name[0];
273
            }
274
275
            $html = array_shift($name);
276
            foreach ($name as $piece) {
277
                $html .= "[$piece]";
278
            }
279
280
            return $html;
281
        }
282
283
        if (is_array($this->column)) {
284
            $names = [];
285
            foreach ($this->column as $key => $name) {
286
                $names[$key] = $this->formatName($name);
287
            }
288
289
            return $names;
290
        }
291
292
        return '';
293
    }
294
295
    /**
296
     * Set form element name.
297
     *
298
     * @param string $name
299
     *
300
     * @return $this
301
     *
302
     * @author Edwin Hui
303
     */
304
    public function setElementName($name)
305
    {
306
        $this->elementName = $name;
307
308
        return $this;
309
    }
310
311
    /**
312
     * Fill data to the field.
313
     *
314
     * @param array $data
315
     *
316
     * @return void
317
     */
318 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...
319
    {
320
        // 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...
321
//        if (!is_null($this->value)) {
322
//            return;
323
//        }
324
325
        if (is_array($this->column)) {
326
            foreach ($this->column as $key => $column) {
327
                $this->value[$key] = array_get($data, $column);
328
            }
329
330
            return;
331
        }
332
333
        $this->value = array_get($data, $this->column);
334
    }
335
336
    /**
337
     * Set original value to the field.
338
     *
339
     * @param array $data
340
     *
341
     * @return void
342
     */
343 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...
344
    {
345
        if (is_array($this->column)) {
346
            foreach ($this->column as $key => $column) {
347
                $this->original[$key] = array_get($data, $column);
348
            }
349
350
            return;
351
        }
352
353
        $this->original = array_get($data, $this->column);
354
    }
355
356
    /**
357
     * @param Form $form
358
     *
359
     * @return $this
360
     */
361
    public function setForm(Form $form = null)
362
    {
363
        $this->form = $form;
364
365
        return $this;
366
    }
367
368
    /**
369
     * Set width for field and label.
370
     *
371
     * @param int $field
372
     * @param int $label
373
     *
374
     * @return $this
375
     */
376
    public function setWidth($field = 8, $label = 2)
377
    {
378
        $this->width = [
379
            'label' => $label,
380
            'field' => $field,
381
        ];
382
383
        return $this;
384
    }
385
386
    /**
387
     * Set the field options.
388
     *
389
     * @param array $options
390
     *
391
     * @return $this
392
     */
393 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...
394
    {
395
        if ($options instanceof Arrayable) {
396
            $options = $options->toArray();
397
        }
398
399
        $this->options = array_merge($this->options, $options);
400
401
        return $this;
402
    }
403
404
    /**
405
     * Get or set rules.
406
     *
407
     * @param null  $rules
408
     * @param array $messages
409
     *
410
     * @return $this
411
     */
412
    public function rules($rules = null, $messages = [])
413
    {
414
        if ($rules instanceof \Closure) {
415
            $this->rules = $rules;
416
        }
417
418
        if (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);
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
     * @param bool $enable
701
     * @return $this
702
     */
703
    public function controlLabel($enable = true)
704
    {
705
        $this->controlLabel = $enable;
706
707
        return $this;
708
    }
709
710
    /**
711
     * @return bool
712
     */
713
    public function getControlLabel()
714
    {
715
        return $this->controlLabel;
716
    }
717
718
    /**
719
     * @param bool $enable
720
     * @return $this
721
     */
722
    public function labelNoWidth($enable = false)
723
    {
724
        $this->labelNoWidth = $enable;
725
726
        return $this;
727
    }
728
729
    /**
730
     * @return bool
731
     */
732
    public function getLabelNoWidth()
733
    {
734
        return $this->labelNoWidth;
735
    }
736
737
    /**
738
     * @param null $width
739
     * @return $this
740
     */
741
    public function fieldWidth($width = null)
742
    {
743
        $this->fieldWidth = $width;
744
745
        return $this;
746
    }
747
748
    /**
749
     * @return int
750
     */
751
    public function getFieldWidth()
752
    {
753
        return $this->fieldWidth;
754
    }
755
756
    /**
757
     * Prepare for a field value before update or insert.
758
     *
759
     * @param $value
760
     *
761
     * @return mixed
762
     */
763
    public function prepare($value)
764
    {
765
        return $value;
766
    }
767
768
    /**
769
     * Format the field attributes.
770
     *
771
     * @return string
772
     */
773
    protected function formatAttributes()
774
    {
775
        $html = [];
776
777
        foreach ($this->attributes as $name => $value) {
778
            $html[] = $name.'="'.e($value).'"';
779
        }
780
781
        return implode(' ', $html);
782
    }
783
784
    /**
785
     * @return $this
786
     */
787
    public function disableHorizontal()
788
    {
789
        $this->horizontal = false;
790
791
        return $this;
792
    }
793
794
    /**
795
     * @return array
796
     */
797
    public function getViewElementClasses()
798
    {
799
        if ($this->getLabelNoWidth()) {
800
            return [
801
                'label'      => "",
802
                'field'      => "",
803
                'form-group' => 'form-group ',
804
            ];
805
        }
806
807
        if ($this->horizontal) {
808
            return [
809
                'label'      => "col-sm-{$this->width['label']}",
810
                'field'      => "col-sm-{$this->width['field']}",
811
                'form-group' => 'form-group ',
812
            ];
813
        }
814
815
        return ['label' => '', 'field' => '', 'form-group' => ''];
816
    }
817
818
    /**
819
     * Set form element class.
820
     *
821
     * @param string|array $class
822
     *
823
     * @return $this
824
     */
825
    public function setElementClass($class)
826
    {
827
        $this->elementClass = (array) $class;
828
829
        return $this;
830
    }
831
832
    /**
833
     * Get element class.
834
     *
835
     * @return array
836
     */
837
    protected function getElementClass()
838
    {
839
        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...
840
            $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...
841
842
            $this->elementClass = (array) str_replace(['[', ']'], '_', $name);
843
        }
844
845
        return $this->elementClass;
846
    }
847
848
    /**
849
     * Get element class string.
850
     *
851
     * @return mixed
852
     */
853 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...
854
    {
855
        $elementClass = $this->getElementClass();
856
857
        if (Arr::isAssoc($elementClass)) {
858
            $classes = [];
859
860
            foreach ($elementClass as $index => $class) {
861
                $classes[$index] = is_array($class) ? implode(' ', $class) : $class;
862
            }
863
864
            return $classes;
865
        }
866
867
        return implode(' ', $elementClass);
868
    }
869
870
    /**
871
     * Get element class selector.
872
     *
873
     * @return string
874
     */
875 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...
876
    {
877
        $elementClass = $this->getElementClass();
878
879
        if (Arr::isAssoc($elementClass)) {
880
            $classes = [];
881
882
            foreach ($elementClass as $index => $class) {
883
                $classes[$index] = '.'.(is_array($class) ? implode('.', $class) : $class);
884
            }
885
886
            return $classes;
887
        }
888
889
        return '.'.implode('.', $elementClass);
890
    }
891
892
    /**
893
     * Add the element class.
894
     *
895
     * @param $class
896
     *
897
     * @return $this
898
     */
899
    public function addElementClass($class)
900
    {
901
        if (is_array($class) || is_string($class)) {
902
            $this->elementClass = array_merge($this->elementClass, (array) $class);
903
904
            $this->elementClass = array_unique($this->elementClass);
905
        }
906
907
        return $this;
908
    }
909
910
    /**
911
     * Remove element class.
912
     *
913
     * @param $class
914
     *
915
     * @return $this
916
     */
917
    public function removeElementClass($class)
918
    {
919
        $delClass = [];
920
921
        if (is_string($class) || is_array($class)) {
922
            $delClass = (array) $class;
923
        }
924
925
        foreach ($delClass as $del) {
926
            if (($key = array_search($del, $this->elementClass))) {
927
                unset($this->elementClass[$key]);
928
            }
929
        }
930
931
        return $this;
932
    }
933
934
    /**
935
     * Get the view variables of this field.
936
     *
937
     * @return array
938
     */
939
    protected function variables()
940
    {
941
        return array_merge($this->variables, [
942
            'id'          => $this->id,
943
            '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...
944
            'help'        => $this->help,
945
            'class'       => $this->getElementClassString(),
946
            'value'       => $this->value(),
947
            'label'       => $this->label,
948
            'viewClass'   => $this->getViewElementClasses(),
949
            'column'      => $this->column,
950
            'errorKey'    => $this->getErrorKey(),
951
            'attributes'  => $this->formatAttributes(),
952
            'placeholder' => $this->getPlaceholder(),
953
            'controlLabel' => $this->getControlLabel(),
954
            'fieldWidth'   => $this->getFieldWidth(),
955
        ]);
956
    }
957
958
    /**
959
     * Get view of this field.
960
     *
961
     * @return string
962
     */
963
    public function getView()
964
    {
965
        if (!empty($this->view)) {
966
            return $this->view;
967
        }
968
969
        $class = explode('\\', get_called_class());
970
971
        return 'admin::form.'.strtolower(end($class));
972
    }
973
974
    /**
975
     * Get script of current field.
976
     *
977
     * @return string
978
     */
979
    public function getScript()
980
    {
981
        return $this->script;
982
    }
983
984
    /**
985
     * Render this filed.
986
     *
987
     * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
988
     */
989
    public function render()
990
    {
991
        Admin::script($this->script);
992
993
        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 993 which is incompatible with the return type declared by the interface Illuminate\Contracts\Support\Renderable::render of type string.
Loading history...
994
    }
995
996
    /**
997
     * @return string
998
     */
999
    public function __toString()
1000
    {
1001
        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...
1002
    }
1003
}
1004