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

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