Passed
Pull Request — master (#192)
by Sergei
03:16
created

File   A

Complexity

Total Complexity 22

Size/Duplication

Total Lines 174
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 56
dl 0
loc 174
ccs 60
cts 60
cp 1
rs 10
c 1
b 0
f 0
wmc 22

12 Methods

Rating   Name   Duplication   Size   Complexity  
A disabled() 0 5 1
A ariaDescribedBy() 0 5 1
A uncheckInputTagAttributes() 0 5 1
A accept() 0 5 1
A beforeRender() 0 8 5
A multiple() 0 5 1
A tabIndex() 0 5 1
A generateInput() 0 24 6
A uncheckValue() 0 5 1
A required() 0 5 1
A prepareContainerTagAttributes() 0 7 2
A ariaLabel() 0 5 1
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
 * The input element with a type attribute whose value is "file" represents a list of file items, each consisting of a
19
 * file name, a file type, and a file body (the contents of the file).
20
 *
21
 * @link https://html.spec.whatwg.org/multipage/input.html#file-upload-state-(type=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 $uncheckInputTagAttributes = [];
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->inputTagAttributes['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->inputTagAttributes['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->inputTagAttributes['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->inputTagAttributes['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->inputTagAttributes['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->inputTagAttributes['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->inputTagAttributes['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 5
    public function uncheckValue(bool|float|int|string|Stringable|null $value): self
135
    {
136 5
        $new = clone $this;
137 5
        $new->uncheckValue = $value;
138 5
        return $new;
139
    }
140
141 1
    public function uncheckInputTagAttributes(array $attributes): self
142
    {
143 1
        $new = clone $this;
144 1
        $new->uncheckInputTagAttributes = $attributes;
145 1
        return $new;
146
    }
147
148
    /**
149
     * @psalm-suppress MixedAssignment,MixedArgument Remove after fix https://github.com/yiisoft/validator/issues/225
150
     */
151 15
    protected function beforeRender(): void
152
    {
153 15
        parent::beforeRender();
154 15
        if ($this->enrichmentFromRules && $this->hasFormModelAndAttribute()) {
155 1
            $rules = $this->getFormModel()->getRules()[$this->getAttributeName()] ?? [];
156 1
            foreach ($rules as $rule) {
157 1
                if ($rule instanceof Required) {
158 1
                    $this->inputTagAttributes['required'] = true;
159
                }
160
            }
161
        }
162
    }
163
164 15
    protected function generateInput(): string
165
    {
166 15
        $value = $this->getAttributeValue();
167
168 15
        if (!is_string($value)
169 15
            && $value !== null
170
            && (!$value instanceof Stringable)
171
        ) {
172 1
            throw new InvalidArgumentException(
173
                'File field requires a string, Stringable or null value.'
174
            );
175
        }
176
177 14
        $tagAttributes = $this->getInputTagAttributes();
178
179 14
        $tag = Html::file($this->getInputName(), $value, $tagAttributes);
180 14
        if ($this->uncheckValue !== null) {
181 4
            $tag = $tag->uncheckValue($this->uncheckValue);
182 4
            if (!empty($this->uncheckInputTagAttributes)) {
183 1
                $tag = $tag->uncheckInputTagAttributes($this->uncheckInputTagAttributes);
184
            }
185
        }
186
187 14
        return $tag->render();
188
    }
189
190 7
    protected function prepareContainerTagAttributes(array &$attributes): void
191
    {
192 7
        if ($this->hasFormModelAndAttribute()) {
193 7
            $this->addValidationClassToTagAttributes(
194
                $attributes,
195 7
                $this->getFormModel(),
196 7
                $this->getAttributeName(),
197
            );
198
        }
199
    }
200
}
201