Passed
Push — master ( 79bb78...087da0 )
by Alexander
02:53
created

File::beforeRender()   B

Complexity

Conditions 7
Paths 5

Size

Total Lines 12
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 7

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 7
eloc 8
c 1
b 0
f 0
nc 5
nop 0
dl 0
loc 12
ccs 9
cts 9
cp 1
crap 7
rs 8.8333
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\BeforeValidationInterface;
16
use Yiisoft\Validator\Rule\Required;
0 ignored issues
show
Bug introduced by
The type Yiisoft\Validator\Rule\Required was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

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