Passed
Pull Request — master (#192)
by Alexander
05:47 queued 02:55
created

Number::tabIndex()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

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