Passed
Push — master ( 938383...498485 )
by Alexander
02:16
created

ModalCard::footer()   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\Bulma;
6
7
use InvalidArgumentException;
8
use Yiisoft\Html\Html;
9
use Yiisoft\Html\Tag\Button;
10
use Yiisoft\Html\Tag\CustomTag;
11
use Yiisoft\Html\Tag\Div;
12
use Yiisoft\Html\Tag\P;
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
use function implode;
16
use function in_array;
17
18
/**
19
 * ModalCard renders a modal window that can be toggled by clicking on a button.
20
 *
21
 * The following example will show the content enclosed between the {@see Widget::begin()} and {@see Widget::end()}
22
 * calls within the modal window:
23
 *
24
 * ```php
25
 * echo ModalCard::widget()
26
 *     ->title('Modal title')
27
 *     ->footer(
28
 *         Html::button('Cancel', ['class' => 'button'])
29
 *     )
30
 *     ->begin();
31
 *
32
 * echo 'Say hello...';
33
 *
34
 * echo ModalCard::end();
35
 * ```
36
 *
37
 * @link https://bulma.io/documentation/components/modal/
38
 */
39
final class ModalCard extends Widget
40
{
41
    public const SIZE_SMALL = 'is-small';
42
    public const SIZE_MEDIUM = 'is-medium';
43
    public const SIZE_LARGE = 'is-large';
44
    private const SIZE_ALL = [
45
        self::SIZE_SMALL,
46
        self::SIZE_MEDIUM,
47
        self::SIZE_LARGE,
48
    ];
49
    public const COLOR_PRIMARY = 'is-primary';
50
    public const COLOR_LINK = 'is-link';
51
    public const COLOR_INFO = 'is-info';
52
    public const COLOR_SUCCESS = 'is-success';
53
    public const COLOR_WARNING = 'is-warning';
54
    public const COLOR_DANGER = 'is-danger';
55
    public const COLOR_DARK = 'is-dark';
56
    private const COLOR_ALL = [
57
        self::COLOR_PRIMARY,
58
        self::COLOR_LINK,
59
        self::COLOR_INFO,
60
        self::COLOR_SUCCESS,
61
        self::COLOR_WARNING,
62
        self::COLOR_DANGER,
63
        self::COLOR_DARK,
64
    ];
65
    private array $attributes = [];
66
    private string $autoIdPrefix = 'w';
67
    private string $backgroundClass = 'modal-background';
68
    private array $bodyAttributes = [];
69
    private string $bodyClass = 'modal-card-body';
70
    private string $buttonClass = 'button modal-button';
71
    private array $cardAttributes = [];
72
    private string $cardClass = 'modal';
73
    private array $closeButtonAttributes = [];
74
    private string $closeButtonClass = 'button delete';
75
    private string $closeButtonSize = '';
76
    private string $contentClass = 'modal-card';
77
    private string $footer = '';
78
    private array $headerAttributes = [];
79
    private string $headerClass = 'modal-card-head';
80
    private array $footerAttributes = [];
81
    private string $footerClass = 'modal-card-foot';
82
    private string $title = '';
83
    private string $titleClass = 'modal-card-title';
84
    private array $titleAttributes = [];
85
    private array $toggleButtonAttributes = [];
86
    private string $toggleButtonColor = '';
87
    private string $toggleButtonLabel = 'Toggle button';
88
    private string $toggleButtonSize = '';
89
    private bool $withoutCloseButton = false;
90
    private bool $withoutToggleButton = false;
91
92
    /**
93
     * The HTML attributes.
94
     *
95
     * @param array $values Attribute values indexed by attribute names.
96
     *
97
     * @return self
98
     *
99
     * See {@see \Yiisoft\Html\Html::renderTagAttributes()} for details on how attributes are being rendered.
100
     */
101 2
    public function attributes(array $values): self
102
    {
103 2
        $new = clone $this;
104 2
        $new->attributes = $values;
105 2
        return $new;
106
    }
107
108
    /**
109
     * Returns a new instance with the specified prefix to the automatically generated widget IDs.
110
     *
111
     * @param string $value The prefix to the automatically generated widget IDs.
112
     *
113
     * @return self
114
     */
115 1
    public function autoIdPrefix(string $value): self
116
    {
117 1
        $new = clone $this;
118 1
        $new->autoIdPrefix = $value;
119 1
        return $new;
120
    }
121
122
    /**
123
     * Returns a new instance with the specified body attributes.
124
     *
125
     * @param array $value The body attributes.
126
     *
127
     * {@see Html::renderTagAttributes()} for details on how attributes are being rendered.
128
     *
129
     * @return self
130
     */
131 3
    public function bodyAttributes(array $value): self
132
    {
133 3
        $new = clone $this;
134 3
        $new->bodyAttributes = $value;
135
136 3
        return $new;
137
    }
138
139
    /**
140
     * Returns a new instance with the specified close button attributes.
141
     *
142
     * @param array $value The close button attributes.
143
     *
144
     * {@see Html::renderTagAttributes()} for details on how attributes are being rendered.
145
     *
146
     * @return self
147
     */
148 2
    public function closeButtonAttributes(array $value): self
149
    {
150 2
        $new = clone $this;
151 2
        $new->closeButtonAttributes = $value;
152
153 2
        return $new;
154
    }
155
156
    /**
157
     * Returns a new instance with the specified close button class.
158
     *
159
     * @param string $value The close button class.
160
     *
161
     * @return self
162
     */
163
    public function closeButtonClass(string $value): self
164
    {
165
        $new = clone $this;
166
        $new->closeButtonClass = $value;
167
168
        return $new;
169
    }
170
171
    /**
172
     * Returns a new instance with the specified close button size.
173
     *
174
     * @param string $value The close button size. Default setting is "normal".
175
     * Possible values are: ModalCard::SIZE_SMALL, ModalCard::SIZE_MEDIUM, ModalCard::SIZE_LARGE.
176
     *
177
     * @return self
178
     */
179 3
    public function closeButtonSize(string $value): self
180
    {
181 3
        if (!in_array($value, self::SIZE_ALL, true)) {
182 1
            $values = implode('", "', self::SIZE_ALL);
183 1
            throw new InvalidArgumentException("Invalid size. Valid values are: \"$values\".");
184
        }
185
186 2
        $new = clone $this;
187 2
        $new->closeButtonSize = $value;
188
189 2
        return $new;
190
    }
191
192
    /**
193
     * Returns a new instance with the specified card attributes.
194
     *
195
     * @param array $value The content attributes.
196
     *
197
     * {@see Html::renderTagAttributes()} for details on how attributes are being rendered.
198
     *
199
     * @return self
200
     */
201 2
    public function cardAttributes(array $value): self
202
    {
203 2
        $new = clone $this;
204 2
        $new->cardAttributes = $value;
205
206 2
        return $new;
207
    }
208
209
    /**
210
     * Returns a new instance with the specified footer content.
211
     *
212
     * @param string $value The footer content in the modal window.
213
     *
214
     * @return self
215
     */
216 16
    public function footer(string $value): self
217
    {
218 16
        $new = clone $this;
219 16
        $new->footer = $value;
220
221 16
        return $new;
222
    }
223
224
    /**
225
     * Returns a new instance with the specified footer attributes.
226
     *
227
     * @param array $value The footer attributes.
228
     *
229
     * {@see Html::renderTagAttributes()} for details on how attributes are being rendered.
230
     *
231
     * @return self
232
     */
233 2
    public function footerAttributes(array $value): self
234
    {
235 2
        $new = clone $this;
236 2
        $new->footerAttributes = $value;
237
238 2
        return $new;
239
    }
240
241
    /**
242
     * Returns a new instance with the specified header attributes.
243
     *
244
     * @param array $value The header attributes.
245
     *
246
     * {@see Html::renderTagAttributes()} for details on how attributes are being rendered.
247
     *
248
     * @return self
249
     */
250 2
    public function headerAttributes(array $value): self
251
    {
252 2
        $new = clone $this;
253 2
        $new->headerAttributes = $value;
254
255 2
        return $new;
256
    }
257
258
    /**
259
     * Returns a new instance with the specified ID of the widget.
260
     *
261
     * @param string|null $value The ID of the widget.
262
     *
263
     * @return self
264
     */
265 1
    public function id(?string $value): self
266
    {
267 1
        $new = clone $this;
268 1
        $new->attributes['id'] = $value;
269 1
        return $new;
270
    }
271
272
    /**
273
     * Returns a new instance with the specified modal card background class.
274
     *
275
     * @param string $value The modal card background class.
276
     *
277
     * @return self
278
     */
279 1
    public function backgroundClass(string $value): self
280
    {
281 1
        $new = clone $this;
282 1
        $new->backgroundClass = $value;
283
284 1
        return $new;
285
    }
286
287
    /**
288
     * Returns a new instance with the specified modal card body class.
289
     *
290
     * @param string $value The modal card body class.
291
     *
292
     * @return self
293
     */
294 1
    public function bodyClass(string $value): self
295
    {
296 1
        $new = clone $this;
297 1
        $new->bodyClass = $value;
298
299 1
        return $new;
300
    }
301
302
    /**
303
     * Returns a new instance with the specified modal card button class.
304
     *
305
     * @param string $value The modal card button class.
306
     *
307
     * @return self
308
     */
309 1
    public function buttonClass(string $value): self
310
    {
311 1
        $new = clone $this;
312 1
        $new->buttonClass = $value;
313
314 1
        return $new;
315
    }
316
317
    /**
318
     * Returns a new instance with the specified modal card class.
319
     *
320
     * @param string $value The modal card class.
321
     *
322
     * @return self
323
     */
324 1
    public function cardClass(string $value): self
325
    {
326 1
        $new = clone $this;
327 1
        $new->cardClass = $value;
328
329 1
        return $new;
330
    }
331
332
    /**
333
     * Returns a new instance with the specified modal card content class.
334
     *
335
     * @param string $value The modal card content class.
336
     *
337
     * @return self
338
     */
339 1
    public function contentClass(string $value): self
340
    {
341 1
        $new = clone $this;
342 1
        $new->contentClass = $value;
343
344 1
        return $new;
345
    }
346
347
    /**
348
     * Returns a new instance with the specified modal card footer class.
349
     *
350
     * @param string $value The modal card footer class.
351
     *
352
     * @return self
353
     */
354 1
    public function footerClass(string $value): self
355
    {
356 1
        $new = clone $this;
357 1
        $new->footerClass = $value;
358
359 1
        return $new;
360
    }
361
362
    /**
363
     * Returns a new instance with the specified modal card header class.
364
     *
365
     * @param string $value The modal card head class.
366
     *
367
     * @return self
368
     */
369 1
    public function headerClass(string $value): self
370
    {
371 1
        $new = clone $this;
372 1
        $new->headerClass = $value;
373
374 1
        return $new;
375
    }
376
377
    /**
378
     * Returns a new instance with the specified modal card title class.
379
     *
380
     * @param string $value The modal card title class.
381
     *
382
     * @return self
383
     */
384 1
    public function titleClass(string $value): self
385
    {
386 1
        $new = clone $this;
387 1
        $new->titleClass = $value;
388
389 1
        return $new;
390
    }
391
392
    /**
393
     * Returns a new instance with the specified title content.
394
     *
395
     * @param string $value The title content in the modal window.
396
     *
397
     * @return self
398
     */
399 16
    public function title(string $value): self
400
    {
401 16
        $new = clone $this;
402 16
        $new->title = $value;
403
404 16
        return $new;
405
    }
406
407
    /**
408
     * Returns a new instance with the specified title attributes.
409
     *
410
     * @param array $value The title attributes.
411
     *
412
     * {@see Html::renderTagAttributes()} for details on how attributes are being rendered.
413
     *
414
     * @return self
415
     */
416 2
    public function titleAttributes(array $value): self
417
    {
418 2
        $new = clone $this;
419 2
        $new->titleAttributes = $value;
420
421 2
        return $new;
422
    }
423
424
    /**
425
     * Returns a new instance with the specified toggle button attributes.
426
     *
427
     * @param array $value The toggle button attributes.
428
     *
429
     * {@see Html::renderTagAttributes()} for details on how attributes are being rendered.
430
     *
431
     * @return self
432
     */
433 2
    public function toggleButtonAttributes(array $value): self
434
    {
435 2
        $new = clone $this;
436 2
        $new->toggleButtonAttributes = $value;
437
438 2
        return $new;
439
    }
440
441
    /**
442
     * Returns a new instance with the specified toggle button color.
443
     *
444
     * @param string $value The toggle button color. By default there's no color set.
445
     * Possible values are: ModalCard::COLOR_PRIMARY, ModalCard::COLOR_INFO, ModalCard::COLOR_SUCCESS,
446
     * ModalCard::COLOR_WARNING, ModalCard::COLOR_DANGER, ModalCard::COLOR_DARK
447
     *
448
     * @return self
449
     */
450 3
    public function toggleButtonColor(string $value): self
451
    {
452 3
        if (!in_array($value, self::COLOR_ALL, true)) {
453 1
            $values = implode('", "', self::COLOR_ALL);
454 1
            throw new InvalidArgumentException("Invalid color. Valid values are: \"$values\".");
455
        }
456
457 2
        $new = clone $this;
458 2
        $new->toggleButtonColor = $value;
459
460 2
        return $new;
461
    }
462
463
    /**
464
     * Returns a new instance with the specified ID of the toggle button.
465
     *
466
     * @param string|null $value The ID of the widget.
467
     *
468
     * @return self
469
     */
470 1
    public function toggleButtonId(?string $value): self
471
    {
472 1
        $new = clone $this;
473 1
        $new->toggleButtonAttributes['id'] = $value;
474 1
        return $new;
475
    }
476
477
    /**
478
     * Returns a new instance with the specified toggle button label.
479
     *
480
     * @param string $value The toggle button label.
481
     *
482
     * @return self
483
     */
484 2
    public function toggleButtonLabel(string $value): self
485
    {
486 2
        $new = clone $this;
487 2
        $new->toggleButtonLabel = $value;
488
489 2
        return $new;
490
    }
491
492
    /**
493
     * Returns a new instance with the specified toggle button size.
494
     *
495
     * @param string $value The toggle button size.
496
     *
497
     * @return self
498
     */
499 3
    public function toggleButtonSize(string $value): self
500
    {
501 3
        if (!in_array($value, self::SIZE_ALL, true)) {
502 1
            $values = implode('", "', self::SIZE_ALL);
503 1
            throw new InvalidArgumentException("Invalid size. Valid values are: \"$values\".");
504
        }
505
506 2
        $new = clone $this;
507 2
        $new->toggleButtonSize = $value;
508
509 2
        return $new;
510
    }
511
512
    /**
513
     * Returns a new instance with the specified options for rendering the close button tag.
514
     *
515
     * @param bool $value Whether the close button is disabled.
516
     *
517
     * @return self
518
     */
519 2
    public function withoutCloseButton(bool $value): self
520
    {
521 2
        $new = clone $this;
522 2
        $new->withoutCloseButton = $value;
523
524 2
        return $new;
525
    }
526
527
    /**
528
     * Returns a new instance with the disabled toggle button.
529
     *
530
     * @param bool $value Whether the toggle button is disabled.
531
     *
532
     * @return self
533
     */
534 2
    public function withoutToggleButton(bool $value): self
535
    {
536 2
        $new = clone $this;
537 2
        $new->withoutToggleButton = $value;
538
539 2
        return $new;
540
    }
541
542 15
    public function begin(): ?string
543
    {
544 15
        parent::begin();
545
546 15
        $attributes = $this->attributes;
547 15
        $cardAttributes = $this->cardAttributes;
548 15
        $html = '';
549
550 15
        if (!array_key_exists('id', $attributes)) {
551 15
            $attributes['id'] = Html::generateId($this->autoIdPrefix) . '-modal';
552
        }
553
554
        /** @var string */
555 15
        $id = $attributes['id'];
556
557 15
        if ($this->withoutToggleButton === false) {
558 14
            $html .= $this->renderToggleButton($id) . "\n";
559
        }
560
561 15
        Html::addCssClass($attributes, $this->cardClass);
562 15
        Html::addCssClass($cardAttributes, $this->contentClass);
563
564 15
        $html .= Html::openTag('div', $attributes) . "\n"; // .modal
565 15
        $html .= $this->renderBackgroundTransparentOverlay() . "\n"; // .modal-background
566 15
        $html .= Html::openTag('div', $cardAttributes) . "\n"; // .modal-card
567 15
        $html .= $this->renderHeader();
568 15
        $html .= $this->renderBodyBegin() . "\n";
569
570 15
        return $html;
571
    }
572
573 15
    protected function run(): string
574
    {
575 15
        $html = $this->renderBodyEnd() . "\n";
576 15
        $html .= $this->renderFooter() . "\n";
577 15
        $html .= Html::closeTag('div') . "\n"; // .modal-card
578 15
        $html .= Html::closeTag('div'); // .modal
579
580 15
        return $html;
581
    }
582
583
    /**
584
     * Renders the background transparent overlay.
585
     *
586
     * @return string
587
     */
588 15
    private function renderBackgroundTransparentOverlay(): string
589
    {
590 15
        return Div::tag()->class($this->backgroundClass)->render();
591
    }
592
593
    /**
594
     * Renders begin body tag.
595
     *
596
     * @return string
597
     */
598 15
    private function renderBodyBegin(): string
599
    {
600 15
        $bodyAttributes = $this->bodyAttributes;
601
602 15
        Html::addCssClass($bodyAttributes, $this->bodyClass);
603
604 15
        return Html::openTag('section', $bodyAttributes);
605
    }
606
607
    /**
608
     * Renders end body tag.
609
     *
610
     * @return string
611
     */
612 15
    private function renderBodyEnd(): string
613
    {
614 15
        return Html::closeTag('section');
615
    }
616
617
    /**
618
     * Renders the close button.
619
     *
620
     * @return string
621
     */
622 14
    private function renderCloseButton(): string
623
    {
624 14
        $closeButtonAttributes = $this->closeButtonAttributes;
625 14
        $closeButtonAttributes['aria-label'] = 'close';
626
627 14
        Html::addCssClass($closeButtonAttributes, $this->closeButtonClass);
628
629 14
        if ($this->closeButtonSize !== '') {
630 1
            Html::addCssClass($closeButtonAttributes, $this->closeButtonSize);
631
        }
632
633 14
        return Button::tag()->attributes($closeButtonAttributes)->render() . PHP_EOL;
634
    }
635
636
    /**
637
     * Renders the footer.
638
     *
639
     * @return string
640
     */
641 15
    private function renderFooter(): string
642
    {
643 15
        $footer = $this->footer;
644 15
        $footerAttributes = $this->footerAttributes;
645
646 15
        if ($footer !== '') {
647 15
            $footer = PHP_EOL . $footer . PHP_EOL;
648
        }
649
650 15
        Html::addCssClass($footerAttributes, $this->footerClass);
651
652 15
        return CustomTag::name('footer')->attributes($footerAttributes)->content($footer)->encode(false)->render();
653
    }
654
655
    /**
656
     * Renders header.
657
     *
658
     * @return string
659
     */
660 15
    private function renderHeader(): string
661
    {
662 15
        $content = '';
663 15
        $headerAttributes = $this->headerAttributes;
664 15
        $titleAttributes = $this->titleAttributes;
665
666 15
        Html::addCssClass($headerAttributes, $this->headerClass);
667 15
        Html::addCssClass($titleAttributes, $this->titleClass);
668
669 15
        $content .= P::tag()->attributes($titleAttributes)->content($this->title)->render() . PHP_EOL;
670
671 15
        if ($this->withoutCloseButton === false) {
672 14
            $content .= $this->renderCloseButton();
673
        }
674
675 15
        return CustomTag::name('header')
676 15
            ->attributes($headerAttributes)
677 15
            ->content(PHP_EOL . $content)
678 15
            ->encode(false)
679 15
            ->render() . PHP_EOL;
680
    }
681
682
    /**
683
     * Renders the toggle button.
684
     *
685
     * @param string $id
686
     *
687
     * @return string
688
     */
689 14
    private function renderToggleButton(string $id): string
690
    {
691 14
        $toggleButtonAttributes = $this->toggleButtonAttributes;
692
693 14
        if (!array_key_exists('id', $toggleButtonAttributes)) {
694 14
            $toggleButtonAttributes['id'] = Html::generateId($this->autoIdPrefix) . '-button';
695
        }
696
697 14
        $toggleButtonAttributes['data-target'] = '#' . $id;
698 14
        $toggleButtonAttributes['aria-haspopup'] = 'true';
699
700 14
        if ($this->toggleButtonSize !== '') {
701 1
            Html::addCssClass($toggleButtonAttributes, $this->toggleButtonSize);
702
        }
703
704 14
        if ($this->toggleButtonColor !== '') {
705 1
            Html::addCssClass($toggleButtonAttributes, $this->toggleButtonColor);
706
        }
707
708 14
        Html::addCssClass($toggleButtonAttributes, $this->buttonClass);
709
710 14
        return Button::tag()->attributes($toggleButtonAttributes)->content($this->toggleButtonLabel)->render();
711
    }
712
}
713