Passed
Pull Request — master (#57)
by Wilmer
02:15
created

Modal   A

Complexity

Total Complexity 29

Size/Duplication

Total Lines 392
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 2
Bugs 0 Features 0
Metric Value
wmc 29
eloc 128
c 2
b 0
f 0
dl 0
loc 392
ccs 112
cts 112
cp 1
rs 10

20 Methods

Rating   Name   Duplication   Size   Complexity  
A autoIdPrefix() 0 5 1
A attributes() 0 5 1
A closeButtonAttributes() 0 6 1
A modalContentClass() 0 6 1
A renderToggleButton() 0 18 3
A renderCloseButton() 0 12 2
A begin() 0 32 4
A withoutToggleButton() 0 6 1
A run() 0 6 1
A withoutCloseButton() 0 6 1
A toggleButtonSize() 0 11 2
A modalBackgroundClass() 0 6 1
A closeButtonSize() 0 11 2
A modalClass() 0 6 1
A toggleButtonAttributes() 0 6 1
A id() 0 5 1
A toggleButtonColor() 0 11 2
A contentAttributes() 0 6 1
A toggleButtonLabel() 0 6 1
A modalButtonClass() 0 6 1
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\Div;
10
use Yiisoft\Html\Tag\Button;
11
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...
12
13
use function implode;
14
use function in_array;
15
16
/**
17
 * Modal renders a modal window that can be toggled by clicking on a button.
18
 *
19
 * The following example will show the content enclosed between the {@see Widget::begin()} and {@see Widget::end()}
20
 * calls within the modal window:
21
 *
22
 * ```php
23
 * echo Modal::widget()->begin();
24
 *
25
 * echo 'Say hello...';
26
 *
27
 * echo Modal::end();
28
 * ```
29
 *
30
 * @link https://bulma.io/documentation/components/modal/
31
 */
32
final class Modal 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
43
    public const COLOR_PRIMARY = 'is-primary';
44
    public const COLOR_LINK = 'is-link';
45
    public const COLOR_INFO = 'is-info';
46
    public const COLOR_SUCCESS = 'is-success';
47
    public const COLOR_WARNING = 'is-warning';
48
    public const COLOR_DANGER = 'is-danger';
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
    ];
57
    private array $attributes = [];
58
    private string $autoIdPrefix = 'w';
59
    private array $closeButtonAttributes = [];
60
    private string $closeButtonClass = 'modal-close';
61
    private string $closeButtonSize = '';
62
    private array $contentAttributes = [];
63
    private string $modalBackgroundClass = 'modal-background';
64
    private string $modalButtonClass = 'button modal-button';
65
    private string $modalClass = 'modal';
66
    private string $modalContentClass = 'modal-content';
67
    private array $toggleButtonAttributes = [];
68
    private string $toggleButtonLabel = 'Toggle button';
69
    private string $toggleButtonSize = '';
70
    private string $toggleButtonColor = '';
71
    private bool $withoutCloseButton = false;
72
    private bool $withoutToggleButton = false;
73
74
    /**
75
     * The HTML attributes.
76
     *
77
     * @param array $values Attribute values indexed by attribute names.
78
     *
79
     * @return self
80
     *
81
     * See {@see \Yiisoft\Html\Html::renderTagAttributes()} for details on how attributes are being rendered.
82
     */
83 2
    public function attributes(array $values): self
84
    {
85 2
        $new = clone $this;
86 2
        $new->attributes = $values;
87 2
        return $new;
88
    }
89
90
    /**
91
     * Returns a new instance with the specified prefix to the automatically generated widget IDs.
92
     *
93
     * @param string $value The prefix to the automatically generated widget IDs.
94
     *
95
     * @return self
96
     */
97 1
    public function autoIdPrefix(string $value): self
98
    {
99 1
        $new = clone $this;
100 1
        $new->autoIdPrefix = $value;
101 1
        return $new;
102
    }
103
104
    /**
105
     * Returns a new instance with the specified close button options.
106
     *
107
     * @param array $value The close button options.
108
     *
109
     * {@see Html::renderTagAttributes()} for details on how attributes are being rendered.
110
     *
111
     * @return self
112
     */
113 2
    public function closeButtonAttributes(array $value): self
114
    {
115 2
        $new = clone $this;
116 2
        $new->closeButtonAttributes = $value;
117
118 2
        return $new;
119
    }
120
121
    /**
122
     * Returns a new instance with the specified close button size.
123
     *
124
     * @param string $value The close button size. Default setting empty normal.
125
     * Possible values: Modal::SIZE_SMALL, Modal::SIZE_MEDIUM, Model::SIZE_LARGE.
126
     *
127
     * @return self
128
     */
