Passed
Push — master ( 94344c...86ce1f )
by Alexander
07:20 queued 04:31
created

Range::step()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 3
c 1
b 0
f 0
nc 1
nop 1
dl 0
loc 5
ccs 4
cts 4
cp 1
crap 1
rs 10
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\EnrichmentFromRules\EnrichmentFromRulesInterface;
10
use Yiisoft\Form\Field\Base\EnrichmentFromRules\EnrichmentFromRulesTrait;
11
use Yiisoft\Form\Field\Base\InputField;
12
use Yiisoft\Form\Field\Base\ValidationClass\ValidationClassInterface;
13
use Yiisoft\Form\Field\Base\ValidationClass\ValidationClassTrait;
14
use Yiisoft\Html\Html;
15
use Yiisoft\Validator\Rule\Number as NumberRule;
16
use Yiisoft\Validator\Rule\Required;
17
18
use function is_string;
19
20
/**
21
 * Represents `<input>` element of type "range" are let the user specify a numeric value which must be no less than
22
 * a given value, and no more than another given value.
23
 *
24
 * @link https://html.spec.whatwg.org/multipage/input.html#range-state-(type=range)
25
 * @link https://developer.mozilla.org/docs/Web/HTML/Element/input/range
26
 */
27
final class Range extends InputField implements EnrichmentFromRulesInterface, ValidationClassInterface
28
{
29
    use EnrichmentFromRulesTrait;
30
    use ValidationClassTrait;
31
32
    private bool $showOutput = false;
33
34
    /**
35
     * @psalm-var non-empty-string
36
     */
37
    private string $outputTag = 'span';
38
    private array $outputAttributes = [];
39
40
    /**
41
     * Maximum value.
42
     *
43
     * @link https://html.spec.whatwg.org/multipage/input.html#attr-input-max
44
     */
45 8
    public function max(float|int|string|Stringable|null $value): self
46
    {
47 8
        $new = clone $this;
48 8
        $new->inputAttributes['max'] = $value;
49 8
        return $new;
50
    }
51
52
    /**
53
     * Minimum value.
54
     *
55
     * @link https://html.spec.whatwg.org/multipage/input.html#attr-input-min
56
     */
57 8
    public function min(float|int|string|Stringable|null $value): self
58
    {
59 8
        $new = clone $this;
60 8
        $new->inputAttributes['min'] = $value;
61 8
        return $new;
62
    }
63
64
    /**
65
     * Granularity to be matched by the form control's value.
66
     *
67
     * @link https://html.spec.whatwg.org/multipage/input.html#attr-input-step
68
     */
69 5
    public function step(float|int|string|Stringable|null $value): self
70
    {
71 5
        $new = clone $this;
72 5
        $new->inputAttributes['step'] = $value;
73 5
        return $new;
74
    }
75
76
    /**
77
     * ID of element that lists predefined options suggested to the user.
78
     *
79
     * @link https://html.spec.whatwg.org/multipage/input.html#the-list-attribute
80
     */
81 1
    public function list(?string $id): self
82
    {
83 1
        $new = clone $this;
84 1
        $new->inputAttributes['list'] = $id;
85 1
        return $new;
86
    }
87
88
    /**
89
     * @link https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#attr-fe-disabled
90
     */
91 1
    public function disabled(bool $disabled = true): self
92
    {
93 1
        $new = clone $this;
94 1
        $new->inputAttributes['disabled'] = $disabled;
95 1
        return $new;
96
    }
97
98
    /**
99
     * Identifies the element (or elements) that describes the object.
100
     *
101
     * @link https://w3c.github.io/aria/#aria-describedby
102
     */
103 1
    public function ariaDescribedBy(?string $value): self
104
    {
105 1
        $new = clone $this;
106 1
        $new->inputAttributes['aria-describedby'] = $value;
107 1
        return $new;
108
    }
109
110
    /**
111
     * Defines a string value that labels the current element.
112
     *
113
     * @link https://w3c.github.io/aria/#aria-label
114
     */
115 1
    public function ariaLabel(?string $value): self
116
    {
117 1
        $new = clone $this;
118 1
        $new->inputAttributes['aria-label'] = $value;
119 1
        return $new;
120
    }
121
122
    /**
123
     * Focus on the control (put cursor into it) when the page loads. Only one form element could be in focus
124
     * at the same time.
125
     *
126
     * @link https://html.spec.whatwg.org/multipage/interaction.html#attr-fe-autofocus
127
     */
128 1
    public function autofocus(bool $value = true): self
129
    {
130 1
        $new = clone $this;
131 1
        $new->inputAttributes['autofocus'] = $value;
132 1
        return $new;
133
    }
134
135
    /**
136
     * The `tabindex` attribute indicates that its element can be focused, and where it participates in sequential
137
     * keyboard navigation (usually with the Tab key, hence the name).
138
     *
139
     * It accepts an integer as a value, with different results depending on the integer's value:
140
     *
141
     * - A negative value (usually `tabindex="-1"`) means that the element is not reachable via sequential keyboard
142
     *   navigation, but could be focused with Javascript or visually. It's mostly useful to create accessible widgets
143
     *   with JavaScript.
144
     * - `tabindex="0"` means that the element should be focusable in sequential keyboard navigation, but its order is
145
     *   defined by the document's source order.
146
     * - A positive value means the element should be focusable in sequential keyboard navigation, with its order
147
     *   defined by the value of the number. That is, `tabindex="4"` is focused before `tabindex="5"`, but after
148
     *   `tabindex="3"`.
149
     *
150
     * @link https://html.spec.whatwg.org/multipage/interaction.html#attr-tabindex
151
     */
152 1
    public function tabIndex(?int $value): self
153
    {
154 1
        $new = clone $this;
155 1
        $new->inputAttributes['tabindex'] = $value;
156 1
        return $new;
157
    }
158
159 4
    public function showOutput(bool $show = true): self
160
    {
161 4
        $new = clone $this;
162 4
        $new->showOutput = $show;
163 4
        return $new;
164
    }
165
166 2
    public function outputTag(string $tagName): self
167
    {
168 2
        if ($tagName === '') {
169 1
            throw new InvalidArgumentException('The output tag name it cannot be empty value.');
170
        }
171
172 1
        $new = clone $this;
173 1
        $new->outputTag = $tagName;
174 1
        return $new;
175
    }
176
177 3
    public function outputAttributes(array $attributes): self
178
    {
179 3
        $new = clone $this;
180 3
        $new->outputAttributes = $attributes;
181 3
        return $new;
182
    }
183
184 1
    public function addOutputAttributes(array $attributes): self
185
    {
186 1
        $new = clone $this;
187 1
        $new->outputAttributes = array_merge($new->outputAttributes, $attributes);
188 1
        return $new;
189
    }
190
191
    /**
192
     * @psalm-suppress MixedAssignment,MixedArgument Remove after fix https://github.com/yiisoft/validator/issues/225
193
     */
194 30
    protected function beforeRender(): void
195
    {
196 30
        parent::beforeRender();
197 30
        if ($this->enrichmentFromRules && $this->hasFormModelAndAttribute()) {
198 2
            $rules = $this->getFormModel()->getRules()[$this->getFormAttributeName()] ?? [];
199 2
            foreach ($rules as $rule) {
200 2
                if ($rule instanceof Required) {
201 1
                    $this->inputAttributes['required'] = true;
202
                }
203
204 2
                if ($rule instanceof NumberRule) {
205 1
                    if (null !== $min = $rule->getOptions()['min']) {
206 1
                        $this->inputAttributes['min'] = $min;
207
                    }
208 1
                    if (null !== $max = $rule->getOptions()['max']) {
209 1
                        $this->inputAttributes['max'] = $max;
210
                    }
211
                }
212
            }
213
        }
214
    }
215
216 30
    protected function generateInput(): string
217
    {
218 30
        $value = $this->getFormAttributeValue();
219
220 30
        if (!is_string($value) && !is_numeric($value) && $value !== null) {
221 1
            throw new InvalidArgumentException('Range field requires a string, numeric or null value.');
222
        }
223
224 29
        $tag = Html::range($this->getInputName(), $value, $this->getInputAttributes());
225 29
        if ($this->showOutput) {
226 4
            $tag = $tag
227 4
                ->showOutput()
228 4
                ->outputTag($this->outputTag)
229 4
                ->outputAttributes($this->outputAttributes);
230
        }
231
232 29
        return $tag->render();
233
    }
234
235 6
    protected function prepareContainerAttributes(array &$attributes): void
236
    {
237 6
        if ($this->hasFormModelAndAttribute()) {
238 6
            $this->addValidationClassToAttributes(
239
                $attributes,
240 6
                $this->getFormModel(),
241 6
                $this->getFormAttributeName(),
242
            );
243
        }
244
    }
245
246 29
    protected function prepareInputAttributes(array &$attributes): void
247
    {
248 29
        if ($this->hasFormModelAndAttribute()) {
249 29
            $this->addInputValidationClassToAttributes(
250
                $attributes,
251 29
                $this->getFormModel(),
252 29
                $this->getFormAttributeName(),
253
            );
254
        }
255
    }
256
}
257