Passed
Pull Request — master (#44)
by Wilmer
02:06
created

Alert::bodyTag()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 5
c 1
b 0
f 0
nc 2
nop 1
dl 0
loc 9
ccs 6
cts 6
cp 1
crap 2
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Yii\Widgets;
6
7
use InvalidArgumentException;
8
use Yiisoft\Html\Html;
9
use Yiisoft\Html\Tag\Button;
10
use Yiisoft\Html\Tag\CustomTag;
11
use Yiisoft\Html\Tag\Div;
12
use Yiisoft\Widget\Widget;
13
14
/**
15
 * Alert renders an alert component.
16
 *
17
 * @link https://getbootstrap.com/docs/5.0/components/alerts/
18
 * @link https://bulma.io/documentation/elements/notification/
19
 * @link https://tailwindui.com/components/application-ui/feedback/alerts
20
 */
21
final class Alert extends Widget
22
{
23
    private array $attributes = [];
24
    private array $buttonAttributes = [];
25
    private string $buttonClass = '';
26
    private string $buttonLabel = '&times;';
27
    private string $buttonOnClick = '';
28
    private string $body = '';
29
    private array $bodyAttributes = [];
30
    private string $bodyClass = '';
31
    private bool $bodyContainer = false;
32
    private array $bodyContainerAttributes = [];
33
    private string $bodyContainerClass = '';
34
    /** @var non-empty-string */
0 ignored issues
show
Documentation Bug introduced by
The doc comment non-empty-string at position 0 could not be parsed: Unknown type name 'non-empty-string' at position 0 in non-empty-string.
Loading history...
35
    private string $bodyTag = 'span';
36
    private string $class = '';
37
    private ?string $id = null;
38
    private string $header = '';
39
    private array $headerAttributes = [];
40
    private string $headerClass = '';
41
    private bool $headerContainer = false;
42
    private array $headerContainerAttributes = [];
43
    private string $headerContainerClass = '';
44
    /** @var non-empty-string */
0 ignored issues
show
Documentation Bug introduced by
The doc comment non-empty-string at position 0 could not be parsed: Unknown type name 'non-empty-string' at position 0 in non-empty-string.
Loading history...
45
    private string $headerTag = 'span';
46
    private array $iconAttributes = [];
47
    private array $iconContainerAttributes = [];
48
    private string $iconContainerClass = '';
49
    private string $iconClass = '';
50
    private string $iconText = '';
51
    private string $layoutHeader = '';
52
    private string $layoutBody = '{body}{button}';
53
    private array $parts = [];
54
55
    /**
56
     * The HTML attributes for widget. The following special options are recognized.
57
     *
58
     * @param array $value
59
     *
60
     * @return static
61
     */
62
    public function attributes(array $value): self
63
    {
64
        $new = clone $this;
65
        $new->attributes = $value;
66
        return $new;
67
    }
68
69
    /**
70
     * The message content in the alert component. Alert widget will also be treated as the message content, and will be
71
     * rendered before this.
72
     *
73
     * @param string $value
74
     *
75
     * @return static
76
     */
77 19
    public function body(string $value): self
78
    {
79 19
        $new = clone $this;
80 19
        $new->body = $value;
81 19
        return $new;
82
    }
83
84
    /**
85
     * The attributes for rendering message content in the alert component.
86
     *
87
     * @param array $value
88
     *
89
     * @return static
90
     *
91
     * {@see Html::renderTagAttributes()} for details on how attributes are being rendered.
92
     */
93 1
    public function bodyAttributes(array $value): self
94
    {
95 1
        $new = clone $this;
96 1
        $new->bodyAttributes = $value;
97 1
        return $new;
98
    }
99
100
    /**
101
     * The CSS class for the alert panel body.
102
     *
103
     * @param string $value
104
     *
105
     * @return static
106
     */
107 7
    public function bodyClass(string $value): self
108
    {
109 7
        $new = clone $this;
110 7
        $new->bodyClass = $value;
111 7
        return $new;
112
    }
113
114
    /**
115
     * Allows you to add a div tag to the alert panel body.
116
     *
117
     * @param bool $value
118
     *
119
     * @return static
120
     */
121 6
    public function bodyContainer(bool $value = true): self
122
    {
123 6
        $new = clone $this;
124 6
        $new->bodyContainer = $value;
125 6
        return $new;
126
    }
127
128
    /**
129
     * The attributes for rendering the panel alert body.
130
     *
131
     * @param array $value
132
     *
133
     * @return static
134
     *
135
     * {@see Html::renderTagAttributes()} for details on how attributes are being rendered.
136
     */
137 1
    public function bodyContainerAttributes(array $value): self
138
    {
139 1
        $new = clone $this;
140 1
        $new->bodyContainerAttributes = $value;
141 1
        return $new;
142
    }
143
144
    /**
145
     * The CSS class for the alert panel body.
146
     *
147
     * @param string $value
148
     *
149
     * @return static
150
     */
151 6
    public function bodyContainerClass(string $value): self
152
    {
153 6
        $new = clone $this;
154 6
        $new->bodyContainerClass = $value;
155 6
        return $new;
156
    }
157
158
    /**
159
     * Set tag name for the alert panel body.
160
     *
161
     * @param string $value
162
     *
163
     * @throws InvalidArgumentException
164
     *
165
     * @return static
166
     */
167 2
    public function bodyTag(string $value): self
168
    {
169 2
        if (empty($value)) {
170 1
            throw new InvalidArgumentException('Body tag must be a string and cannot be empty.');
171
        }
172
173 1
        $new = clone $this;
174 1
        $new->bodyTag = $value;
175 1
        return $new;
176
    }
177
178
    /**
179
     * The attributes for rendering the close button tag.
180
     *
181
     * The close button is displayed in the header of the modal window. Clicking on the button will hide the modal
182
     * window.
183
     *
184
     * If {@see closeButtonEnabled} is false, no close button will be rendered.
185
     *
186
     * The rest of the options will be rendered as the HTML attributes of the button tag.
187
     *
188
     * @param array $value
189
     *
190
     * @return static
191
     *
192
     * {@see Html::renderTagAttributes()} for details on how attributes are being rendered.
193
     */
194 4
    public function buttonAttributes(array $value): self
195
    {
196 4
        $new = clone $this;
197 4
        $new->buttonAttributes = $value;
198 4
        return $new;
199
    }
200
201
    /**
202
     * The CSS class for the close button.
203
     *
204
     * @param string $value
205
     *
206
     * @return static
207
     */
208 13
    public function buttonClass(string $value): self
209
    {
210 13
        $new = clone $this;
211 13
        $new->buttonClass = $value;
212 13
        return $new;
213
    }
214
215
    /**
216
     * The label for the close button.
217
     *
218
     * @param string $value
219
     *
220
     * @return static
221
     */
222 4
    public function buttonLabel(string $value = ''): self
223
    {
224 4
        $new = clone $this;
225 4
        $new->buttonLabel = $value;
226 4
        return $new;
227
    }
228
229
    /**
230
     * The onclick JavaScript for the close button.
231
     *
232
     * @param string $value
233
     *
234
     * @return static
235
     */
236 11
    public function buttonOnClick(string $value = ''): self
237
    {
238 11
        $new = clone $this;
239 11
        $new->buttonOnClick = $value;
240 11
        return $new;
241
    }
242
243
    /**
244
     * Set attribute class for widget.
245
     *
246
     * @param string $value
247
     *
248
     * @return static
249
     */
250 12
    public function class(string $value): self
251
    {
252 12
        $new = clone $this;
253 12
        $new->class = $value;
254 12
        return $new;
255
    }
256
257 19
    public function id(?string $value): self
258
    {
259 19
        $new = clone $this;
260 19
        $new->id = $value;
261 19
        return $new;
262
    }
263
264
    /**
265
     * The header content in the alert component. Alert widget will also be treated as the header content, and will be
266
     * rendered before this.
267
     *
268
     * @param string $value
269
     *
270
     * @return static
271
     */
272 4
    public function header(string $value): self
273
    {
274 4
        $new = clone $this;
275 4
        $new->header = $value;
276 4
        return $new;
277
    }
278
279
    /**
280
     * The attributes for rendering the header content in the alert component.
281
     *
282
     * @param array $value
283
     *
284
     * @return static
285
     *
286
     * {@see Html::renderTagAttributes()} for details on how attributes are being rendered.
287
     */
288 1
    public function headerAttributes(array $value): self
289
    {
290 1
        $new = clone $this;
291 1
        $new->headerAttributes = $value;
292 1
        return $new;
293
    }
294
295
    /**
296
     * The CSS class for the alert panel header.
297
     *
298
     * @param string $value
299
     *
300
     * @return static
301
     */
302 2
    public function headerClass(string $value): self
303
    {
304 2
        $new = clone $this;
305 2
        $new->headerClass = $value;
306 2
        return $new;
307
    }
308
309
    /**
310
     * Allows you to add a div tag to the alert panel header.
311
     *
312
     * @param bool $value
313
     *
314
     * @return static
315
     */
316 2
    public function headerContainer(bool $value = true): self
317
    {
318 2
        $new = clone $this;
319 2
        $new->headerContainer = $value;
320 2
        return $new;
321
    }
322
323
    /**
324
     * The CSS class for the alert panel header.
325
     *
326
     * @param string $value
327
     *
328
     * @return static
329
     */
330 1
    public function headerContainerClass(string $value): self
331
    {
332 1
        $new = clone $this;
333 1
        $new->headerContainerClass = $value;
334 1
        return $new;
335
    }
336
337
    /**
338
     * The attributes for rendering the panel alert header.
339
     *
340
     * @param array $value
341
     *
342
     * @return static
343
     *
344
     * {@see Html::renderTagAttributes()} for details on how attributes are being rendered.
345
     */
346 1
    public function headerContainerAttributes(array $value): self
347
    {
348 1
        $new = clone $this;
349 1
        $new->headerContainerAttributes = $value;
350 1
        return $new;
351
    }
352
353
    /**
354
     * Set tag name for the alert panel header.
355
     *
356
     * @param string $value
357
     *
358
     * @throws InvalidArgumentException
359
     *
360
     * @return static
361
     */
362 2
    public function headerTag(string $value): self
363
    {
364 2
        if (empty($value)) {
365 1
            throw new InvalidArgumentException('Header tag must be a string and cannot be empty.');
366
        }
367
368 1
        $new = clone $this;
369 1
        $new->headerTag = $value;
370 1
        return $new;
371
    }
372
373
    /**
374
     * The attributes for rendering the `<i>` tag for icons alerts.
375
     *
376
     * @param array $value
377
     *
378
     * @return static
379
     *
380
     * {@see Html::renderTagAttributes()} for details on how attributes are being rendered.
381
     */
382 2
    public function iconAttributes(array $value): self
383
    {
384 2
        $new = clone $this;
385 2
        $new->iconAttributes = $value;
386 2
        return $new;
387
    }
388
389
    /**
390
     * Set icon css class in the alert component.
391
     *
392
     * @param string $value
393
     *
394
     * @return static
395
     */
396 5
    public function iconClass(string $value): self
397
    {
398 5
        $new = clone $this;
399 5
        $new->iconClass = $value;
400 5
        return $new;
401
    }
402
403
    /**
404
     * The attributes for rendering the container `<i>` tag.
405
     *
406
     * The rest of the options will be rendered as the HTML attributes of the `<i>` tag.
407
     *
408
     * @param array $value
409
     *
410
     * @return static
411
     *
412
     * {@see Html::renderTagAttributes()} for details on how attributes are being rendered.
413
     */
414 1
    public function iconContainerAttributes(array $value): self
415
    {
416 1
        $new = clone $this;
417 1
        $new->iconContainerAttributes = $value;
418 1
        return $new;
419
    }
420
421
    /**
422
     * The CSS class for the container `<i>` tag.
423
     *
424
     * @param string $value
425
     *
426
     * @return static
427
     */
428 2
    public function iconContainerClass(string $value): self
429
    {
430 2
        $new = clone $this;
431 2
        $new->iconContainerClass = $value;
432 2
        return $new;
433
    }
434
435
    /**
436
     * Set icon text in the alert component.
437
     *
438
     * @param string $value
439
     *
440
     * @return static
441
     */
442 3
    public function iconText(string $value): self
443
    {
444 3
        $new = clone $this;
445 3
        $new->iconText = $value;
446 3
        return $new;
447
    }
448
449
    /**
450
     * Set layout the alert panel body.
451
     *
452
     * @param string $value
453
     *
454
     * @return static
455
     */
456 8
    public function layoutBody(string $value): self
457
    {
458 8
        $new = clone $this;
459 8
        $new->layoutBody = $value;
460 8
        return $new;
461
    }
462
463
    /**
464
     * Set layout the alert panel header.
465
     *
466
     * @param string $value
467
     *
468
     * @return static
469
     */
470 6
    public function layoutHeader(string $value): self
471
    {
472 6
        $new = clone $this;
473 6
        $new->layoutHeader = $value;
474 6
        return $new;
475
    }
476
477 19
    protected function run(): string
478
    {
479 19
        return $this->renderAlert();
480
    }
481
482
    /**
483
     * Render Alert.
484
     */
485 19
    private function renderAlert(): string
486
    {
487 19
        $new = clone $this;
488 19
        $new->attributes['role'] = 'alert';
489 19
        $new->attributes['id'] ??= $new->id ?? Html::generateId('alert-');
490
491 19
        if (!isset($new->parts['{button}'])) {
492 19
            $new->renderCloseButton($new);
493
        }
494
495 19
        if (!isset($new->parts['{icon}'])) {
496 19
            $new->renderIcon($new);
497
        }
498
499 19
        if (!isset($new->parts['{body}'])) {
500 19
            $new->renderBody($new);
501
        }
502
503 19
        if (!isset($new->parts['{header}'])) {
504 19
            $new->renderHeader($new);
505
        }
506
507 19
        $contentAlert = $new->renderPanelHeader($new) . PHP_EOL . $new->renderPanelBody($new);
508
509 19
        if ($new->class !== '') {
510 12
            Html::addCssClass($new->attributes, $new->class);
511
        }
512
513 19
        return $new->body !== ''
514 19
            ? Div::tag()
515 19
                ->attributes($new->attributes)
516 19
                ->content(PHP_EOL . trim($contentAlert) . PHP_EOL)
517 19
                ->encode(false)
518 19
                ->render()
519 19
            : '';
520
    }
521
522
    /**
523
     * Renders close button.
524
     */
525 19
    private function renderCloseButton(self $new): void
526
    {
527 19
        $new->parts['{button}'] = '';
528
529 19
        if ($new->buttonOnClick !== '') {
530 7
            $new->buttonAttributes['onclick'] = $new->buttonOnClick;
531
        }
532
533 19
        if ($new->buttonClass !== '') {
534 13
            Html::addCssClass($new->buttonAttributes, $new->buttonClass);
535
        }
536
537 19
        $new->parts['{button}'] = PHP_EOL .
538 19
            Button::tag()
539 19
                ->attributes($new->buttonAttributes)
540 19
                ->content($new->buttonLabel)
541 19
                ->encode(false)
542 19
                ->type('button')
543 19
                ->render();
544 19
    }
545
546
    /**
547
     * Render icon.
548
     */
549 19
    private function renderIcon(self $new): void
550
    {
551 19
        if ($new->iconClass !== '') {
552 5
            Html::addCssClass($new->iconAttributes, $new->iconClass);
553
        }
554
555 19
        if ($new->iconContainerClass !== '') {
556 2
            Html::addCssClass($new->iconContainerAttributes, $new->iconContainerClass);
557
        }
558
559 19
        $icon = CustomTag::name('i')->attributes($new->iconAttributes)->content($new->iconText)->render();
560
561 19
        $new->parts['{icon}'] = PHP_EOL .
562 19
            Div::tag()
563 19
                ->attributes($new->iconContainerAttributes)
564 19
                ->content($icon)
565 19
                ->encode(false)
566 19
                ->render() . PHP_EOL;
567 19
    }
568
569
    /**
570
     * Render the alert message.
571
     */
572 19
    private function renderBody(self $new): void
573
    {
574 19
        if ($new->bodyClass !== '') {
575 7
            Html::addCssClass($new->bodyAttributes, $new->bodyClass);
576
        }
577
578 19
        $new->parts['{body}'] = CustomTag::name($new->bodyTag)
579 19
            ->attributes($new->bodyAttributes)
580 19
            ->content($new->body)
581 19
            ->encode(false)
582 19
            ->render();
583 19
    }
584
585
    /**
586
     * Render the alert message header.
587
     */
588 19
    private function renderHeader(self $new): void
589
    {
590 19
        if ($new->headerClass !== '') {
591 2
            Html::addCssClass($new->headerAttributes, $new->headerClass);
592
        }
593
594 19
        $new->parts['{header}'] = CustomTag::name($new->headerTag)
595 19
            ->attributes($new->headerAttributes)
596 19
            ->content($new->header)
597 19
            ->encode(false)
598 19
            ->render();
599 19
    }
600
601
    /**
602
     * Render the alert panel header.
603
     */
604 19
    private function renderPanelHeader(self $new): string
605
    {
606 19
        $headerHtml = trim(strtr($new->layoutHeader, $new->parts));
607
608 19
        if ($new->headerContainerClass !== '') {
609 1
            Html::addCssClass($new->headerContainerAttributes, $new->headerContainerClass);
610
        }
611
612 19
        if ($new->headerContainer && $headerHtml !== '') {
613 2
            $headerHtml = Div::tag()
614 2
                ->attributes($new->headerContainerAttributes)
615 2
                ->content(PHP_EOL . $headerHtml . PHP_EOL)
616 2
                ->encode(false)
617 2
                ->render();
618
        }
619
620 19
        return $headerHtml;
621
    }
622
623
    /**
624
     * Render the alert panel body.
625
     */
626 19
    private function renderPanelBody(self $new): string
627
    {
628 19
        $bodyHtml = trim(strtr($new->layoutBody, $new->parts));
629
630 19
        if ($new->bodyContainerClass !== '') {
631 6
            Html::addCssClass($new->bodyContainerAttributes, $new->bodyContainerClass);
632
        }
633
634 19
        if ($new->bodyContainer) {
635 6
            $bodyHtml = Div::tag()
636 6
                ->attributes($new->bodyContainerAttributes)
637 6
                ->content(PHP_EOL . $bodyHtml . PHP_EOL)
638 6
                ->encode(false)
639 6
                ->render();
640
        }
641
642 19
        return $bodyHtml;
643
    }
644
}
645