129 3
    public function closeButtonSize(string $value): self
130
    {
131 3
        if (!in_array($value, self::SIZE_ALL, true)) {
132 1
            $values = implode('"', self::SIZE_ALL);
133 1
            throw new InvalidArgumentException("Invalid size. Valid values are: \"$values\".");
134
        }
135
136 2
        $new = clone $this;
137 2
        $new->closeButtonSize = $value;
138
139 2
        return $new;
140
    }
141
142
    /**
143
     * Returns a new instance with the specified content options.
144
     *
145
     * @param array $value The content options.
146
     *
147
     * {@see Html::renderTagAttributes()} for details on how attributes are being rendered.
148
     *
149
     * @return self
150
     */
151 2
    public function contentAttributes(array $value): self
152
    {
153 2
        $new = clone $this;
154 2
        $new->contentAttributes = $value;
155
156 2
        return $new;
157
    }
158
159
    /**
160
     * Returns a new instance with the specified ID of the widget.
161
     *
162
     * @param string $value The ID of the widget.
163
     *
164
     * @return self
165
     */
166 1
    public function id(string $value): self
167
    {
168 1
        $new = clone $this;
169 1
        $new->attributes['id'] = $value;
170 1
        return $new;
171
    }
172
173
    /**
174
     * Returns a new instance with the specified modal background class.
175
     *
176
     * @param string $value The modal background class.
177
     *
178
     * @return self
179
     */
180 2
    public function modalBackgroundClass(string $value): self
181
    {
182 2
        $new = clone $this;
183 2
        $new->modalBackgroundClass = $value;
184
185 2
        return $new;
186
    }
187
188
    /**
189
     * Returns a new instance with the specified modal button class.
190
     *
191
     * @param string $value The modal button class.
192
     *
193
     * @return self
194
     */
195 2
    public function modalButtonClass(string $value): self
196
    {
197 2
        $new = clone $this;
198 2
        $new->modalButtonClass = $value;
199
200 2
        return $new;
201
    }
202
203
    /**
204
     * Returns a new instance with the specified modal class.
205
     *
206
     * @param string $value The modal class.
207
     *
208
     * @return self
209
     */
210 2
    public function modalClass(string $value): self
211
    {
212 2
        $new = clone $this;
213 2
        $new->modalClass = $value;
214
215 2
        return $new;
216
    }
217
218
    /**
219
     * Returns a new instance with the specified modal content class.
220
     *
221
     * @param string $value The modal content class.
222
     *
223
     * @return self
224
     */
225 2
    public function modalContentClass(string $value): self
226
    {
227 2
        $new = clone $this;
228 2
        $new->modalContentClass = $value;
229
230 2
        return $new;
231
    }
232
233
    /**
234
     * Returns a new instance with the specified toggle button options.
235
     *
236
     * @param array $values Attribute values indexed by attribute names.
237
     *
238
     * {@see Html::renderTagAttributes()} for details on how attributes are being rendered.
239
     *
240
     * @return self
241
     */
242 2
    public function toggleButtonAttributes(array $values): self
243
    {
244 2
        $new = clone $this;
245 2
        $new->toggleButtonAttributes = $values;
246
247 2
        return $new;
248
    }
249
250
    /**
251
     * Returns a new instance with the specified toggle button color.
252
     *
253
     * @param string $value The toggle button color. $value Setting default is empty.
254
     * Possible values: Modal::COLOR_PRIMARY, Modal::COLOR_LINK, Modal::COLOR_INFO, Modal::COLOR_SUCCESS,
255
     * Modal::COLOR_WARNING, Modal::COLOR_DANGER.
256
     *
257
     * @return self
258
     */
259 3
    public function toggleButtonColor(string $value): self
260
    {
261 3
        if (!in_array($value, self::COLOR_ALL, true)) {
262 1
            $values = implode(' ', self::COLOR_ALL);
263 1
            throw new InvalidArgumentException("Invalid color. Valid values are: \"$values\".");
264
        }
265
266 2
        $new = clone $this;
267 2
        $new->toggleButtonColor = $value;
268
269 2
        return $new;
270
    }
271
272
    /**
273
     * Returns a new instance with the specified toggle button label.
274
     *
275
     * @param string $value The toggle button label.
276
     *
277
     * @return self
278
     */
279 2
    public function toggleButtonLabel(string $value): self
280
    {
281 2
        $new = clone $this;
282 2
        $new->toggleButtonLabel = $value;
283
284 2
        return $new;
285
    }
