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

Modal::id()   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 0
Metric Value
cc 1
eloc 3
nc 1
nop 1
dl 0
loc 5
ccs 4
cts 4
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\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
    private const COLORS = ['is-primary', 'is-link', 'is-info', 'is-success', 'is-warning', 'is-danger', 'is-dark'];
35
    private const SIZES = ['is-small', 'is-medium', 'is-large'];
36
    private array $attributes = [];
37
    private string $autoIdPrefix = 'w';
38
    private array $closeButtonAttributes = [];
39
    private string $closeButtonClass = 'modal-close';
40
    private string $closeButtonSize = '';
41
    private array $contentAttributes = [];
42
    private string $modalBackgroundClass = 'modal-background';
43
    private string $modalButtonClass = 'button modal-button';
44
    private string $modalClass = 'modal';
45
    private string $modalContentClass = 'modal-content';
46
    private array $toggleButtonAttributes = [];
47
    private string $toggleButtonLabel = 'Toggle button';
48
    private string $toggleButtonSize = '';
49
    private string $toggleButtonColor = '';
50
    private bool $withoutCloseButton = true;
51
    private bool $withoutToggleButton = true;
52
53
    /**
54
     * The HTML attributes. The following special options are recognized.
55
     *
56
     * @param array $values Attribute values indexed by attribute names.
57
     *
58
     * @return self
59
     *
60
     * See {@see \Yiisoft\Html\Html::renderTagAttributes()} for details on how attributes are being rendered.
61
     */
62 2
    public function attributes(array $values): self
63
    {
64 2
        $new = clone $this;
65 2
        $new->attributes = $values;
66 2
        return $new;
67
    }
68
69
    /**
70
     * Returns a new instance with the specified prefix to the automatically generated widget IDs.
71
     *
72
     * @param string $value The prefix to the automatically generated widget IDs.
73
     *
74
     * @return self
75
     */
76 1
    public function autoIdPrefix(string $value): self
77
    {
78 1
        $new = clone $this;
79 1
        $new->autoIdPrefix = $value;
80 1
        return $new;
81
    }
82
83
    /**
84
     * Returns a new instance with the specified close button options.
85
     *
86
     * @param array $value The close button options.
87
     *
88
     * {@see Html::renderTagAttributes()} for details on how attributes are being rendered.
89
     *
90
     * @return self
91
     */
92 2
    public function closeButtonAttributes(array $value): self
93
    {
94 2
        $new = clone $this;
95 2
        $new->closeButtonAttributes = $value;
96
97 2
        return $new;
98
    }
99
100
    /**
101
     * Returns a new instance with the specified close button size.
102
     *
103
     * @param string $value The close button size.
104
     *
105
     * @return self
106
     */
107 3
    public function closeButtonSize(string $value): self
108
    {
109 3
        if (!in_array($value, self::SIZES, true)) {
110 1
            $values = implode('"', self::SIZES);
111 1
            throw new InvalidArgumentException("Invalid size. Valid values are: \"$values\".");
112
        }
113
114 2
        $new = clone $this;
115 2
        $new->closeButtonSize = $value;
116
117 2
        return $new;
118
    }
119
120
    /**
121
     * Returns a new instance with the specified content options.
122
     *
123
     * @param array $value The content options.
124
     *
125
     * {@see Html::renderTagAttributes()} for details on how attributes are being rendered.
126
     *
127
     * @return self
128
     */
129 2
    public function contentAttributes(array $value): self
130
    {
131 2
        $new = clone $this;
132 2
        $new->contentAttributes = $value;
133
134 2
        return $new;
135
    }
136
137
    /**
138
     * Returns a new instance with the specified ID of the widget.
139
     *
140
     * @param string $value The ID of the widget.
141
     *
142
     * @return self
143
     */
144 1
    public function id(string $value): self
145
    {
146 1
        $new = clone $this;
147 1
        $new->attributes['id'] = $value;
148 1
        return $new;
149
    }
150
151
    /**
152
     * Returns a new instance with the specified modal background class.
153
     *
154
     * @param string $value The modal background class.
155
     *
156
     * @return self
157
     */
158 2
    public function modalBackgroundClass(string $value): self
159
    {
160 2
        $new = clone $this;
161 2
        $new->modalBackgroundClass = $value;
162
163 2
        return $new;
164
    }
165
166
    /**
167
     * Returns a new instance with the specified modal button class.
168
     *
169
     * @param string $value The modal button class.
170
     *
171
     * @return self
172
     */
173 2
    public function modalButtonClass(string $value): self
174
    {
175 2
        $new = clone $this;
176 2
        $new->modalButtonClass = $value;
177
178 2
        return $new;
179
    }
180
181
    /**
182
     * Returns a new instance with the specified modal class.
183
     *
184
     * @param string $value The modal class.
185
     *
186
     * @return self
187
     */
188 2
    public function modalClass(string $value): self
189
    {
190 2
        $new = clone $this;
191 2
        $new->modalClass = $value;
192
193 2
        return $new;
194
    }
195
196
    /**
197
     * Returns a new instance with the specified modal content class.
198
     *
199
     * @param string $value The modal content class.
200
     *
201
     * @return self
202
     */
203 2
    public function modalContentClass(string $value): self
204
    {
205 2
        $new = clone $this;
206 2
        $new->modalContentClass = $value;
207
208 2
        return $new;
209
    }
210
211
    /**
212
     * Returns a new instance with the specified toggle button options.
213
     *
214
     * @param array $values Attribute values indexed by attribute names.
215
     *
216
     * {@see Html::renderTagAttributes()} for details on how attributes are being rendered.
217
     *
218
     * @return self
219
     */
