Passed
Pull Request — master (#192)
by Alexander
06:02 queued 02:54
created

Select::generateInput()   B

Complexity

Conditions 10
Paths 5

Size

Total Lines 33
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 17
CRAP Score 10.1167

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 10
eloc 21
nc 5
nop 0
dl 0
loc 33
ccs 17
cts 19
cp 0.8947
crap 10.1167
rs 7.6666
c 1
b 0
f 0

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Form\Field;
6
7
use InvalidArgumentException;
8
use Stringable;
9
use Yiisoft\Form\Field\Base\AbstractInputField;
10
use Yiisoft\Html\Tag\Optgroup;
11
use Yiisoft\Html\Tag\Option;
12
use Yiisoft\Html\Tag\Select as SelectTag;
13
14
/**
15
 * A control for selecting amongst a set of options.
16
 *
17
 * @link https://html.spec.whatwg.org/multipage/form-elements.html#the-select-element
18
 */
19
final class Select extends AbstractInputField
20
{
21
    private SelectTag $select;
22
23 5
    public function __construct()
24
    {
25 5
        $this->select = SelectTag::tag();
26
    }
27
28 1
    public function items(Optgroup|Option ...$items): self
29
    {
30 1
        $new = clone $this;
31 1
        $new->select = $this->select->items(...$items);
32 1
        return $new;
33
    }
34
35 1
    public function options(Option ...$options): self
36
    {
37 1
        return $this->items(...$options);
38
    }
39
40
    /**
41
     * @param array $data Options data. The array keys are option values, and the array values are the corresponding
42
     * option labels. The array can also be nested (i.e. some array values are arrays too). For each sub-array,
43
     * an option group will be generated whose label is the key associated with the sub-array.
44
     *
45
     * Example:
46
     * ```php
47
     * [
48
     *     '1' => 'Santiago',
49
     *     '2' => 'Concepcion',
50
     *     '3' => 'Chillan',
51
     *     '4' => 'Moscow'
52
     *     '5' => 'San Petersburg',
53
     *     '6' => 'Novosibirsk',
54
     *     '7' => 'Ekaterinburg'
55
     * ];
56
     * ```
57
     *
58
     * Example with options groups:
59
     * ```php
60
     * [
61
     *     '1' => [
62
     *         '1' => 'Santiago',
63
     *         '2' => 'Concepcion',
64
     *         '3' => 'Chillan',
65
     *     ],
66
     *     '2' => [
67
     *         '4' => 'Moscow',
68
     *         '5' => 'San Petersburg',
69
     *         '6' => 'Novosibirsk',
70
     *         '7' => 'Ekaterinburg'
71
     *     ],
72
     * ];
73
     * ```
74
     * @param bool $encode Whether option content should be HTML-encoded.
75
     * @param array[] $optionsAttributes Array of option attribute sets indexed by option values from {@see $data}.
76
     * @param array[] $groupsAttributes Array of group attribute sets indexed by group labels from {@see $data}.
77
     *
78
     * @psalm-param array<array-key, string|array<array-key,string>> $data
79
     *
80
     * @return self
81
     */
82 5
    public function optionsData(
83
        array $data,
84
        bool $encode = true,
85
        array $optionsAttributes = [],
86
        array $groupsAttributes = []
87
    ): self {
88 5
        $new = clone $this;
89 5
        $new->select = $this->select->optionsData($data, $encode, $optionsAttributes, $groupsAttributes);
90 5
        return $new;
91
    }
92
93
    /**
94
     * @param bool $disabled Whether select input is disabled.
95
     *
96
     * @link https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#attr-fe-disabled
97
     */
98 1
    public function disabled(?bool $disabled = true): self
99
    {
100 1
        $new = clone $this;
101 1
        $new->inputTagAttributes['disabled'] = $disabled;
102 1
        return $new;
103
    }
104
105
    /**
106
     * @param bool $value Whether the user is to be allowed to select zero or more options.
107
     *
108
     * @link https://html.spec.whatwg.org/multipage/form-elements.html#attr-select-multiple
109
     */
110 2
    public function multiple(bool $value = true): self
111
    {
112 2
        $new = clone $this;
113 2
        $new->inputTagAttributes['multiple'] = $value;
114 2
        return $new;
115
    }
116
117
    /**
118
     * @param string|null $text Text of the option that has dummy value and is rendered as an invitation to select
119
     * a value.
120
     */
121 1
    public function prompt(?string $text): self
122
    {
123 1
        $new = clone $this;
124 1
        $new->select = $this->select->prompt($text);
125 1
        return $new;
126
    }
127
128
    /**
129
     * @param Option|null $option Option that has dummy value and is rendered as an invitation to select a value.
130
     */
131 1
    public function promptOption(?Option $option): self
132
    {
133 1
        $new = clone $this;
134 1
        $new->select = $this->select->promptOption($option);
135 1
        return $new;
136
    }
137
138
    /**
139
     * A boolean attribute. When specified, the element is required.
140
     *
141
     * @param bool $value Whether the control is required for form submission.
142
     *
143
     * @link https://html.spec.whatwg.org/multipage/form-elements.html#attr-select-required
144
     */
145 1
    public function required(bool $value = true): self
146
    {
147 1
        $new = clone $this;
148 1
        $new->inputTagAttributes['required'] = $value;
149 1
        return $new;
150
    }
151
152
    /**
153
     * The size of the control.
154
     *
155
     * @param int $value The number of options to show to the user.
156
     *
157
     * @link https://html.spec.whatwg.org/multipage/form-elements.html#attr-select-size
158
     */
159 1
    public function size(int $value): self
160
    {
161 1
        $new = clone $this;
162 1
        $new->inputTagAttributes['size'] = $value;
163 1
        return $new;
164
    }
165
166 1
    public function unselectValue(bool|float|int|string|Stringable|null $value): self
167
    {
168 1
        $new = clone $this;
169 1
        $new->select = $this->select->unselectValue($value);
170 1
        return $new;
171
    }
172
173 4
    protected function generateInput(): string
174
    {
175 4
        $value = $this->getAttributeValue();
176 4
        $multiple = (bool) ($this->inputTagAttributes['multiple'] ?? false);
177
178 4
        if ($multiple) {
179
            /** @var mixed $value */
180 1
            $value ??= [];
181 1
            if (!is_iterable($value)) {
182
                throw new InvalidArgumentException(
183
                    'Select field with multiple option requires iterable or null value.'
184
                );
185
            }
186
        } else {
187 3
            if (!is_bool($value)
188 3
                && !is_string($value)
189 3
                && !is_numeric($value)
190 3
                && $value !== null
191 3
                && (!is_object($value) || !method_exists($value, '__toString'))
192
            ) {
193
                throw new InvalidArgumentException(
194
                    'Non-multiple Select field requires a string, numeric, bool, Stringable or null value.'
195
                );
196
            }
197 3
            $value = $value === null ? [] : [$value];
198
        }
199
        /** @psalm-var iterable<int, Stringable|scalar> $value */
200
201 4
        return $this->select
202 4
            ->attributes($this->inputTagAttributes)
203 4
            ->name($this->getInputName())
204 4
            ->values($value)
205 4
            ->render();
206
    }
207
}
208