Passed
Pull Request — master (#162)
by Wilmer
02:57
created

FieldAttributes::addValidatorAttributeHtml()   C

Complexity

Conditions 12
Paths 49

Size

Total Lines 48
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 23
CRAP Score 12

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 12
eloc 22
nc 49
nop 4
dl 0
loc 48
ccs 23
cts 23
cp 1
crap 12
rs 6.9666
c 1
b 0
f 0

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Form\Widget\Attribute;
6
7
use InvalidArgumentException;
8
use Yiisoft\Form\FormModelInterface;
9
use Yiisoft\Form\Helper\HtmlForm;
10
use Yiisoft\Form\Helper\HtmlFormErrors;
11
use Yiisoft\Html\Html;
12
use Yiisoft\Validator\Rule\HasLength;
13
use Yiisoft\Validator\Rule\MatchRegularExpression;
14
use Yiisoft\Validator\Rule\Number;
15
use Yiisoft\Validator\Rule\Required;
16
use Yiisoft\Validator\Rule\Url;
17
18
trait FieldAttributes
19
{
20
    private bool $ariaDescribedBy = false;
21
    private string $attribute = '';
22
    private array $attributes = [];
23
    private string $containerClass = '';
24
    private string $errorClass = '';
25
    private string $errorMessage = '';
26
    private string $hintClass = '';
27
    private string $id = '';
28
    private string $inputClass = '';
29
    private string $labelClass = '';
30
    private string $invalidClass = '';
31
    private string $validClass = '';
32
    private array $parts = [];
33
    private string $template = "{label}\n{input}\n{hint}\n{error}";
34
    private string $validationStateOn = 'input';
35
    private ?FormModelInterface $formModel = null;
36
37
    /**
38
     * Set aria-describedby attribute.
39
     *
40
     * @return static
41
     *
42
     * @link https://www.w3.org/TR/WCAG20-TECHS/ARIA1.html
43
     */
44 2
    public function ariaDescribedBy(): self
45
    {
46 2
        $new = clone $this;
47 2
        $new->ariaDescribedBy = true;
48 2
        return $new;
49
    }
50
51
    /**
52
     * Set form interface, attribute name and attributes, and attributes for the widget.
53
     *
54
     * @param FormModelInterface $formModel Form.
55
     * @param string $attribute Form model property this widget is rendered for.
56
     * @param array $attributes The HTML attributes for the widget container tag.
57
     *
58
     * @return static
59
     *
60
     * {@see \Yiisoft\Html\Html::renderTagAttributes()} for details on how attributes are being rendered.
61
     */
62 174
    public function config(FormModelInterface $formModel, string $attribute, array $attributes = []): self
63
    {
64 174
        $new = clone $this;
65 174
        $new->formModel = $formModel;
66 174
        $new->attribute = $attribute;
67 174
        $new->attributes = $attributes;
68 174
        return $new;
69
    }
70
71
    /**
72
     * Set container css class.
73
     *
74
     * @return static
75
     */
76 2
    public function containerClass(string $value): self
77
    {
78 2
        $new = clone $this;
79 2
        $new->containerClass = $value;
80 2
        return $new;
81
    }
82
83
    /**
84
     * Set error css class.
85
     *
86
     * @return static
87
     */
88 9
    public function errorClass(string $value): self
89
    {
90 9
        $new = clone $this;
91 9
        $new->errorClass = $value;
92 9
        return $new;
93
    }
94
95
    /**
96
     * Set hint css class.
97
     *
98
     * @return static
99
     */
100 9
    public function hintClass(string $value): self
101
    {
102 9
        $new = clone $this;
103 9
        $new->hintClass = $value;
104 9
        return $new;
105
    }
106
107
    /**
108
     * Set input css class.
109
     *
110
     * @return static
111
     */
112 2
    public function inputClass(string $value): self
113
    {
114 2
        $new = clone $this;
115 2
        $new->inputClass = $value;
116 2
        return $new;
117
    }
118
119
    /**
120
     * Set invalid css class.
121
     *
122
     * @return static
123
     */
124 9
    public function invalidClass(string $value): self
125
    {
126 9
        $new = clone $this;
127 9
        $new->invalidClass = $value;
128 9
        return $new;
129
    }
130
131
    /**
132
     * Set the label css class.
133
     *
134
     * @return static
135
     */
136 2
    public function labelClass(string $value): self
137
    {
138 2
        $new = clone $this;
139 2
        $new->labelClass = $value;
140 2
        return $new;
141
    }
142
143
    /**
144
     * Set layout template for render a field.
145
     *
146
     * @param string $value
147
     *
148
     * @return static
149
     */
150 2
    public function template(string $value): self
151
    {
152 2
        $new = clone $this;
153 2
        $new->template = $value;
154 2
        return $new;
155
    }
156
157
    /**
158
     * Set the value valid css class.
159
     *
160
     * @param string $value is the valid css class.
161
     *
162
     * @return static
163
     */
164 9
    public function validClass(string $value): self
165
    {
166 9
        $new = clone $this;
167 9
        $new->validClass = $value;
168 9
        return $new;
169
    }
170
171 174
    protected function getFormModel(): FormModelInterface
172
    {
173 174
        if ($this->formModel === null) {
174 1
            throw new InvalidArgumentException('Form model is not set.');
175
        }
176
177 173
        return $this->formModel;
178
    }
179
180 173
    private function addValidatorAttributeHtml(
181
        FormModelInterface $formModel,
182
        string $attribute,
183
        array $attributes,
184
        string $type
185
    ): array {
186
        /** @var array */
187 173
        $rules = $formModel->getRules()[$attribute] ?? [];
188
189
        /** @var object $rule */
190 173
        foreach ($rules as $rule) {
191 20
            if ($rule instanceof Required) {
192 14
                $attributes['required'] = true;
193
            }
194 20
            if ($rule instanceof HasLength && in_array($type, self::HAS_LENGTH_TYPES, true)) {
195
                /** @var string */
196 11
                $attributes['maxlength'] = $rule->getOptions()['max'];
197
                /** @var string */
198 11
                $attributes['minlength'] = $rule->getOptions()['min'];
199
            }
200 20
            if ($rule instanceof MatchRegularExpression && in_array($type, self::MATCH_REGULAR_EXPRESSION_TYPES, true)) {
201
                /** @var string */
202 5
                $pattern = $rule->getOptions()['pattern'];
203 5
                $attributes['pattern'] = Html::normalizeRegexpPattern($pattern);
204
            }
205 20
            if ($rule instanceof Number && $type === self::TYPE_NUMBER) {
206
                /** @var string */
207 2
                $attributes['max'] = $rule->getOptions()['max'];
208
                /** @var string */
209 2
                $attributes['min'] = $rule->getOptions()['min'];
210
            }
211 20
            if ($rule instanceof Url && $type === self::TYPE_URL) {
212
                /** @var array<array-key, string> */
213 1
                $validSchemes = $rule->getOptions()['validSchemes'];
214
215 1
                $schemes = [];
216 1
                foreach ($validSchemes as $scheme) {
217 1
                    $schemes[] = $this->getSchemePattern($scheme);
218
                }
219
220
                /** @var array<array-key, float|int|string>|string */
221 1
                $pattern = $rule->getOptions()['pattern'];
222 1
                $normalizePattern = str_replace('{schemes}', '(' . implode('|', $schemes) . ')', $pattern);
223 1
                $attributes['pattern'] = Html::normalizeRegexpPattern($normalizePattern);
224
            }
225
        }
226
227 173
        return $attributes;
228
    }
229
230 1
    private function getSchemePattern(string $scheme): string
231
    {
232 1
        $result = '';
233 1
        for ($i = 0, $length = mb_strlen($scheme); $i < $length; $i++) {
234 1
            $result .= '[' . mb_strtolower($scheme[$i]) . mb_strtoupper($scheme[$i]) . ']';
235
        }
236 1
        return $result;
237
    }
238
239
    /**
240
     * Return the input id.
241
     *
242
     * @return string
243
     */
244 1
    private function getId(): string
245
    {
246
        /** @var string */
247 1
        $id = $this->attributes['id'] ?? $this->id;
248
249 1
        return $id === '' ? HtmlForm::getInputId($this->getFormModel(), $this->attribute) : $id;
250
    }
251
252 173
    private function setInputAttributes(array $attributes): array
253
    {
254 173
        $new = clone $this;
255 173
        $placeHolder = '';
256
        /** @var string */
257 173
        $type = $attributes['type'] ?? '';
258 173
        unset($attributes['type']);
259 173
        $attributes = $new->addValidatorAttributeHtml($new->getFormModel(), $new->attribute, $attributes, $type);
260 173
        $attributeName = HtmlForm::getAttributeName($new->getFormModel(), $new->attribute);
261
262 173
        if ($new->ariaDescribedBy === true) {
263 1
            $attributes['aria-describedby'] = $new->getId();
264
        }
265
266 173
        if ($new->inputClass !== '') {
267 1
            Html::addCssClass($attributes, $new->inputClass);
268
        }
269
270 173
        if ($new->errorClass !== '' && HtmlFormErrors::hasErrors($new->getFormModel(), $attributeName)) {
271 8
            Html::addCssClass($attributes, $new->invalidClass);
272 173
        } elseif ($new->validClass !== '' && $new->getFormModel()->isValidated()) {
273 8
            Html::addCssClass($attributes, $new->validClass);
274
        }
275
276 173
        if (!in_array($type, self::NO_PLACEHOLDER_TYPES, true)) {
277 143
            $placeHolder = $new->getFormModel()->getAttributePlaceholder($new->attribute);
278
        }
279
280 173
        if (!isset($attributes['placeholder']) && $placeHolder !== '') {
281 59
            $attributes['placeholder'] = $placeHolder;
282
        }
283
284 173
        return $attributes;
285
    }
286
}
287