Passed
Pull Request — master (#192)
by Alexander
03:40
created

Range::generateInput()   A

Complexity

Conditions 5
Paths 3

Size

Total Lines 17
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 5.0187

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 5
eloc 10
nc 3
nop 0
dl 0
loc 17
ccs 10
cts 11
cp 0.9091
crap 5.0187
rs 9.6111
c 1
b 0
f 0
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\InputField;
10
use Yiisoft\Form\Field\Base\ValidationClass\ValidationClassInterface;
11
use Yiisoft\Form\Field\Base\ValidationClass\ValidationClassTrait;
12
use Yiisoft\Html\Html;
13
14
use function is_string;
15
16
/**
17
 * An imprecise control for setting the element’s value to a string representing a number.
18
 *
19
 * @link https://html.spec.whatwg.org/multipage/input.html#range-state-(type=range)
20
 */
21
final class Range extends InputField implements ValidationClassInterface
22
{
23
    use ValidationClassTrait;
24
25
    private bool $showOutput = false;
26
27
    /**
28
     * @psalm-var non-empty-string
29
     */
30
    private string $outputTagName = 'span';
31
    private array $outputTagAttributes = [];
32
33
    /**
34
     * Maximum value.
35
     *
36
     * @link https://html.spec.whatwg.org/multipage/input.html#attr-input-max
37
     */
38 2
    public function max(float|int|string|Stringable|null $value): self
39
    {
40 2
        $new = clone $this;
41 2
        $new->inputTagAttributes['max'] = $value;
42 2
        return $new;
43
    }
44
45
    /**
46
     * Minimum value.
47
     *
48
     * @link https://html.spec.whatwg.org/multipage/input.html#attr-input-min
49
     */
50 2
    public function min(float|int|string|Stringable|null $value): self
51
    {
52 2
        $new = clone $this;
53 2
        $new->inputTagAttributes['min'] = $value;
54 2
        return $new;
55
    }
56
57
    /**
58
     * Granularity to be matched by the form control's value.
59
     *
60
     * @link https://html.spec.whatwg.org/multipage/input.html#attr-input-step
61
     */
62
    public function step(float|int|string|Stringable|null $value): self
63
    {
64
        $new = clone $this;
65
        $new->inputTagAttributes['step'] = $value;
66
        return $new;
67
    }
68
69
    /**
70
     * ID of element that lists predefined options suggested to the user.
71
     *
72
     * @link https://html.spec.whatwg.org/multipage/input.html#the-list-attribute
73
     */
74
    public function list(?string $id): self
75
    {
76
        $new = clone $this;
77
        $new->inputTagAttributes['list'] = $id;
78
        return $new;
79
    }
80
81
    /**
82
     * @link https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#attr-fe-disabled
83
     */
84
    public function disabled(bool $disabled = true): self
85
    {
86
        $new = clone $this;
87
        $new->inputTagAttributes['disabled'] = $disabled;
88
        return $new;
89
    }
90
91
    /**
92
     * Identifies the element (or elements) that describes the object.
93
     *
94
     * @link https://w3c.github.io/aria/#aria-describedby
95
     */
96
    public function ariaDescribedBy(string $value): self
97
    {
98
        $new = clone $this;
99
        $new->inputTagAttributes['aria-describedby'] = $value;
100
        return $new;
101
    }
102
103
    /**
104
     * Defines a string value that labels the current element.
105
     *
106
     * @link https://w3c.github.io/aria/#aria-label
107
     */
108
    public function ariaLabel(string $value): self
109
    {
110
        $new = clone $this;
111
        $new->inputTagAttributes['aria-label'] = $value;
112
        return $new;
113
    }
114
115
    /**
116
     * Focus on the control (put cursor into it) when the page loads. Only one form element could be in focus
117
     * at the same time.
118
     *
119
     * @link https://html.spec.whatwg.org/multipage/interaction.html#attr-fe-autofocus
120
     */
121
    public function autofocus(bool $value = true): self
122
    {
123
        $new = clone $this;
124
        $new->inputTagAttributes['autofocus'] = $value;
125
        return $new;
126
    }
127
128
    /**
129
     * The `tabindex` attribute indicates that its element can be focused, and where it participates in sequential
130
     * keyboard navigation (usually with the Tab key, hence the name).
131
     *
132
     * It accepts an integer as a value, with different results depending on the integer's value:
133
     *
134
     * - A negative value (usually `tabindex="-1"`) means that the element is not reachable via sequential keyboard
135
     *   navigation, but could be focused with Javascript or visually. It's mostly useful to create accessible widgets
136
     *   with JavaScript.
137
     * - `tabindex="0"` means that the element should be focusable in sequential keyboard navigation, but its order is
138
     *   defined by the document's source order.
139
     * - A positive value means the element should be focusable in sequential keyboard navigation, with its order
140
     *   defined by the value of the number. That is, `tabindex="4"` is focused before `tabindex="5"`, but after
141
     *   `tabindex="3"`.
142
     *
143
     * @link https://html.spec.whatwg.org/multipage/interaction.html#attr-tabindex
144
     */
145
    public function tabIndex(?int $value): self
146
    {
147
        $new = clone $this;
148
        $new->inputTagAttributes['tabindex'] = $value;
149
        return $new;
150
    }
151
152 1
    public function showOutput(bool $show = true): self
153
    {
154 1
        $new = clone $this;
155 1
        $new->showOutput = $show;
156 1
        return $new;
157
    }
158
159
    public function outputTagName(string $tagName): self
160
    {
161
        if ($tagName === '') {
162
            throw new InvalidArgumentException('The output tag name it cannot be empty value.');
163
        }
164
165
        $new = clone $this;
166
        $new->outputTagName = $tagName;
167
        return $new;
168
    }
169
170 1
    public function outputTagAttributes(array $attributes): self
171
    {
172 1
        $new = clone $this;
173 1
        $new->outputTagAttributes = $attributes;
174 1
        return $new;
175
    }
176
177 2
    protected function generateInput(): string
178
    {
179 2
        $value = $this->getAttributeValue();
180
181 2
        if (!is_string($value) && !is_numeric($value) && $value !== null) {
182
            throw new InvalidArgumentException('Range widget requires a string, numeric or null value.');
183
        }
184
185 2
        $tag = Html::range($this->getInputName(), $value, $this->getInputTagAttributes());
186 2
        if ($this->showOutput) {
187 1
            $tag = $tag
188 1
                ->showOutput()
189 1
                ->outputTagName($this->outputTagName)
190 1
                ->outputTagAttributes($this->outputTagAttributes);
191
        }
192
193 2
        return $tag->render();
194
    }
195
196 2
    protected function prepareContainerTagAttributes(array &$attributes): void
197
    {
198 2
        if ($this->hasFormModelAndAttribute()) {
199 2
            $this->addValidationClassToTagAttributes(
200
                $attributes,
201 2
                $this->getFormModel(),
202 2
                $this->getAttributeName(),
203
            );
204
        }
205
    }
206
}
207