Passed
Pull Request — master (#78)
by
unknown
02:33
created

Alert::body()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
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 6
ccs 4
cts 4
cp 1
crap 1
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Yii\Bootstrap5;
6
7
use JsonException;
8
use Yiisoft\Arrays\ArrayHelper;
9
use Yiisoft\Html\Html;
10
11
use function array_merge;
12
13
/**
14
 * Alert renders an alert bootstrap component.
15
 *
16
 * For example,
17
 *
18
 * ```php
19
 * echo Alert::widget()
20
 *     ->options([
21
 *         'class' => 'alert-info',
22
 *     ])
23
 *     ->body('Say hello...');
24
 * ```
25
 *
26
 * @link https://getbootstrap.com/docs/5.0/components/alerts/
27
 */
28
final class Alert extends Widget
29
{
30
    public const TYPE_PRIMARY = 'alert-primary';
31
    public const TYPE_SECONDARY = 'alert-secondary';
32
    public const TYPE_SUCCESS = 'alert-success';
33
    public const TYPE_DANGER = 'alert-danger';
34
    public const TYPE_WARNING = 'alert-warning';
35
    public const TYPE_INFO = 'alert-info';
36
    public const TYPE_LIGHT = 'alert-light';
37
    public const TYPE_DARK = 'alert-dark';
38
39
    private string $body = '';
40
    private ?string $header = null;
41
    private array $headerOptions = [];
42
    private ?array $closeButton = [
43
        'class' => 'btn-close',
44
    ];
45
    private bool $encode = false;
46
    private array $options = [];
47
    private ?string $type = null;
48
    private bool $fade = false;
49
50 9
    public function getId(?string $suffix = '-alert'): ?string
51
    {
52 9
        return $this->options['id'] ?? parent::getId($suffix);
53
    }
54
55 9
    protected function run(): string
56
    {
57 9
        $options = $this->prepareOptions();
58 9
        $tag = ArrayHelper::remove($options, 'tag', 'div');
59
60 9
        $content = Html::openTag($tag, $options);
61 9
        $content .= $this->renderHeader();
62 9
        $content .= $this->encode ? Html::encode($this->body) : $this->body;
63 9
        $content .= $this->renderCloseButton();
64 9
        $content .= Html::closeTag($tag);
65
66 9
        return $content;
67
    }
68
69
    /**
70
     * The body content in the alert component. Alert widget will also be treated as the body content, and will be
71
     * rendered before this.
72
     *
73
     * @param string $value
74
     *
75
     * @return self
76
     */
77 9
    public function body(string $value): self
78
    {
79 9
        $new = clone $this;
80 9
        $new->body = $value;
81
82 9
        return $new;
83
    }
84
85
    /**
86
     * The header content in alert component
87
     *
88
     * @param string|null $header
89
     *
90
     * @return self
91
     */
92 1
    public function header(?string $header): self
93
    {
94 1
        $new = clone $this;
95 1
        $new->header = $header;
96
97 1
        return $new;
98
    }
99
100
    /**
101
     * The HTML attributes for the widget header tag. The following special options are recognized.
102
     *
103
     * {@see Html::renderTagAttributes()} for details on how attributes are being rendered.
104
     *
105
     * @param array $options
106
     *
107
     * @return self
108
     */
109 1
    public function headerOptions(array $options): self
110
    {
111 1
        $new = clone $this;
112 1
        $new->headerOptions = $options;
113
114 1
        return $new;
115
    }
116
117
    /**
118
     * The options for rendering the close button tag.
119
     *
120
     * The close button is displayed in the header of the modal window. Clicking on the button will hide the modal
121
     * window. If {@see closeButtonEnabled} is false, no close button will be rendered.
122
     *
123
     * The following special options are supported:
124
     *
125
     * - tag: string, the tag name of the button. Defaults to 'button'.
126
     * - label: string, the label of the button. Defaults to '&times;'.
127
     *
128
     * The rest of the options will be rendered as the HTML attributes of the button tag.
129
     *
130
     * Please refer to the [Alert documentation](http://getbootstrap.com/components/#alerts) for the supported HTML
131
     * attributes.
132
     *
133
     * @param array $value
134
     *
135
     * @return self
136
     */
137 3
    public function closeButton(?array $value): self
138
    {
139 3
        $new = clone $this;
140 3
        $new->closeButton = $value;
141
142 3
        return $new;
143
    }
144
145
    /**
146
     * Disable close button.
147
     *
148
     * @return self
149
     */
150 2
    public function withoutCloseButton(): self
151
    {
152 2
        return $this->closeButton(null);
153
    }
154
155
    /**
156
     * The HTML attributes for the widget container tag. The following special options are recognized.
157
     *
158
     * {@see Html::renderTagAttributes()} for details on how attributes are being rendered.
159
     *
160
     * @param array $value
161
     *
162
     * @return self
163
     */
164 3
    public function options(array $value): self
165
    {
166 3
        $new = clone $this;
167 3
        $new->options = $value;
168
169 3
        return $new;
170
    }
171
172
    /**
173
     * Enable/Disable encode body
174
     *
175
     * @param bool $encode
176
     *
177
     * @return self
178
     */
179
    public function encode(bool $encode = true): self
180
    {
181
        $new = clone $this;
182
        $new->encode = $encode;
183
184
        return $new;
185
    }
186
187
    /**
188
     * Enable/Disable dissmiss animation
189
     *
190
     * @param bool $fade
191
     *
192
     * @return self
193
     */
194 2
    public function fade(bool $fade = true): self
195
    {
196 2
        $new = clone $this;
197 2
        $new->fade = $fade;
198
199 2
        return $new;
200
    }
201
202
    /**
203
     * Set type of alert, 'alert-success', 'alert-danger' etc
204
     *
205
     * @param string $type
206
     *
207
     * @return self
208
     */
209 1
    public function type(string $type): self
210
    {
211 1
        $new = clone $this;
212 1
        $new->type = $type;
213
214 1
        return $new;
215
    }
216
217
    /**
218
     * Short method for primary alert type
219
     *
220
     * @return self
221
     */
222 1
    public function primary(): self
223
    {
224 1
        return $this->type(self::TYPE_PRIMARY);
225
    }
226
227
    /**
228
     * Short method for secondary alert type
229
     *
230
     * @return self
231
     */
232 1
    public function secondary(): self
233
    {
234 1
        return $this->type(self::TYPE_SECONDARY);
235
    }
236
237
    /**
238
     * Short method for success alert type
239
     *
240
     * @return self
241
     */
242 1
    public function success(): self
243
    {
244 1
        return $this->type(self::TYPE_SUCCESS);
245
    }
246
247
    /**
248
     * Short method for danger alert type
249
     *
250
     * @return self
251
     */
252 1
    public function danger(): self
253
    {
254 1
        return $this->type(self::TYPE_DANGER);
255
    }
256
257
    /**
258
     * Short method for warning alert type
259
     *
260
     * @return self
261
     */
262 1
    public function warning(): self
263
    {
264 1
        return $this->type(self::TYPE_WARNING);
265
    }
266
267
    /**
268
     * Short method for info alert type
269
     *
270
     * @return self
271
     */
272 1
    public function info(): self
273
    {
274 1
        return $this->type(self::TYPE_INFO);
275
    }
276
277
    /**
278
     * Short method for light alert type
279
     *
280
     * @return self
281
     */
282 1
    public function light(): self
283
    {
284 1
        return $this->type(self::TYPE_LIGHT);
285
    }
286
287
    /**
288
     * Short method for dark alert type
289
     *
290
     * @return self
291
     */
292 1
    public function dark(): self
293
    {
294 1
        return $this->type(self::TYPE_DARK);
295
    }
296
297
    /**
298
     * Renders the close button.
299
     *
300
     * @throws JsonException
301
     *
302
     * @return string the rendering result
303
     */
304 9
    public function renderCloseButton(bool $outside = false): ?string
305
    {
306 9
        if ($this->closeButton === null) {
307 2
            return null;
308
        }
309
310 7
        $options = array_merge(
311 7
            $this->closeButton,
312
            [
313 7
                'aria-label' => 'Close',
314
                'data-bs-dismiss' => 'alert',
315
            ],
316
        );
317 7
        $tag = ArrayHelper::remove($options, 'tag', 'button');
318 7
        $label = ArrayHelper::remove($options, 'label', '');
319 7
        $encode = ArrayHelper::remove($options, 'encode', $this->encode);
320
321 7
        if ($tag === 'button' && !isset($options['type'])) {
322 7
            $options['type'] = 'button';
323
        }
324
325 7
        if ($outside) {
326
            $options['data-bs-target'] = '#' . $this->getId();
327
        }
328
329 7
        return Html::tag($tag, $label, $options)->encode($encode)->render();
330
    }
331
332
    /**
333
     * Render header tag
334
     *
335
     * @return string|null
336
     */
337 9
    private function renderHeader(): ?string
338
    {
339 9
        if ($this->header === null) {
340 8
            return null;
341
        }
342
343 1
        $options = $this->headerOptions;
344 1
        $tag = ArrayHelper::remove($options, 'tag', 'h4');
345 1
        $encode = ArrayHelper::remove($options, 'encode', true);
346
347 1
        Html::addCssClass($options, ['alert-heading']);
348
349 1
        return Html::tag($tag, $this->header, $options)->encode($encode)->render();
350
    }
351
352
    /**
353
     * Prepare the widget options.
354
     *
355
     * This method returns the default values for various options.
356
     *
357
     * @return array
358
     */
359 9
    private function prepareOptions(): array
360
    {
361 9
        $options = $this->options;
362 9
        $options['id'] = $this->getId();
363 9
        $classNames = ['widget' => 'alert'];
364
365 9
        if ($this->type) {
366 1
            $classNames[] = $this->type;
367
        }
368
369 9
        if ($this->closeButton !== null) {
370 7
            $classNames[] = 'alert-dismissible';
371
        }
372
373 9
        if ($this->fade) {
374 2
            $classNames[] = 'fade show';
375
        }
376
377 9
        Html::addCssClass($options, $classNames);
378
379 9
        if (!isset($options['role'])) {
380 9
            $options['role'] = 'alert';
381
        }
382
383 9
        return $options;
384
    }
385
}
386