Test Failed
Pull Request — master (#160)
by Wilmer
02:22
created

Field::renderField()   A

Complexity

Conditions 6
Paths 24

Size

Total Lines 24
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 13
CRAP Score 6

Importance

Changes 0
Metric Value
cc 6
eloc 12
c 0
b 0
f 0
nc 24
nop 0
dl 0
loc 24
ccs 13
cts 13
cp 1
crap 6
rs 9.2222
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\PlaceholderInterface;
17
use Yiisoft\Form\Widget\Attribute\WidgetAttributes;
18
use Yiisoft\Form\Widget\FieldPart\Error;
19
use Yiisoft\Form\Widget\FieldPart\Hint;
20
use Yiisoft\Form\Widget\FieldPart\Label;
21
use Yiisoft\Html\Html;
22
use Yiisoft\Html\Tag\Div;
23
use Yiisoft\Widget\Widget;
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
    private array $containerAttributes = [];
0 ignored issues
show
introduced by
The private property $containerAttributes is not used, and could be removed.
Loading history...
37
    private WidgetAttributes $widget;
38
39
    /**
40
     * Renders a checkbox.
41
     *
42
     * This method will generate the `checked` tag attribute according to the model attribute value.
43
     *
44
     * @param FormModelInterface $formModel The model object.
45
     * @param string $attribute The attribute name or expression.
46
     * @param array $config The configuration array for widget factory.
47
     * Available methods:
48
     * [
49
     *     'enclosedByLabel()' => [false],
50
     *     'label()' => ['test-text-label'],
51
     *     'labelAttributes()' => [['class' => 'test-class']],
52
     *     'uncheckValue()' => ['0'],
53
     * ]
54
     *
55
     * @throws CircularReferenceException|InvalidConfigException|NotFoundException|NotInstantiableException
56
     *
57
     * @return static the field widget instance.
58
     */
59
    public function checkbox(FormModelInterface $formModel, string $attribute, array $config = []): self
60
    {
61
        $new = clone $this;
62
63
        /** @var array */
64
        $enclosedByLabel = $config['enclosedByLabel()'] ?? [true];
65
66
        if ($enclosedByLabel === [true]) {
67
            $new->parts['{label}'] = '';
68
        }
69
70
        $new->widget = 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\Attribute\WidgetAttributes or Yiisoft\Form\Widget\FieldPart\Error. ( Ignorable by Annotation )

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

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

567
            /** @scrutinizer ignore-call */ 
568
            $new->widget = $new->widget->ariaDescribedBy($new->widget->getAttribute() . 'Help');
Loading history...
568
        }
569 9
570
        // Set encode.
571 9
        $new->widget = $new->widget->encode($new->getEncode());
572 9
573 9
        // Set input class.
574 9
        if ($new->inputClass !== '') {
575
            $new->widget = $new->widget->class($new->inputClass);
576 9
        }
577 8
578
        // Set label settings for the radio and checkbox fields.
579
        if ($new->widget instanceof Radio || $new->widget instanceof Checkbox) {
580
            $new->widget = $new->widget->label($new->getLabel())->labelAttributes($new->getLabelAttributes());
581 9
        }
582 9
583
        // Set placeholder.
584 1
        $new->placeholder ??= $new->widget->getAttributePlaceHolder();
585
586
        if ($new->widget instanceof PlaceholderInterface && $new->placeholder !== '') {
587 9
            $new->widget = $new->widget->attributes(['placeholder' => $new->placeholder]);
588 1
        }
589
590
        // Set valid class and invalid class.
591 9
        if ($new->invalidClass !== '' && $new->widget->hasError()) {
592 1
            $new->widget = $new->widget->class($new->invalidClass);
593
        } elseif ($new->validClass !== '' && $new->widget->isValidated()) {
594
            $new->widget = $new->widget->class($new->validClass);
595 9
        }
596
597 8
        return $new;
598 9
    }
599 9
600 9
    private function renderButtons(): string
601
    {
602 8
        $buttons = '';
603
604
        foreach ($this->buttons as $key => $button) {
605
            $buttonsAttributes = $this->getButtonsIndividualAttributes((string) $key) ?? $this->attributes;
606
607
            // Set input class.
608
            if ($this->inputClass !== '') {
609
                $button = $button->class($this->inputClass);
610
            }
611
612
            $buttons .= $button->attributes($buttonsAttributes)->render();
613
        }
614
615
        return $buttons;
616
    }
