Passed
Pull Request — master (#56)
by Wilmer
03:57 queued 01:41
created

Message::renderMessageBody()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 16
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 3

Importance

Changes 0
Metric Value
cc 3
eloc 8
nc 4
nop 0
dl 0
loc 16
ccs 9
cts 9
cp 1
crap 3
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;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, Yiisoft\Yii\Bulma\Widget. Consider defining an alias.

Let?s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let?s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

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