220 2
    public function toggleButtonAttributes(array $values): self
221
    {
222 2
        $new = clone $this;
223 2
        $new->toggleButtonAttributes = $values;
224
225 2
        return $new;
226
    }
227
228
    /**
229
     * Returns a new instance with the specified toggle button color.
230
     *
231
     * @param string $value The toggle button color.
232
     *
233
     * @return self
234
     */
235 3
    public function toggleButtonColor(string $value): self
236
    {
237 3
        if (!in_array($value, self::COLORS, true)) {
238 1
            $values = implode(' ', self::COLORS);
239 1
            throw new InvalidArgumentException("Invalid color. Valid values are: $values.");
240
        }
241
242 2
        $new = clone $this;
243 2
        $new->toggleButtonColor = $value;
244
245 2
        return $new;
246
    }
247
248
    /**
249
     * Returns a new instance with the specified toggle button label.
250
     *
251
     * @param string $value The toggle button label.
252
     *
253
     * @return self
254
     */
255 2
    public function toggleButtonLabel(string $value): self
256
    {
257 2
        $new = clone $this;
258 2
        $new->toggleButtonLabel = $value;
259
260 2
        return $new;
261
    }
262
263
    /**
264
     * Returns a new instance with the specified toggle button size.
265
     *
266
     * @param string $value The toggle button size.
267
     *
268
     * @return self
269
     */
270 3
    public function toggleButtonSize(string $value): self
271
    {
272 3
        if (!in_array($value, self::SIZES, true)) {
273 1
            $values = implode(' ', self::SIZES);
274 1
            throw new InvalidArgumentException("Invalid size. Valid values are: $values.");
275
        }
276
277 2
        $new = clone $this;
278 2
        $new->toggleButtonSize = $value;
279
280 2
        return $new;
281
    }
282
283
    /**
284
     * Returns a new instance with the specified options for rendering the close button tag.
285
     *
286
     * @return self
287
     */
288 2
    public function withoutCloseButton(): self
289
    {
290 2
        $new = clone $this;
291 2
        $new->withoutCloseButton = false;
292
293 2
        return $new;
294
    }
295
296
    /**
297
     * Returns a new instance with the disabled toggle button.
298
     *
299
     * @return self
300
     */
301 2
    public function withoutToggleButton(): self
302
    {
303 2
        $new = clone $this;
304 2
        $new->withoutToggleButton = false;
305
306 2
        return $new;
307
    }
308
309 15
    public function begin(): ?string
310
    {
311 15
        parent::begin();
312
313 15
        $attributes = $this->attributes;
314 15
        $contentAttributes = $this->contentAttributes;
315 15
        $html = '';
316
317 15
        if (!array_key_exists('id', $attributes)) {
318 15
            $attributes['id'] = Html::generateId($this->autoIdPrefix) . '-modal';
319
        }
320
321
        /** @var string */
322 15
        $id = $attributes['id'];
323
324 15
        Html::addCssClass($attributes, $this->modalClass);
325 15
        Html::addCssClass($contentAttributes, $this->modalContentClass);
326
327 15
        if ($this->withoutToggleButton) {
328 14
            $html .= $this->renderToggleButton($id) . "\n";
329
        }
330
331 15
        $html .= Html::openTag('div', $attributes) . "\n"; // .modal
332 15
        $html .= Div::tag()->class($this->modalBackgroundClass) . "\n";
333
334 15
        if ($this->withoutCloseButton) {
335 14
            $html .= $this->renderCloseButton() . "\n";
336
        }
337
338 15
        $html .= Html::openTag('div', $contentAttributes) . "\n"; // .modal-content
339
340 15
        return $html;
341
    }
342
343 15
    protected function run(): string
344
    {
345 15
        $html = Html::closeTag('div') . "\n"; // .modal-content
346 15
        $html .= Html::closeTag('div'); // .modal
347
348 15
        return $html;
349
    }
350
351
    /**
352
     * Renders the toggle button.
353
     *
354
     * @param string $id
355
     *
356
     * @return string
357
     */
358 14
    private function renderToggleButton(string $id): string
359
    {
360 14
        $toggleButtonAttributes = $this->toggleButtonAttributes;
361
362 14
        $toggleButtonAttributes['data-target'] = '#' . $id;
363 14
        $toggleButtonAttributes['aria-haspopup'] = 'true';
364
365 14
        if ($this->toggleButtonSize !== '') {
366 1
            Html::addCssClass($toggleButtonAttributes, $this->toggleButtonSize);
367
        }
368
369 14
        if ($this->toggleButtonColor !== '') {
370 1
            Html::addCssClass($toggleButtonAttributes, $this->toggleButtonColor);
371
        }
372
373 14
        Html::addCssClass($toggleButtonAttributes, $this->modalButtonClass);
374
375 14
        return Button::tag()->attributes($toggleButtonAttributes)->content($this->toggleButtonLabel)->render();
376
    }
377
378
    /**
379
     * Renders the close button.
380
     *
381
     * @return string
382
     */
383 14
    private function renderCloseButton(): string
384
    {
385 14
        $closeButtonAttributes = $this->closeButtonAttributes;
386 14
        $closeButtonAttributes['aria-label'] = 'close';
387
388 14
        if ($this->closeButtonSize !== '') {
389 1
            Html::addCssClass($closeButtonAttributes, $this->closeButtonSize);
390
        }
391
392 14
        Html::addCssClass($closeButtonAttributes, $this->closeButtonClass);
393
394 14
        return Button::tag()->attributes($closeButtonAttributes)->render();
395
    }
396
}
397