617
618
    /**
619
     * @throws CircularReferenceException|InvalidConfigException|NotFoundException|NotInstantiableException
620
     */
621
    private function renderError(): string
622
    {
623
        $errorAttributes = $this->getErrorAttributes();
624
        $errorClass = $this->getErrorIndividualClass($this->type) ?? $this->getErrorClass();
625
626
        if ($errorClass !== '') {
627
            Html::addCssClass($errorAttributes, $errorClass);
628
        }
629
630 14
        return Error::widget()
631
            ->attributes($errorAttributes)
632 14
            ->encode($this->getEncode())
633 14
            ->for($this->widget->getFormModel(), $this->widget->getAttribute())
634 14
            ->message($this->getError() ?? '')
635
            ->messageCallback($this->getErrorMessageCallback())
636 14
            ->tag($this->getErrorTag())
637
            ->render();
638 14
    }
639 1
640
    /**
641
     * @throws CircularReferenceException|InvalidConfigException|NotFoundException|NotInstantiableException
642 14
     */
643 1
    private function renderField(): string
644 13
    {
645 1
        $new = clone $this;
646
647
        $new = $new->buildField();
648 14
        $new->widget = $new->widget->attributes($this->attributes);
649 1
650
        if (!array_key_exists('{input}', $new->parts)) {
651
            $new->parts['{input}'] = $new->widget->render();
652 14
        }
653
654 1
        if (!array_key_exists('{error}', $new->parts)) {
655 1
            $new->parts['{error}'] = $this->getError() !== null ? $new->renderError() : '';
656
        }
657
658 14
        if (!array_key_exists('{hint}', $new->parts)) {
659 1
            $new->parts['{hint}'] = $new->renderHint();
660
        }
661
662 14
        if (!array_key_exists('{label}', $new->parts)) {
663
            $new->parts['{label}'] = $new->renderLabel();
664 1
        }
665 1
666
        return preg_replace('/^\h*\v+/m', '', trim(strtr($new->template, $new->parts)));
667
    }
668 14
669 1
    /**
670
     * @throws CircularReferenceException|InvalidConfigException|NotFoundException|NotInstantiableException
671
     */
672 14
    private function renderHint(): string
673 1
    {
674
        $hintAttributes = $this->getHintAttributes();
675
        $hintClass = $this->getHintIndividualClass($this->type) ?? $this->getHintClass();
676
677 14
        if ($hintClass !== '') {
678 14
            Html::addCssClass($hintAttributes, $hintClass);
679
        }
680 1
681
        if ($this->getAriaDescribedBy() === true) {
682
            $hintAttributes['id'] = $this->widget->getInputId();
683
        }
684 14
685 14
        return Hint::widget()
686 14
            ->attributes($hintAttributes)
687 14
            ->encode($this->getEncode())
688 14
            ->for($this->widget->getFormModel(), $this->widget->getAttribute())
689 14
            ->hint($this->getHint())
690
            ->tag($this->getHintTag())
691
            ->render();
692 13
    }
693 14
694 14
    /**
695 14
     * @throws CircularReferenceException|InvalidConfigException|NotFoundException|NotInstantiableException
696 14
     */
697
    private function renderLabel(): string
698 13
    {
699
        $labelAttributes = $this->getLabelAttributes();
700
        $labelClass = $this->getLabelIndividualClass($this->type) ?? $this->getLabelClass();
701
702
        if (!array_key_exists('for', $labelAttributes)) {
703
            /** @var string */
704
            $labelAttributes['for'] = ArrayHelper::getValue($this->attributes, 'id', $this->widget->getInputId());
705
        }
706
707
        if ($labelClass !== '') {
708
            Html::addCssClass($labelAttributes, $labelClass);
709
        }
710
711
        return Label::widget()
712 9
            ->attributes($labelAttributes)
713
            ->encode($this->getEncode())
714 9
            ->for($this->widget->getFormModel(), $this->widget->getAttribute())
715 9
            ->label($this->getLabel())
716 9
            ->render();
717 9
    }
718
}
719