Passed
Push — master ( dc9b7e...714990 )
by Alexander
03:27 queued 13s
created

Alert::header()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

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