Passed
Pull Request — master (#127)
by Sergei
02:52
created

Collapse::renderCollapse()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 5
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 8
ccs 6
cts 6
cp 1
crap 1
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Yii\Bootstrap5;
6
7
use Stringable;
8
use Yiisoft\Arrays\ArrayHelper;
9
use Yiisoft\Html\Html;
10
use function array_key_exists;
11
12
/**
13
 * Collapse renders an collapse bootstrap JavaScript component.
14
 *
15
 * For example
16
 *
17
 * $collapse =Collapse::widget()
18
 *      ->withTitle('Foo')
19
 *      ->withContent('Bar');
20
 *
21
 * echo $collapse->render();
22
 *
23
 * Or
24
 *
25
 * $collapse = $collapse->withToggle(false);
26
 *
27
 * echo '<p>' . $collapse->renderToggle() . '</p><div>Some other content</div>' . $collapse->render();
28
 */
29
final class Collapse extends AbstractToggleWidget
30
{
31
    private array $options = [];
32
    private array $bodyOptions = [
33
        'tag' => 'div',
34
    ];
35
    private string|Stringable $content = '';
36
    private bool $horizontal = false;
37
    private bool $collapsed = false;
38
    private ?string $tagName = null;
39
40 40
    public function getId(?string $suffix = '-collapse'): ?string
41
    {
42 40
        return $this->options['id'] ?? parent::getId($suffix);
43
    }
44
45 40
    protected function bsToggle(): string
46
    {
47 40
        return 'collapse';
48
    }
49
50 33
    public function withOptions(array $options): self
51
    {
52 33
        $new = clone $this;
53 33
        $new->options = $options;
54
55 33
        return $new;
56
    }
57
58 34
    public function withBodyOptions(array $options): self
59
    {
60 34
        $new = clone $this;
61 34
        $new->bodyOptions = $options;
62
63 34
        if (!array_key_exists('tag', $this->bodyOptions)) {
64
            $this->bodyOptions['tag'] = 'div';
65
        }
66
67 34
        return $new;
68
    }
69
70 17
    public function withContent(string|Stringable $content): self
71
    {
72 17
        $new = clone $this;
73 17
        $new->content = $content;
74
75 17
        return $new;
76
    }
77
78 2
    public function withHorizontal(bool $horizontal): self
79
    {
80 2
        $new = clone $this;
81 2
        $new->horizontal = $horizontal;
82
83 2
        return $new;
84
    }
85
86 11
    public function withCollapsed(bool $collapsed): self
87
    {
88 11
        $new = clone $this;
89 11
        $new->collapsed = $collapsed;
90
91 11
        return $new;
92
    }
93
94 39
    private function prepareOptions(): array
95
    {
96 39
        $options = $this->options;
97 39
        $options['id'] = $this->getId();
98
99 39
        $classNames = [
100 39
            'widget' => 'collapse',
101 39
        ];
102
103 39
        if ($this->horizontal) {
104 2
            $classNames[] = 'collapse-horizontal';
105
        }
106
107 39
        if ($this->collapsed) {
108 7
            $classNames[] = 'show';
109
        }
110
111 39
        Html::addCssClass($options, $classNames);
112
113 39
        return $options;
114
    }
115
116 39
    private function prepareBodyOptions(): array
117
    {
118 39
        $options = $this->bodyOptions;
119 39
        Html::addCssClass($options, ['widget' => 'card card-body']);
120
121 39
        return $options;
122
    }
123
124 40
    protected function prepareToggleOptions(): array
125
    {
126 40
        [$tagName, $options, $encode] = parent::prepareToggleOptions();
127
128 40
        $options['aria-expanded'] = $this->collapsed ? 'true' : 'false';
129
130 40
        return [$tagName, $options, $encode];
131
    }
132
133 22
    public function begin(): ?string
134
    {
135 22
        parent::begin();
136
137 22
        $options = $this->prepareOptions();
138 22
        $bodyOptions = $this->prepareBodyOptions();
139 22
        $this->tagName = ArrayHelper::remove($options, 'tag', 'div');
140 22
        $html = $this->renderToggle ? $this->renderToggle() : '';
141 22
        $html .= Html::openTag($this->tagName, $options);
0 ignored issues
show
Bug introduced by
It seems like $this->tagName can also be of type null; however, parameter $name of Yiisoft\Html\Html::openTag() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

141
        $html .= Html::openTag(/** @scrutinizer ignore-type */ $this->tagName, $options);
Loading history...
142
143 22
        if ($bodyTag = ArrayHelper::remove($bodyOptions, 'tag')) {
144 1
            $html .= Html::openTag($bodyTag, $bodyOptions);
145
        }
146
147 22
        return $html;
148
    }
149
150
    /**
151
     * @inheritDoc
152
     */
153 39
    public function render(): string
154
    {
155 39
        if ($tagName = $this->tagName) {
156 22
            $this->tagName = null;
157
158 22
            if (isset($this->bodyOptions['tag'])) {
159 1
                return Html::closeTag($this->bodyOptions['tag']) . Html::closeTag($tagName);
160
            }
161
162 21
            return Html::closeTag($tagName);
163
        }
164
165 17
        if ($this->renderToggle) {
166 5
            return $this->renderToggle() . $this->renderCollapse();
167
        }
168
169 12
        return $this->renderCollapse();
170
    }
171
172 17
    private function renderCollapse(): string
173
    {
174 17
        $options = $this->prepareOptions();
175 17
        $tagName = ArrayHelper::remove($options, 'tag', 'div');
176
177 17
        return Html::tag($tagName, $this->renderBody(), $options)
178 17
            ->encode(false)
179 17
            ->render();
180
    }
181
182 17
    private function renderBody(): string
183
    {
184 17
        $options = $this->prepareBodyOptions();
185 17
        $tagName = ArrayHelper::remove($options, 'tag', 'div');
186 17
        $encode = ArrayHelper::remove($options, 'encode');
187
188 17
        if ($tagName === null) {
189 1
            return $encode ? Html::encode($this->content) : (string) $this->content;
190
        }
191
192 16
        return Html::tag($tagName, $this->content, $options)
193 16
            ->encode($encode)
194 16
            ->render();
195
    }
196
}
197