Completed
Pull Request — master (#2153)
by
unknown
11:07
created

Field::format()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 4
rs 10
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 963.

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

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

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

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

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

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