286
287
    /**
288
     * Returns a new instance with the specified toggle button size.
289
     *
290
     * @param string $value The toggle button size. Default setting empty normal.
291
     * Possible values: Modal::SIZE_SMALL, Modal::SIZE_MEDIUM, Model::SIZE_LARGE.
292
     *
293
     * @return self
294
     */
295 3
    public function toggleButtonSize(string $value): self
296
    {
297 3
        if (!in_array($value, self::SIZE_ALL, true)) {
298 1
            $values = implode(' ', self::SIZE_ALL);
299 1
            throw new InvalidArgumentException("Invalid size. Valid values are: \"$values\".");
300
        }
301
302 2
        $new = clone $this;
303 2
        $new->toggleButtonSize = $value;
304
305 2
        return $new;
306
    }
307
308
    /**
309
     * Returns a new instance with the specified options for rendering the close button tag.
310
     *
311
     * @param bool $value Whether the close button is disabled.
312
     *
313
     * @return self
314
     */
315 2
    public function withoutCloseButton(bool $value): self
316
    {
317 2
        $new = clone $this;
318 2
        $new->withoutCloseButton = $value;
319
320 2
        return $new;
321
    }
322
323
    /**
324
     * Returns a new instance with the disabled toggle button.
325
     *
326
     * @param bool $value Whether the toggle button is disabled.
327
     *
328
     * @return self
329
     */
330 2
    public function withoutToggleButton(bool $value): self
331
    {
332 2
        $new = clone $this;
333 2
        $new->withoutToggleButton = $value;
334
335 2
        return $new;
336
    }
337
338 15
    public function begin(): ?string
339
    {
340 15
        parent::begin();
341
342 15
        $attributes = $this->attributes;
343 15
        $contentAttributes = $this->contentAttributes;
344 15
        $html = '';
345
346 15
        if (!array_key_exists('id', $attributes)) {
347 15
            $attributes['id'] = Html::generateId($this->autoIdPrefix) . '-modal';
348
        }
349
350
        /** @var string */
351 15
        $id = $attributes['id'];
352
353 15
        Html::addCssClass($attributes, $this->modalClass);
354 15
        Html::addCssClass($contentAttributes, $this->modalContentClass);
355
356 15
        if ($this->withoutToggleButton == false) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
357 14
            $html .= $this->renderToggleButton($id) . "\n";
358
        }
359
360 15
        $html .= Html::openTag('div', $attributes) . "\n"; // .modal
361 15
        $html .= Div::tag()->class($this->modalBackgroundClass) . "\n";
362
363 15
        if ($this->withoutCloseButton === false) {
364 14
            $html .= $this->renderCloseButton() . "\n";
365
        }
366
367 15
        $html .= Html::openTag('div', $contentAttributes) . "\n"; // .modal-content
368
369 15
        return $html;
370
    }
371
372 15
    protected function run(): string
373
    {
374 15
        $html = Html::closeTag('div') . "\n"; // .modal-content
375 15
        $html .= Html::closeTag('div'); // .modal
376
377 15
        return $html;
378
    }
379
380
    /**
381
     * Renders the toggle button.
382
     *
383
     * @param string $id
384
     *
385
     * @return string
386
     */
387 14
    private function renderToggleButton(string $id): string
388
    {
389 14
        $toggleButtonAttributes = $this->toggleButtonAttributes;
390
391 14
        $toggleButtonAttributes['data-target'] = '#' . $id;
392 14
        $toggleButtonAttributes['aria-haspopup'] = 'true';
393
394 14
        if ($this->toggleButtonSize !== '') {
395 1
            Html::addCssClass($toggleButtonAttributes, $this->toggleButtonSize);
396
        }
397
398 14
        if ($this->toggleButtonColor !== '') {
399 1
            Html::addCssClass($toggleButtonAttributes, $this->toggleButtonColor);
400
        }
401
402 14
        Html::addCssClass($toggleButtonAttributes, $this->modalButtonClass);
403
404 14
        return Button::tag()->attributes($toggleButtonAttributes)->content($this->toggleButtonLabel)->render();
405
    }
406
407
    /**
408
     * Renders the close button.
409
     *
410
     * @return string
411
     */
412 14
    private function renderCloseButton(): string
413
    {
414 14
        $closeButtonAttributes = $this->closeButtonAttributes;
415 14
        $closeButtonAttributes['aria-label'] = 'close';
416
417 14
        if ($this->closeButtonSize !== '') {
418 1
            Html::addCssClass($closeButtonAttributes, $this->closeButtonSize);
419
        }
420
421 14
        Html::addCssClass($closeButtonAttributes, $this->closeButtonClass);
422
423 14
        return Button::tag()->attributes($closeButtonAttributes)->render();
424
    }
425
}
426