Passed
Pull Request — master (#79)
by Wilmer
02:24
created

Message::render()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Yii\Bulma;
6
7
use InvalidArgumentException;
8
use Yiisoft\Html\Html;
9
use Yiisoft\Html\Tag\Button;
10
use Yiisoft\Html\Tag\Div;
11
use Yiisoft\Html\Tag\P;
12
use Yiisoft\Html\Tag\Span;
13
use Yiisoft\Widget\Widget;
14
15
use function implode;
16
use function in_array;
17
18
/**
19
 * Message renders Bulma message component.
20
 *
21
 * For example,
22
 *
23
 * ```php
24
 * <?= Message::widget()
25
 *     ->headerColor('success')
26
 *     ->header('System info')
27
 *     ->body('Say hello...') ?>
28
 * ```
29
 *
30
 * @link https://bulma.io/documentation/components/message/
31
 */
32
final class Message extends Widget
33
{
34
    public const SIZE_SMALL = 'is-small';
35
    public const SIZE_MEDIUM = 'is-medium';
36
    public const SIZE_LARGE = 'is-large';
37
    private const SIZE_ALL = [
38
        self::SIZE_SMALL,
39
        self::SIZE_MEDIUM,
40
        self::SIZE_LARGE,
41
    ];
42
    public const COLOR_PRIMARY = 'is-primary';
43
    public const COLOR_LINK = 'is-link';
44
    public const COLOR_INFO = 'is-info';
45
    public const COLOR_SUCCESS = 'is-success';
46
    public const COLOR_WARNING = 'is-warning';
47
    public const COLOR_DANGER = 'is-danger';
48
    public const COLOR_DARK = 'is-dark';
49
    private const COLOR_ALL = [
50
        self::COLOR_PRIMARY,
51
        self::COLOR_LINK,
52
        self::COLOR_INFO,
53
        self::COLOR_SUCCESS,
54
        self::COLOR_WARNING,
55
        self::COLOR_DANGER,
56
        self::COLOR_DARK,
57
    ];
58
    private array $attributes = [];
59
    private string $autoIdPrefix = 'w';
60
    private string $body = '';
61
    private array $bodyAttributes = [];
62
    private string $bodyCssClass = 'message-body';
63
    private array $buttonSpanAttributes = [];
64
    private string $buttonSpanAriaHidden = 'true';
65
    private string $buttonCssClass = 'delete';
66
    private string $cssClass = 'message';
67
    private bool $closedButton = false;
68
    private array $closeButtonAttributes = [];
69
    private bool $encode = false;
70
    private array $headerAttributes = [];
71
    private string $headerColor = self::COLOR_DARK;
72
    private string $headerMessage = '';
73
    private string $headerMessageCssClass = 'message-header';
74
    private string $size = '';
75
    private bool $withoutHeader = false;
76
77
    /**
78
     * Returns a new instance with the specified HTML attributes for widget.
79
     *
80
     * @param array $values Attribute values indexed by attribute names.
81
     *
82
     * @return self
83
     *
84
     * {@see \Yiisoft\Html\Html::renderTagAttributes()} For details on how attributes are being rendered.
85
     */
86 2
    public function attributes(array $values): self
87
    {
88 2
        $new = clone $this;
89 2
        $new->attributes = $values;
90 2
        return $new;
91
    }
92
93
    /**
94
     * Returns a new instance with the specified prefix to the automatically generated widget IDs.
95
     *
96
     * @param string $value The prefix to the automatically generated widget IDs.
97
     *
98
     * @return self
99
     */
100 1
    public function autoIdPrefix(string $value): self
101
    {
102 1
        $new = clone $this;
103 1
        $new->autoIdPrefix = $value;
104 1
        return $new;
105
    }
106
107
    /**
108
     * Returns a new instance with the specified the body content.
109
     *
110
     * @param string $value The body content.
111
     *
112
     * @return self
113
     */
114 12
    public function body(string $value): self
115
    {
116 12
        $new = clone $this;
117 12
        $new->body = $value;
118 12
        return $new;
119
    }
120
121
    /**
122
     * Returns a new instance with the specified HTML attributes for the widget body tag.
123
     *
124
     * @param array $values Attribute values indexed by attribute names.
125
     *
126
     * @return self
127
     *
128
     * {@see Html::renderTagAttributes()} for details on how attributes are being rendered.
129
     */
130 2
    public function bodyAttributes(array $values): self
131
    {
132 2
        $new = clone $this;
133 2
        $new->bodyAttributes = $values;
134 2
        return $new;
135
    }
136
137
    /**
138
     * Returns a new instance with the specified the CSS class for the body container.
139
     *
140
     * @param string $value The CSS class for the body container.
141
     *
142
     * @return self
143
     */
144 1
    public function bodyCssClass(string $value): self
145
    {
146 1
        $new = clone $this;
147 1
        $new->bodyCssClass = $value;
148 1
        return $new;
149
    }
150
151
    /**
152
     * Returns a new instance with the specified HTML attributes for the close button tag.
153
     *
154
     * The close button is displayed in the header of the Message. Clicking on the button will hide the message.
155
     *
156
     * @param array $values Attribute values indexed by attribute names.
157
     *
158
     * @return self
159
     *
160
     * {@see Html::renderTagAttributes()} For details on how attributes are being rendered.
161
     */
162 2
    public function closeButtonAttributes(array $values): self
163
    {
164 2
        $new = clone $this;
165 2
        $new->closeButtonAttributes = $values;
166 2
        return $new;
167
    }
168
169
    /**
170
     * Returns a new instance with the specified whether the tags for the message are encoded.
171
     *
172
     * @param bool $value whether to encode the output.
173
     *
174
     * @return self
175
     */
176 1
    public function encode(bool $value): self
177
    {
178 1
        $new = clone $this;
179 1
        $new->encode = $value;
180 1
        return $new;
181
    }
182
183
    /**
184
     * Returns a new instance with the specified HTML attributes for the widget header tag.
185
     *
186
     * @param array $values Attribute values indexed by attribute names.
187
     *
188
     * @return self
189
     *
190
     * {@see Html::renderTagAttributes()} For details on how attributes are being rendered.
191
     */
192 2
    public function headerAttributes(array $values): self
193
    {
194 2
        $new = clone $this;
195 2
        $new->headerAttributes = $values;
196 2
        return $new;
197
    }
198
199
    /**
200
     * Returns a new instance with the specified message header color.
201
     *
202
     * @param string $value The header color. Default is Message::COLOR_DARK.
203
     * Possible values: Message::COLOR_PRIMARY, Message::COLOR_LINK, Message::COLOR_INFO, Message::COLOR_SUCCESS,
204
     * Message::COLOR_WARNING, Message::COLOR_DANGER, Message::COLOR_DARK.
205
     *
206
     * @return self
207
     *
208
     * @link https://bulma.io/documentation/components/message/#colors
209
     */
210 3
    public function headerColor(string $value): self
211
    {
212 3
        if (!in_array($value, self::COLOR_ALL, true)) {
213 1
            $values = implode('", "', self::COLOR_ALL);
214 1
            throw new InvalidArgumentException("Invalid color. Valid values are: \"$values\".");
215
        }
216
217 2
        $new = clone $this;
218 2
        $new->headerColor = $value;
219 2
        return $new;
220
    }
221
222
    /**
223
     * Returns a new instance with the specified the header message.
224
     *
225
     * @param string $value The header message.
226
     *
227
     * @return self
228
     */
229 12
    public function headerMessage(string $value): self
230
    {
231 12
        $new = clone $this;
232 12
        $new->headerMessage = $value;
233 12
        return $new;
234
    }
235
236
    /**
237
     * Returns a new instance with the specified ID of the widget.
238
     *
239
     * @param string $value The ID of the widget.
240
     *
241
     * @return self
242
     */
243 2
    public function id(string $value): self
244
    {
245 2
        $new = clone $this;
246 2
        $new->attributes['id'] = $value;
247 2
        return $new;
248
    }
249
250
    /**
251
     * Returns a new instance with the specified size for the widget.
252
     *
253
     * @param string $value size class. By default, not class is added and the size is considered "normal".
254
     * Possible values: Message::SIZE_SMALL, Message::SIZE_MEDIUM, Message::SIZE_LARGE.
255
     *
256
     * @return self
257
     *
258
     * @link https://bulma.io/documentation/components/message/#sizes
259
     */
260 3
    public function size(string $value): self
261
    {
262 3
        if (!in_array($value, self::SIZE_ALL, true)) {
263 1
            $values = implode('", "', self::SIZE_ALL);
264 1
            throw new InvalidArgumentException("Invalid size. Valid values are: \"$values\".");
265
        }
266
267 2
        $new = clone $this;
268 2
        $new->size = $value;
269 2
        return $new;
270
    }
271
272
    /**
273
     * Returns a new instance with the specified allows you to remove the close button.
274
     *
275
     * @param bool $value Whether to remove the close button.
276
     *
277
     * @return self
278
     */
279 2
    public function withoutCloseButton(bool $value): self
280
    {
281 2
        $new = clone $this;
282 2
        $new->closedButton = $value;
283 2
        return $new;
284
    }
285
286
    /**
287
     * Returns a new instance with the specified allows you to disable header.
288
     *
289
     * @param bool $value Whether to disable header.
290
     *
291
     * @return self
292
     *
293
     * @link https://bulma.io/documentation/components/message/#message-body-only
294
     */
295 2
    public function withoutHeader(bool $value): self
296
    {
297 2
        $new = clone $this;
298 2
        $new->withoutHeader = $value;
299 2
        return $new;
300
    }
301
302 11
    public function render(): string
303
    {
304 11
        return $this->renderMessage();
305
    }
306
307 11
    private function renderCloseButton(): string
308
    {
309 11
        $html = '';
310
311 11
        $buttonSpanAttributes = $this->buttonSpanAttributes;
312 11
        $closeButtonAttributes = $this->closeButtonAttributes;
313
314 11
        if ($this->closedButton === true) {
315 1
            return $html;
316
        }
317
318 10
        $buttonSpanAttributes['aria-hidden'] = $this->buttonSpanAriaHidden;
319 10
        $closeButtonAttributes['type'] = 'button';
320
321 10
        Html::addCssClass($closeButtonAttributes, $this->buttonCssClass);
322 10
        unset($closeButtonAttributes['label']);
323
324 10
        $label = Span::tag()
325 10
            ->attributes($buttonSpanAttributes)
326 10
            ->content('&times;')
327 10
            ->encode(false)
328 10
            ->render();
329
330 10
        if ($this->size !== '') {
331 1
            Html::addCssClass($closeButtonAttributes, $this->size);
332
        }
333
334 10
        return Button::tag()
335 10
            ->attributes($closeButtonAttributes)
336 10
            ->content($label)
337 10
            ->encode(false)
338 10
            ->render() . PHP_EOL;
339
    }
340
341 11
    private function renderHeader(): string
342
    {
343 11
        $html = '';
344
345 11
        $headerAttributes = $this->headerAttributes;
346 11
        $headerMessage = $this->headerMessage;
347
348 11
        Html::addCssClass($headerAttributes, $this->headerMessageCssClass);
349
350 11
        $renderCloseButton = $this->renderCloseButton();
351
352 11
        if ($this->encode) {
353 1
            $headerMessage = Html::encode($headerMessage);
354
        }
355
356 11
        if ($renderCloseButton !== '') {
357 10
            $headerMessage = PHP_EOL . P::tag()->content($headerMessage) . PHP_EOL . $renderCloseButton;
358
        }
359
360 11
        if ($this->withoutHeader === false) {
361 10
            $html = Div::tag()
362 10
                ->attributes($headerAttributes)
363 10
                ->content($headerMessage)
364 10
                ->encode(false)
365 10
                ->render() . PHP_EOL;
366
        }
367
368 11
        return $html;
369
    }
370
371 11
    private function renderMessage(): string
372
    {
373 11
        $attributes = $this->attributes;
374
375
        /** @var string */
376 11
        $id = $attributes['id'] ?? (Html::generateId($this->autoIdPrefix) . '-message');
377 11
        unset($attributes['id']);
378
379 11
        Html::addCssClass($attributes, $this->cssClass);
380 11
        Html::addCssClass($attributes, $this->headerColor);
381
382 11
        if ($this->size !== '') {
383 1
            Html::addCssClass($attributes, $this->size);
384
        }
385
386 11
        return Div::tag()
387 11
            ->attributes($attributes)
388 11
            ->content(PHP_EOL . $this->renderHeader() . $this->renderMessageBody())
389 11
            ->encode(false)
390 11
            ->id($id)
391 11
            ->render();
392
    }
393
394 11
    private function renderMessageBody(): string
395
    {
396 11
        $body = $this->body;
397 11
        $bodyAttributes = $this->bodyAttributes;
398
399 11
        Html::addCssClass($bodyAttributes, $this->bodyCssClass);
400
401 11
        if ($this->encode) {
402 1
            $body = Html::encode($body);
403
        }
404
405 11
        if ($body !== '') {
406 11
            $body = PHP_EOL . $body . PHP_EOL;
407
        }
408
409 11
        return Div::tag()
410 11
            ->attributes($bodyAttributes)
411 11
            ->content($body)
412 11
            ->encode(false)
413 11
            ->render() . PHP_EOL;
414
    }
415
}
416