Passed
Pull Request — master (#160)
by Wilmer
03:04
created

Field   D

Complexity

Total Complexity 58

Size/Duplication

Total Lines 718
Duplicated Lines 0 %

Test Coverage

Coverage 99.54%

Importance

Changes 2
Bugs 1 Features 0
Metric Value
eloc 192
dl 0
loc 718
ccs 215
cts 216
cp 0.9954
rs 4.5599
c 2
b 1
f 0
wmc 58

28 Methods

Rating   Name   Duplication   Size   Complexity  
A hidden() 0 9 1
B run() 0 29 7
A file() 0 6 1
A range() 0 6 1
A checkbox() 0 14 2
B buildField() 0 40 10
A url() 0 6 1
A email() 0 6 1
A dateTimeLocal() 0 6 1
A renderHint() 0 20 3
A date() 0 6 1
A telephone() 0 6 1
A renderButtons() 0 19 4
A checkboxList() 0 6 1
A image() 0 9 1
A renderInputWidget() 0 23 6
A radio() 0 14 2
A select() 0 6 1
A text() 0 6 1
A dateTime() 0 6 1
A renderLabel() 0 24 3
A textArea() 0 6 1
A password() 0 6 1
A renderError() 0 17 2
A resetButton() 0 6 1
A radioList() 0 6 1
A number() 0 6 1
A submitButton() 0 6 1

How to fix   Complexity   

Complex Class

Complex classes like Field often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Field, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Form\Widget;
6
7
use Yiisoft\Arrays\ArrayHelper;
8
use Yiisoft\Definitions\Exception\CircularReferenceException;
9
use Yiisoft\Definitions\Exception\InvalidConfigException;
10
use Yiisoft\Definitions\Exception\NotInstantiableException;
11
use Yiisoft\Factory\NotFoundException;
12
use Yiisoft\Form\FormModelInterface;
13
use Yiisoft\Form\Widget\Attribute\ButtonAttributes;
14
use Yiisoft\Form\Widget\Attribute\FieldAttributes;
15
use Yiisoft\Form\Widget\Attribute\InputAttributes;
16
use Yiisoft\Form\Widget\Attribute\GlobalAttributes;
17
use Yiisoft\Form\Widget\Attribute\PlaceholderInterface;
18
use Yiisoft\Form\Widget\Attribute\WidgetAttributes;
19
use Yiisoft\Form\Widget\FieldPart\Error;
20
use Yiisoft\Form\Widget\FieldPart\Hint;
21
use Yiisoft\Form\Widget\FieldPart\Label;
22
use Yiisoft\Html\Html;
23
use Yiisoft\Html\Tag\Div;
24
25
use function strtr;
26
27
/**
28
 * Renders the field widget along with label and hint tag (if any) according to template.
29
 *
30
 * @psalm-suppress MissingConstructor
31
 */
32
final class Field extends FieldAttributes
33
{
34
    /** @psalm-var ButtonAttributes[] */
35
    private array $buttons = [];
36
    protected array $parts = [];
37
    private WidgetAttributes $inputWidget;
38
    private GlobalAttributes $widget;
39
40
    /**
41
     * Renders a checkbox.
42
     *
43
     * This method will generate the `checked` tag attribute according to the model attribute value.
44
     *
45
     * @param FormModelInterface $formModel The model object.
46
     * @param string $attribute The attribute name or expression.
47
     * @param array $config The configuration array for widget factory.
48
     * Available methods:
49
     * [
50
     *     'enclosedByLabel()' => [false],
51
     *     'label()' => ['test-text-label'],
52
     *     'labelAttributes()' => [['class' => 'test-class']],
53
     *     'uncheckValue()' => ['0'],
54
     * ]
55
     *
56
     * @throws CircularReferenceException|InvalidConfigException|NotFoundException|NotInstantiableException
57
     *
58
     * @return static the field widget instance.
59
     */
60 20
    public function checkbox(FormModelInterface $formModel, string $attribute, array $config = []): self
61
    {
62 20
        $new = clone $this;
63 20
        $new = $new->type('checkbox');
64
65
        /** @var array */
66 20
        $enclosedByLabel = $config['enclosedByLabel()'] ?? [true];
67
68 20
        if ($enclosedByLabel === [true]) {
69 19
            $new->parts['{label}'] = '';
70
        }
71
72 20
        $new->inputWidget = Checkbox::widget($config)->for($formModel, $attribute);
0 ignored issues
show
Bug introduced by
The method for() does not exist on Yiisoft\Widget\Widget. It seems like you code against a sub-type of Yiisoft\Widget\Widget such as Yiisoft\Form\Widget\FieldPart\Hint or Yiisoft\Form\Widget\FieldPart\Label or Yiisoft\Form\Widget\FieldPart\Error or Yiisoft\Form\Widget\Attribute\WidgetAttributes. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

72
        $new->inputWidget = Checkbox::widget($config)->/** @scrutinizer ignore-call */ for($formModel, $attribute);
Loading history...
73 20
        return $new;
74
    }
75
76
    /**
77
     * Renders a list of checkboxes.
78
     *
79
     * A checkbox list allows multiple selection, As a result, the corresponding submitted value is an array.
80
     *
81
     * The selection of the checkbox list is taken from the value of the model attribute.
82
     *
83
     * @param FormModelInterface $formModel The model object.
84
     * @param string $attribute The attribute name or expression.
85
     * @param array $config the configuration array for widget factory.
86
     * Available methods:
87
     * [
88
     *     'containerAttributes()' => [['class' => 'test-class']],
89
     *     'containerTag()' => ['span'],
90
     *     'individualItemsAttributes()' => [[1 => ['disabled' => true], 2 => ['class' => 'test-class']],
91
     *     'items()' => [[1 => 'Female', 2 => 'Male']],
92
     *     'itemsAttributes()' => [['disabled' => true],
93
     *     'itemsFormatter()' => [
94
     *         static function (CheckboxItem $item) {
95
     *             return $item->checked
96
     *                 ? "<label><input type='checkbox' name='$item->name' value='$item->value' checked> $item->label</label>"
97
     *                 : "<label><input type='checkbox' name='$item->name' value='$item->value'> $item->label</label>";
98
     *         },
99
     *     ],
100
     *     'itemsFromValues()' => [[1 => 'Female', 2 => 'Male']],
101
     *     'separator()' => ['&#9866;'],
102
     * ]
103
     *
104
     * @throws CircularReferenceException|InvalidConfigException|NotFoundException|NotInstantiableException
105
     *
106
     * @return static the field widget instance.
107
     */
108 19
    public function checkboxList(FormModelInterface $formModel, string $attribute, array $config = []): self
109
    {
110 19
        $new = clone $this;
111 19
        $new = $new->type('checkboxList');
112 19
        $new->inputWidget = CheckboxList::widget($config)->for($formModel, $attribute);
113 19
        return $new;
114
    }
115
116
    /**
117
     * Renders a date widget.
118
     *
119
     * @param FormModelInterface $formModel The model object.
120
     * @param string $attribute The attribute name or expression.
121
     * @param array $config the configuration array for widget factory.
122
     *
123
     * @throws CircularReferenceException|InvalidConfigException|NotFoundException|NotInstantiableException
124
     *
125
     * @return static the field widget instance.
126
     */
127 15
    public function date(FormModelInterface $formModel, string $attribute, array $config = []): self
128
    {
129 15
        $new = clone $this;
130 15
        $new = $new->type('date');
131 15
        $new->inputWidget = Date::widget($config)->for($formModel, $attribute);
132 15
        return $new;
133
    }
134
135
    /**
136
     * Renders a date time widget.
137
     *
138
     * @param FormModelInterface $formModel The model object.
139
     * @param string $attribute The attribute name or expression.
140
     * @param array $config the configuration array for widget factory.
141
     *
142
     * @throws CircularReferenceException|InvalidConfigException|NotFoundException|NotInstantiableException
143
     *
144
     * @return static the field widget instance.
145
     */
146 16
    public function dateTime(FormModelInterface $formModel, string $attribute, array $config = []): self
147
    {
148 16
        $new = clone $this;
149 16
        $new = $new->type('dateTime');
150 16
        $new->inputWidget = DateTime::widget($config)->for($formModel, $attribute);
151 16
        return $new;
152
    }
153
154
    /**
155
     * Renders a date time local widget.
156
     *
157
     * @param FormModelInterface $formModel The model object.
158
     * @param string $attribute The attribute name or expression.
159
     * @param array $config the configuration array for widget factory.
160
     *
161
     * @throws CircularReferenceException|InvalidConfigException|NotFoundException|NotInstantiableException
162
     *
163
     * @return static the field widget instance.
164
     */
165 16
    public function dateTimeLocal(FormModelInterface $formModel, string $attribute, array $config = []): self
166
    {
167 16
        $new = clone $this;
168 16
        $new = $new->type('dateTimeLocal');
169 16
        $new->inputWidget = DateTimeLocal::widget($config)->for($formModel, $attribute);
170 16
        return $new;
171
    }
172
173
    /**
174
     * Renders a email widget.
175
     *
176
     * @param FormModelInterface $formModel The model object.
177
     * @param string $attribute The attribute name or expression.
178
     * @param array $config the configuration array for widget factory.
179
     *
180
     * @throws CircularReferenceException|InvalidConfigException|NotFoundException|NotInstantiableException
181
     *
182
     * @return static the field widget instance.
183
     */
184 23
    public function email(FormModelInterface $formModel, string $attribute, array $config = []): self
185
    {
186 23
        $new = clone $this;
187 23
        $new = $new->type('email');
188 23
        $new->inputWidget = Email::widget($config)->for($formModel, $attribute);
189 23
        return $new;
190
    }
191
192
    /**
193
     * Renders a file widget.
194
     *
195
     * @param FormModelInterface $formModel The model object.
196
     * @param string $attribute The attribute name or expression.
197
     * @param array $config the configuration array for widget factory.
198
     * Available methods:
199
     * [
200
     *     'hiddenAttributes()' => [['id' => 'test-id']],
201
     *     'uncheckValue()' => ['0'],
202
     *
203
     * ]
204
     *
205
     * @throws CircularReferenceException|InvalidConfigException|NotFoundException|NotInstantiableException
206
     *
207
     * @return static the field widget instance.
208
     */
209 14
    public function file(FormModelInterface $formModel, string $attribute, array $config = []): self
210
    {
211 14
        $new = clone $this;
212 14
        $new = $new->type('file');
213 14
        $new->inputWidget = File::widget($config)->for($formModel, $attribute);
214 14
        return $new;
215
    }
216
217
    /**
218
     * Renders a hidden widget.
219
     *
220
     * @param FormModelInterface $formModel The model object.
221
     * @param string $attribute The attribute name or expression.
222
     * @param array $config the configuration array for widget factory.
223
     *
224
     * @throws CircularReferenceException|InvalidConfigException|NotFoundException|NotInstantiableException
225
     *
226
     * @return static the field widget instance.
227
     */
228 2
    public function hidden(FormModelInterface $formModel, string $attribute, array $config = []): self
229
    {
230 2
        $new = clone $this;
231 2
        $new = $new->type('hidden');
232 2
        $new->parts['{label}'] = '';
233 2
        $new->parts['{hint}'] = '';
234 2
        $new->parts['{error}'] = '';
235 2
        $new->inputWidget = Hidden::widget($config)->for($formModel, $attribute);
236 2
        return $new;
237
    }
238
239
    /**
240
     * Renders an image widget.
241
     *
242
     * @param array $config the configuration array for widget factory.
243
     * @param array $attributes the HTML attributes for the widget.
244
     * Most used attributes:
245
     * [
246
     *     'alt' => 'test-alt',
247
     *     'height' => '100%',
248
     *     'src' => 'test-src',
249
     *     'width' => '100%',
250
     * ]
251
     *
252
     * @throws CircularReferenceException|InvalidConfigException|NotFoundException|NotInstantiableException
253
     *
254
     * @return static the field object itself.
255
     */
256 12
    public function image(array $config = [], array $attributes = []): self
257
    {
258 12
        $new = clone $this;
259 12
        $new = $new->type('image');
260 12
        $new->parts['{label}'] = '';
261 12
        $new->parts['{hint}'] = '';
262 12
        $new->parts['{error}'] = '';
263 12
        $new->widget = Image::widget($config)->attributes($attributes);
264 12
        return $new;
265
    }
266
267
    /**
268
     * Renders a number widget.
269
     *
270
     * @param FormModelInterface $formModel The model object.
271
     * @param string $attribute The attribute name or expression.
272
     * @param array $config the configuration array for widget factory.
273
     *
274
     * @throws CircularReferenceException|InvalidConfigException|NotFoundException|NotInstantiableException
275
     *
276
     * @return static the field object itself.
277
     */
278 18
    public function number(FormModelInterface $formModel, string $attribute, array $config = []): self
279
    {
280 18
        $new = clone $this;
281 18
        $new = $new->type('number');
282 18
        $new->inputWidget = Number::widget($config)->for($formModel, $attribute);
283 18
        return $new;
284
    }
285
286
    /**
287
     * Renders a password widget.
288
     *
289
     * @param FormModelInterface $formModel The model object.
290
     * @param string $attribute The attribute name or expression.
291
     * @param array $config the configuration array for widget factory.
292
     *
293
     * @throws CircularReferenceException|InvalidConfigException|NotFoundException|NotInstantiableException
294
     *
295
     * @return static the field object itself.
296
     */
297 21
    public function password(FormModelInterface $formModel, string $attribute, array $config = []): self
298
    {
299 21
        $new = clone $this;
300 21
        $new = $new->type('password');
301 21
        $new->inputWidget = Password::widget($config)->for($formModel, $attribute);
302 21
        return $new;
303
    }
304
305
    /**
306
     * Renders a radio widget.
307
     *
308
     * @param FormModelInterface $formModel The model object.
309
     * @param string $attribute The attribute name or expression.
310
     * @param array $config the configuration array for widget factory.
311
     * Available methods:
312
     * [
313
     *     'enclosedByLabel()' => [false],
314
     *     'label()' => ['Email:'],
315
     *     'labelAttributes()' => [['class' => 'test-class']]
316
     *     'uncheckValue()' => ['0'],
317
     * ]
318
     *
319
     * @throws CircularReferenceException|InvalidConfigException|NotFoundException|NotInstantiableException
320
     *
321
     * @return static the field object itself.
322
     */
323 21
    public function radio(FormModelInterface $formModel, string $attribute, array $config = []): self
324
    {
325 21
        $new = clone $this;
326 21
        $new = $new->type('radio');
327
328
        /** @var array */
329 21
        $enclosedByLabel = $config['enclosedByLabel()'] ?? [true];
330
331 21
        if ($enclosedByLabel === [true]) {
332 20
            $new->parts['{label}'] = '';
333
        }
334
335 21
        $new->inputWidget = Radio::widget($config)->for($formModel, $attribute);
336 21
        return $new;
337
    }
338
339
    /**
340
     * Renders a radio list widget.
341
     *
342
     * @param FormModelInterface $formModel The model object.
343
     * @param string $attribute The attribute name or expression.
344
     * @param array $config the configuration array for widget factory.
345
     * Available methods:
346
     * [
347
     *     'containerAttributes()' => [['class' => 'test-class']],
348
     *     'containerTag()' => ['span'],
349
     *     'items()' => [[1 => 'Female', 2 => 'Male']],
350
     *     'itemsAttributes()' => [['class' => 'test-class']],
351
     *     'individualItemsAttributes()' => [[1 => ['disabled' => true], 2 => ['class' => 'test-class']]],
352
     *     'itemsFormatter()' => [
353
     *         static function (RadioItem $item) {
354
     *             return $item->checked
355
     *                 ? "<label><input type='checkbox' name='$item->name' value='$item->value' checked> $item->label</label>"
356
     *                 : "<label><input type='checkbox' name='$item->name' value='$item->value'> $item->label</label>";
357
     *         },
358
     *     ],
359
     *     'itemsFromValues()' => [[1 => 'Female', 2 => 'Male']],
360
     *     'separator()' => [PHP_EOL],
361
     *     'uncheckValue()' => ['0'],
362
     * ]
363
     *
364
     * @throws CircularReferenceException|InvalidConfigException|NotFoundException|NotInstantiableException
365
     *
366
     * @return static the field object itself.
367
     */
368 20
    public function radioList(FormModelInterface $formModel, string $attribute, array $config = []): self
369
    {
370 20
        $new = clone $this;
371 20
        $new = $new->type('radioList');
372 20
        $new->inputWidget = RadioList::widget($config)->for($formModel, $attribute);
373 20
        return $new;
374
    }
375
376
    /**
377
     * Renders a range widget.
378
     *
379
     * @param FormModelInterface $formModel The model object.
380
     * @param string $attribute The attribute name or expression.
381
     * @param array $config the configuration array for widget factory.
382
     * Available methods:
383
     * [
384
     *     'outputTag()' => ['p'],
385
     *     'outputAttributes()' => [['class' => 'test-class']],
386
     * ]
387
     *
388
     * @throws CircularReferenceException|InvalidConfigException|NotFoundException|NotInstantiableException
389
     *
390
     * @return static the field object itself.
391
     */
392 19
    public function range(FormModelInterface $formModel, string $attribute, array $config = []): self
393
    {
394 19
        $new = clone $this;
395 19
        $new = $new->type('range');
396 19
        $new->inputWidget = Range::widget($config)->for($formModel, $attribute);
397 19
        return $new;
398
    }
399
400
    /**
401
     * Renders a reset button widget.
402
     *
403
     * @param array $config the configuration array for widget factory.
404
     * @param array $attributes the HTML attributes for the widget.
405
     *
406
     * @throws CircularReferenceException|InvalidConfigException|NotFoundException|NotInstantiableException
407
     *
408
     * @return static the field object itself.
409
     */
410 17
    public function resetButton(array $config = [], array $attributes = []): self
411
    {
412 17
        $new = clone $this;
413 17
        $new = $new->type('buttons');
414 17
        $new->buttons[] = ResetButton::widget($config)->attributes($attributes);
415 17
        return $new;
416
    }
417
418
    /**
419
     * Renders a select widget.
420
     *
421
     * @param FormModelInterface $formModel The model object.
422
     * @param string $attribute The attribute name or expression.
423
     * @param array $config The configuration array for widget factory.
424
     * Available methods:
425
     * [
426
     *     'encode()' => [true],
427
     *     'groups()' => [['1' => ['2' => 'Moscu', '3' => 'San Petersburg']]],
428
     *     'items()' => [['1' => 'Moscu', '2' => 'San Petersburg']],
429
     *     'itemsAttributes()' => [['2' => ['disabled' => true]],
430
     *     'optionsData()' => [['1' => '<b>Moscu</b>', '2' => 'San Petersburg']],
431
     *     'prompt()' => [['text' => 'Select City Birth', 'attributes' => ['value' => '0', 'selected' => 'selected']]],
432
     *     'unselectValue()' => ['0'],
433
     * ]
434
     *
435
     * @throws CircularReferenceException|InvalidConfigException|NotFoundException|NotInstantiableException
436
     *
437
     * @return static the field object itself.
438
     */
439 21
    public function select(FormModelInterface $formModel, string $attribute, array $config = []): self
440
    {
441 21
        $new = clone $this;
442 21
        $new = $new->type('select');
443 21
        $new->inputWidget = Select::widget($config)->for($formModel, $attribute);
444 21
        return $new;
445
    }
446
447
    /**
448
     * Renders a submit button widget.
449
     *
450
     * @param array $config the configuration array for widget factory.
451
     * @param array $attributes the HTML attributes for the widget.
452
     *
453
     * @throws CircularReferenceException|InvalidConfigException|NotFoundException|NotInstantiableException
454
     *
455
     * @return static the field object itself.
456
     */
457 25
    public function submitButton(array $config = [], array $attributes = []): self
458
    {
459 25
        $new = clone $this;
460 25
        $new = $new->type('buttons');
461 25
        $new->buttons[] = SubmitButton::widget($config)->attributes($attributes);
462 25
        return $new;
463
    }
464
465
    /**
466
     * Renders a text widget.
467
     *
468
     * @param FormModelInterface $formModel The model object.
469
     * @param string $attribute The attribute name or expression.
470
     * @param array $config the configuration array for widget factory.
471
     *
472
     * @throws CircularReferenceException|InvalidConfigException|NotFoundException|NotInstantiableException
473
     *
474
     * @return static the field widget instance.
475
     */
476 21
    public function telephone(FormModelInterface $formModel, string $attribute, array $config = []): self
477
    {
478 21
        $new = clone $this;
479 21
        $new = $new->type('telephone');
480 21
        $new->inputWidget = Telephone::widget($config)->for($formModel, $attribute);
481 21
        return $new;
482
    }
483
484
    /**
485
     * Renders a text widget.
486
     *
487
     * @param FormModelInterface $formModel The model object.
488
     * @param string $attribute The attribute name or expression.
489
     * @param array $config the configuration array for widget factory.
490
     *
491
     * @throws CircularReferenceException|InvalidConfigException|NotFoundException|NotInstantiableException
492
     *
493
     * @return static the field widget instance.
494
     */
495 59
    public function text(FormModelInterface $formModel, string $attribute, array $config = []): self
496
    {
497 59
        $new = clone $this;
498 59
        $new = $new->type('text');
499 59
        $new->inputWidget = Text::widget($config)->for($formModel, $attribute);
500 58
        return $new;
501
    }
502
503
    /**
504
     * Renders a text area widget.
505
     *
506
     * @param FormModelInterface $formModel The model object.
507
     * @param string $attribute The attribute name or expression.
508
     * @param array $config the configuration array for widget factory.
509
     *
510
     * @throws CircularReferenceException|InvalidConfigException|NotFoundException|NotInstantiableException
511
     *
512
     * @return static the field widget instance.
513
     */
514 24
    public function textArea(FormModelInterface $formModel, string $attribute, array $config = []): self
515
    {
516 24
        $new = clone $this;
517 24
        $new = $new->type('textArea');
518 24
        $new->inputWidget = TextArea::widget($config)->for($formModel, $attribute);
519 22
        return $new;
520
    }
521
522
    /**
523
     * Renders a url widget.
524
     *
525
     * @param FormModelInterface $formModel The model object.
526
     * @param string $attribute The attribute name or expression.
527
     * @param array $config the configuration array for widget factory.
528
     *
529
     * @throws CircularReferenceException|InvalidConfigException|NotFoundException|NotInstantiableException
530
     *
531
     * @return static the field widget instance.
532
     */
533 23
    public function url(FormModelInterface $formModel, string $attribute, array $config = []): self
534
    {
535 23
        $new = clone $this;
536 23
        $new = $new->type('url');
537 23
        $new->inputWidget = Url::widget($config)->for($formModel, $attribute);
538 23
        return $new;
539
    }
540
541
    /**
542
     * Renders the whole field.
543
     *
544
     * This method will generate the label, input tag and hint tag (if any), and assemble them into HTML according to
545
     * {@see template}.
546
     *
547
     * If (not set), the default methods will be called to generate the label and input tag, and use them as the
548
     * content.
549
     *
550
     * @throws CircularReferenceException|InvalidConfigException|NotFoundException|NotInstantiableException
551
     *
552
     * @return string the rendering result.
553
     */
554 415
    protected function run(): string
555
    {
556 415
        $content = '';
557
558 415
        $div = Div::tag();
559
560 415
        if (!empty($this->inputWidget)) {
561 369
            $content .= $this->renderInputWidget();
562
        }
563
564 397
        if (!empty($this->widget)) {
565 12
            $content .= $this->widget->attributes($this->getAttributes())->render();
566
        }
567
568 397
        $renderButtons = $this->renderButtons();
569
570 397
        if ($renderButtons !== '') {
571 34
            $content .= $renderButtons;
572
        }
573
574 397
        if ($this->getContainerClass() !== '') {
575 4
            $div = $div->class($this->getContainerClass());
576
        }
577
578 397
        if ($this->getContainerAttributes() !== []) {
579 8
            $div = $div->attributes($this->getContainerAttributes());
580
        }
581
582 397
        return $this->getContainer() ? $div->content(PHP_EOL . $content . PHP_EOL)->encode(false)->render() : $content;
583
    }
584
585 369
    private function buildField(): self
586
    {
587 369
        $new = clone $this;
588
589
        // Set ariadescribedby.
590 369
        if ($new->getAriaDescribedBy() === true && $new->inputWidget instanceof InputAttributes) {
591 1
            $new->inputWidget = $new->inputWidget->ariaDescribedBy($this->inputWidget->getInputId() . '-help');
0 ignored issues
show
Bug introduced by
The method ariaDescribedBy() does not exist on Yiisoft\Form\Widget\Attribute\WidgetAttributes. It seems like you code against a sub-type of Yiisoft\Form\Widget\Attribute\WidgetAttributes such as Yiisoft\Form\Widget\Attribute\InputAttributes or Yiisoft\Form\Widget\Attribute\FieldAttributes. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

591
            /** @scrutinizer ignore-call */ 
592
            $new->inputWidget = $new->inputWidget->ariaDescribedBy($this->inputWidget->getInputId() . '-help');
Loading history...
592
        }
593
594
        // Set encode.
595 369
        $new->inputWidget = $new->inputWidget->encode($new->getEncode());
596
597
        // Set input class.
598 369
        $inputClass = $new->getInputClass();
599
600 369
        if ($inputClass !== '') {
601 2
            $new->inputWidget = $new->inputWidget->class($inputClass);
602
        }
603
604
        // Set placeholder.
605 369
        $placeholder = $new->getPlaceholder() ?? $new->inputWidget->getAttributePlaceHolder();
606
607 369
        if ($new->inputWidget instanceof PlaceholderInterface && $placeholder !== '') {
608 9
            $new->inputWidget = $new->inputWidget->attributes(['placeholder' => $placeholder]);
609
        }
610
611
        // Set valid class and invalid class.
612 369
        $invalidClass = $new->getInvalidClass();
613 369
        $validClass = $new->getValidClass();
614
615 369
        if ($invalidClass !== '' && $new->inputWidget->hasError()) {
0 ignored issues
show
Bug introduced by
The method hasError() does not exist on Yiisoft\Form\Widget\Attribute\GlobalAttributes. It seems like you code against a sub-type of Yiisoft\Form\Widget\Attribute\GlobalAttributes such as Yiisoft\Form\Widget\Attribute\WidgetAttributes. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

615
        if ($invalidClass !== '' && $new->inputWidget->/** @scrutinizer ignore-call */ hasError()) {
Loading history...
616 4
            $new->inputWidget = $new->inputWidget->class($invalidClass);
617 365
        } elseif ($validClass !== '' && $new->inputWidget->isValidated()) {
0 ignored issues
show
Bug introduced by
The method isValidated() does not exist on Yiisoft\Form\Widget\Attribute\GlobalAttributes. It seems like you code against a sub-type of Yiisoft\Form\Widget\Attribute\GlobalAttributes such as Yiisoft\Form\Widget\Attribute\WidgetAttributes. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

617
        } elseif ($validClass !== '' && $new->inputWidget->/** @scrutinizer ignore-call */ isValidated()) {
Loading history...
618 4
            $new->inputWidget = $new->inputWidget->class($validClass);
619
        }
620
621
        // Set attributes.
622 369
        $new->inputWidget = $new->inputWidget->attributes($this->getAttributes());
623
624 369
        return $new;
625
    }
626
627 397
    private function renderButtons(): string
628
    {
629 397
        $buttons = '';
630
631 397
        foreach ($this->buttons as $button) {
632 34
            $nameButton = get_class($button) === SubmitButton::class ? 'submit' : 'reset';
633 34
            $buttonsAttributes = $this->getButtonsAttributes($nameButton);
634
635
            // Set input class.
636 34
            $inputClass = $this->getInputClass();
637
638 34
            if ($inputClass !== '') {
639
                $button = $button->class($inputClass);
640
            }
641
642 34
            $buttons .= $button->attributes($buttonsAttributes)->render();
643
        }
644
645 397
        return $buttons;
646
    }
647
648
    /**
649
     * @throws CircularReferenceException|InvalidConfigException|NotFoundException|NotInstantiableException
650
     */
651 349
    private function renderError(): string
652
    {
653 349
        $errorAttributes = $this->getErrorAttributes();
654 349
        $errorClass = $this->getErrorClass();
655
656 349
        if ($errorClass !== '') {
657 9
            Html::addCssClass($errorAttributes, $errorClass);
658
        }
659
660 349
        return Error::widget()
661 349
            ->attributes($errorAttributes)
662 349
            ->encode($this->getEncode())
663 349
            ->for($this->inputWidget->getFormModel(), $this->inputWidget->getAttribute())
664 349
            ->message($this->getError() ?? '')
665 349
            ->messageCallback($this->getErrorMessageCallback())
666 349
            ->tag($this->getErrorTag())
667 349
            ->render();
668
    }
669
670
    /**
671
     * @throws CircularReferenceException|InvalidConfigException|NotFoundException|NotInstantiableException
672
     */
673 369
    private function renderInputWidget(): string
674
    {
675 369
        $new = clone $this;
676
677 369
        $new = $new->buildField();
678
679 369
        if (!array_key_exists('{input}', $new->parts)) {
680 369
            $new->parts['{input}'] = $new->inputWidget->render();
681
        }
682
683 351
        if (!array_key_exists('{error}', $new->parts)) {
684 350
            $new->parts['{error}'] = $this->getError() !== null ? $new->renderError() : '';
685
        }
686
687 351
        if (!array_key_exists('{hint}', $new->parts)) {
688 350
            $new->parts['{hint}'] = $new->renderHint();
689
        }
690
691 351
        if (!array_key_exists('{label}', $new->parts)) {
692 319
            $new->parts['{label}'] = $new->renderLabel();
693
        }
694
695 351
        return preg_replace('/^\h*\v+/m', '', trim(strtr($new->getTemplate(), $new->parts)));
696
    }
697
698
    /**
699
     * @throws CircularReferenceException|InvalidConfigException|NotFoundException|NotInstantiableException
700
     */
701 350
    private function renderHint(): string
702
    {
703 350
        $hintAttributes = $this->getHintAttributes();
704 350
        $hintClass = $this->getHintClass();
705
706 350
        if ($hintClass !== '') {
707 6
            Html::addCssClass($hintAttributes, $hintClass);
708
        }
709
710 350
        if ($this->getAriaDescribedBy() === true) {
711 1
            $hintAttributes['id'] = $this->inputWidget->getInputId() . '-help';
712
        }
713
714 350
        return Hint::widget()
715 350
            ->attributes($hintAttributes)
716 350
            ->encode($this->getEncode())
717 350
            ->for($this->inputWidget->getFormModel(), $this->inputWidget->getAttribute())
718 350
            ->hint($this->getHint())
719 350
            ->tag($this->getHintTag())
720 350
            ->render();
721
    }
722
723
    /**
724
     * @throws CircularReferenceException|InvalidConfigException|NotFoundException|NotInstantiableException
725
     */
726 319
    private function renderLabel(): string
727
    {
728 319
        $labelAttributes = $this->getLabelAttributes();
729 319
        $labelClass = $this->getLabelClass();
730
731 319
        if (!array_key_exists('for', $labelAttributes)) {
732
            /** @var string */
733 318
            $labelAttributes['for'] = ArrayHelper::getValue(
734 318
                $this->getAttributes(),
735 318
                'id',
736 318
                $this->inputWidget->getInputId(),
737
            );
738
        }
739
740 319
        if ($labelClass !== '') {
741 4
            Html::addCssClass($labelAttributes, $labelClass);
742
        }
743
744 319
        return Label::widget()
745 319
            ->attributes($labelAttributes)
746 319
            ->encode($this->getEncode())
747 319
            ->for($this->inputWidget->getFormModel(), $this->inputWidget->getAttribute())
748 319
            ->label($this->getLabel())
749 319
            ->render();
750
    }
751
}
752