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

File::prepareInputAttributes()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 5
c 0
b 0
f 0
nc 2
nop 1
dl 0
loc 7
ccs 5
cts 5
cp 1
crap 2
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\Required;
16
17
/**
18
 * Represents `<input>` element of type "file" are ley the user choose one or more files from their device storage.
19
 *
20
 * @link https://html.spec.whatwg.org/multipage/input.html#file-upload-state-(type=file)
21
 * @link https://developer.mozilla.org/docs/Web/HTML/Element/input/file
22
 */
23
final class File extends InputField implements EnrichmentFromRulesInterface, ValidationClassInterface
24
{
25
    use EnrichmentFromRulesTrait;
26
    use ValidationClassTrait;
27
28
    private bool|float|int|string|Stringable|null $uncheckValue = null;
29
    private array $uncheckInputAttributes = [];
30
31
    /**
32
     * The accept attribute value is a string that defines the file types the file input should accept. This string is
33
     * a comma-separated list of unique file type specifiers. Because a given file type may be identified in more than
34
     * one manner, it's useful to provide a thorough set of type specifiers when you need files of a given format.
35
     *
36
     * @link https://html.spec.whatwg.org/multipage/input.html#attr-input-accept
37
     */
38 2
    public function accept(?string $value): self
39
    {
40 2
        $new = clone $this;
41 2
        $new->inputAttributes['accept'] = $value;
42 2
        return $new;
43
    }
44
45
    /**
46
     * @param bool $multiple Whether to allow selecting multiple files.
47
     *
48
     * @link https://html.spec.whatwg.org/multipage/input.html#attr-input-multiple
49
     */
50 2
    public function multiple(bool $multiple = true): self
51
    {
52 2
        $new = clone $this;
53 2
        $new->inputAttributes['multiple'] = $multiple;
54 2
        return $new;
55
    }
56
57
    /**
58
     * A boolean attribute. When specified, the element is required.
59
     *
60
     * @param bool $value Whether the control is required for form submission.
61
     *
62
     * @link https://html.spec.whatwg.org/multipage/input.html#attr-input-required
63
     */
64 2
    public function required(bool $value = true): self
65
    {
66 2
        $new = clone $this;
67 2
        $new->inputAttributes['required'] = $value;
68 2
        return $new;
69
    }
70
71
    /**
72
     * @param bool $disabled Whether select input is disabled.
73
     *
74
     * @link https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#attr-fe-disabled
75
     */
76 3
    public function disabled(bool $disabled = true): self
77
    {
78 3
        $new = clone $this;
79 3
        $new->inputAttributes['disabled'] = $disabled;
80 3
        return $new;
81
    }
82
83
    /**
84
     * Identifies the element (or elements) that describes the object.
85
     *
86
     * @link https://w3c.github.io/aria/#aria-describedby
87
     */
88 2
    public function ariaDescribedBy(?string $value): self
89
    {
90 2
        $new = clone $this;
91 2
        $new->inputAttributes['aria-describedby'] = $value;
92 2
        return $new;
93
    }
94
95
    /**
96
     * Defines a string value that labels the current element.
97
     *
98
     * @link https://w3c.github.io/aria/#aria-label
99
     */
100 2
    public function ariaLabel(?string $value): self
101
    {
102 2
        $new = clone $this;
103 2
        $new->inputAttributes['aria-label'] = $value;
104 2
        return $new;
105
    }
106
107
    /**
108
     * The `tabindex` attribute indicates that its element can be focused, and where it participates in sequential
109
     * keyboard navigation (usually with the Tab key, hence the name).
110
     *
111
     * It accepts an integer as a value, with different results depending on the integer's value:
112
     *
113
     * - A negative value (usually `tabindex="-1"`) means that the element is not reachable via sequential keyboard
114
     *   navigation, but could be focused with Javascript or visually. It's mostly useful to create accessible widgets
115
     *   with JavaScript.
116
     * - `tabindex="0"` means that the element should be focusable in sequential keyboard navigation, but its order is
117
     *   defined by the document's source order.
118
     * - A positive value means the element should be focusable in sequential keyboard navigation, with its order
119
     *   defined by the value of the number. That is, `tabindex="4"` is focused before `tabindex="5"`, but after
120
     *   `tabindex="3"`.
121
     *
122
     * @link https://html.spec.whatwg.org/multipage/interaction.html#attr-tabindex
123
     */
124 2
    public function tabIndex(?int $value): self
125
    {
126 2
        $new = clone $this;
127 2
        $new->inputAttributes['tabindex'] = $value;
128 2
        return $new;
129
    }
130
131
    /**
132
     * @param bool|float|int|string|Stringable|null $value Value that corresponds to "unchecked" state of the input.
133
     */
134 6
    public function uncheckValue(bool|float|int|string|Stringable|null $value): self
135
    {
136 6
        $new = clone $this;
137 6
        $new->uncheckValue = $value;
138 6
        return $new;
139
    }
140
141 2
    public function uncheckInputAttributes(array $attributes): self
142
    {
143 2
        $new = clone $this;
144 2
        $new->uncheckInputAttributes = $attributes;
145 2
        return $new;
146
    }
147
148 2
    public function addUncheckInputAttributes(array $attributes): self
149
    {
150 2
        $new = clone $this;
151 2
        $new->uncheckInputAttributes = array_merge($new->uncheckInputAttributes, $attributes);
152 2
        return $new;
153
    }
154
155
    /**
156
     * @psalm-suppress MixedAssignment,MixedArgument Remove after fix https://github.com/yiisoft/validator/issues/225
157
     */
158 16
    protected function beforeRender(): void
159
    {
160 16
        parent::beforeRender();
161 16
        if ($this->enrichmentFromRules && $this->hasFormModelAndAttribute()) {
162 1
            $rules = $this->getFormModel()->getRules()[$this->getFormAttributeName()] ?? [];
163 1
            foreach ($rules as $rule) {
164 1
                if ($rule instanceof Required) {
165 1
                    $this->inputAttributes['required'] = true;
166
                }
167
            }
168
        }
169
    }
170
171 16
    protected function generateInput(): string
172
    {
173 16
        $value = $this->getFormAttributeValue();
174
175 16
        if (!is_string($value)
176 16
            && $value !== null
177
            && (!$value instanceof Stringable)
178
        ) {
179 1
            throw new InvalidArgumentException(
180
                'File field requires a string, Stringable or null value.'
181
            );
182
        }
183
184 15
        $inputAttributes = $this->getInputAttributes();
185
186 15
        $tag = Html::file($this->getInputName(), $value, $inputAttributes);
187 15
        if ($this->uncheckValue !== null) {
188 5
            $tag = $tag->uncheckValue($this->uncheckValue);
189 5
            if (!empty($this->uncheckInputAttributes)) {
190 2
                $tag = $tag->uncheckInputAttributes($this->uncheckInputAttributes);
191
            }
192
        }
193
194 15
        return $tag->render();
195
    }
196
197 8
    protected function prepareContainerAttributes(array &$attributes): void
198
    {
199 8
        if ($this->hasFormModelAndAttribute()) {
200 8
            $this->addValidationClassToAttributes(
201
                $attributes,
202 8
                $this->getFormModel(),
203 8
                $this->getFormAttributeName(),
204
            );
205
        }
206
    }
207
208 15
    protected function prepareInputAttributes(array &$attributes): void
209
    {
210 15
        if ($this->hasFormModelAndAttribute()) {
211 15
            $this->addInputValidationClassToAttributes(
212
                $attributes,
213 15
                $this->getFormModel(),
214 15
                $this->getFormAttributeName(),
215
            );
216
        }
217
    }
218
}
219