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 | |||
11 | use function array_merge; |
||
12 | |||
13 | /** |
||
14 | * Alert renders an alert bootstrap component. |
||
15 | * |
||
16 | * For example, |
||
17 | * |
||
18 | * ```php |
||
19 | * echo Alert::widget() |
||
20 | * ->options([ |
||
21 | * 'class' => 'alert-info', |
||
22 | * ]) |
||
23 | * ->body('Say hello...'); |
||
24 | * ``` |
||
25 | * |
||
26 | * @link https://getbootstrap.com/docs/5.0/components/alerts/ |
||
27 | */ |
||
28 | final class Alert extends Widget |
||
29 | { |
||
30 | use CloseButtonTrait; |
||
31 | |||
32 | private string|Stringable $body = ''; |
||
33 | private ?string $header = null; |
||
34 | private array $headerOptions = []; |
||
35 | /** @psalm-var non-empty-string */ |
||
36 | private string $headerTag = 'h4'; |
||
37 | private bool $encode = false; |
||
38 | private array $options = []; |
||
39 | private array $classNames = []; |
||
40 | private bool $fade = false; |
||
41 | |||
42 | 18 | public function getId(?string $suffix = '-alert'): ?string |
|
43 | { |
||
44 | 18 | return $this->options['id'] ?? parent::getId($suffix); |
|
0 ignored issues
–
show
|
|||
45 | } |
||
46 | |||
47 | 8 | protected function toggleComponent(): string |
|
48 | { |
||
49 | 8 | return 'alert'; |
|
50 | } |
||
51 | |||
52 | 18 | public function render(): string |
|
53 | { |
||
54 | 18 | $options = $this->prepareOptions(); |
|
55 | 18 | $tag = ArrayHelper::remove($options, 'tag', 'div'); |
|
56 | |||
57 | 18 | return Html::tag($tag, '', $options) |
|
58 | 18 | ->encode(false) |
|
59 | 18 | ->content( |
|
60 | 18 | (string) $this->renderHeader(), |
|
61 | 18 | $this->encode ? Html::encode($this->body) : $this->body, |
|
62 | 18 | (string) $this->renderCloseButton(true) |
|
63 | 18 | ) |
|
64 | 18 | ->render(); |
|
65 | } |
||
66 | |||
67 | /** |
||
68 | * The body content in the alert component. Alert widget will also be treated as the body content, and will be |
||
69 | * rendered before this. |
||
70 | */ |
||
71 | 18 | public function body(string|Stringable $value): self |
|
72 | { |
||
73 | 18 | $new = clone $this; |
|
74 | 18 | $new->body = $value; |
|
75 | |||
76 | 18 | return $new; |
|
77 | } |
||
78 | |||
79 | /** |
||
80 | * The header content in alert component |
||
81 | */ |
||
82 | 1 | public function header(?string $header): self |
|
83 | { |
||
84 | 1 | $new = clone $this; |
|
85 | 1 | $new->header = $header; |
|
86 | |||
87 | 1 | return $new; |
|
88 | } |
||
89 | |||
90 | /** |
||
91 | * The HTML attributes for the widget header tag. The following special options are recognized. |
||
92 | * |
||
93 | * {@see Html::renderTagAttributes()} for details on how attributes are being rendered. |
||
94 | */ |
||
95 | 1 | public function headerOptions(array $options): self |
|
96 | { |
||
97 | 1 | $new = clone $this; |
|
98 | 1 | $new->headerOptions = $options; |
|
99 | |||
100 | 1 | return $new; |
|
101 | } |
||
102 | |||
103 | /** |
||
104 | * Set tag name for header |
||
105 | * |
||
106 | * @psalm-param non-empty-string $tag |
||
107 | */ |
||
108 | 1 | public function headerTag(string $tag): self |
|
109 | { |
||
110 | 1 | $new = clone $this; |
|
111 | 1 | $new->headerTag = $tag; |
|
112 | |||
113 | 1 | return $new; |
|
114 | } |
||
115 | |||
116 | /** |
||
117 | * The HTML attributes for the widget container tag. The following special options are recognized. |
||
118 | * |
||
119 | * {@see Html::renderTagAttributes()} for details on how attributes are being rendered. |
||
120 | */ |
||
121 | 3 | public function options(array $value): self |
|
122 | { |
||
123 | 3 | $new = clone $this; |
|
124 | 3 | $new->options = $value; |
|
125 | |||
126 | 3 | return $new; |
|
127 | } |
||
128 | |||
129 | /** |
||
130 | * Enable/Disable encode body |
||
131 | */ |
||
132 | public function encode(bool $encode = true): self |
||
133 | { |
||
134 | $new = clone $this; |
||
135 | $new->encode = $encode; |
||
136 | |||
137 | return $new; |
||
138 | } |
||
139 | |||
140 | /** |
||
141 | * Enable/Disable dissmiss animation |
||
142 | */ |
||
143 | 2 | public function fade(bool $fade = true): self |
|
144 | { |
||
145 | 2 | $new = clone $this; |
|
146 | 2 | $new->fade = $fade; |
|
147 | |||
148 | 2 | return $new; |
|
149 | } |
||
150 | |||
151 | /** |
||
152 | * Set type of alert, 'alert-success', 'alert-danger', 'custom-alert' etc |
||
153 | */ |
||
154 | 9 | public function addClassNames(string ...$classNames): self |
|
155 | { |
||
156 | 9 | $new = clone $this; |
|
157 | 9 | $new->classNames = array_filter($classNames, static fn ($name) => $name !== ''); |
|
158 | |||
159 | 9 | return $new; |
|
160 | } |
||
161 | |||
162 | /** |
||
163 | * Short method for primary alert type |
||
164 | */ |
||
165 | 1 | public function primary(): self |
|
166 | { |
||
167 | 1 | return $this->addClassNames('alert-primary'); |
|
168 | } |
||
169 | |||
170 | /** |
||
171 | * Short method for secondary alert type |
||
172 | */ |
||
173 | 1 | public function secondary(): self |
|
174 | { |
||
175 | 1 | return $this->addClassNames('alert-secondary'); |
|
176 | } |
||
177 | |||
178 | /** |
||
179 | * Short method for success alert type |
||
180 | */ |
||
181 | 1 | public function success(): self |
|
182 | { |
||
183 | 1 | return $this->addClassNames('alert-success'); |
|
184 | } |
||
185 | |||
186 | /** |
||
187 | * Short method for danger alert type |
||
188 | */ |
||
189 | 1 | public function danger(): self |
|
190 | { |
||
191 | 1 | return $this->addClassNames('alert-danger'); |
|
192 | } |
||
193 | |||
194 | /** |
||
195 | * Short method for warning alert type |
||
196 | */ |
||
197 | 1 | public function warning(): self |
|
198 | { |
||
199 | 1 | return $this->addClassNames('alert-warning'); |
|
200 | } |
||
201 | |||
202 | /** |
||
203 | * Short method for info alert type |
||
204 | */ |
||
205 | 1 | public function info(): self |
|
206 | { |
||
207 | 1 | return $this->addClassNames('alert-info'); |
|
208 | } |
||
209 | |||
210 | /** |
||
211 | * Short method for light alert type |
||
212 | */ |
||
213 | 1 | public function light(): self |
|
214 | { |
||
215 | 1 | return $this->addClassNames('alert-light'); |
|
216 | } |
||
217 | |||
218 | /** |
||
219 | * Short method for dark alert type |
||
220 | */ |
||
221 | 1 | public function dark(): self |
|
222 | { |
||
223 | 1 | return $this->addClassNames('alert-dark'); |
|
224 | } |
||
225 | |||
226 | /** |
||
227 | * Render header tag |
||
228 | */ |
||
229 | 18 | private function renderHeader(): ?string |
|
230 | { |
||
231 | 18 | if ($this->header === null) { |
|
232 | 17 | return null; |
|
233 | } |
||
234 | |||
235 | 1 | $options = $this->headerOptions; |
|
236 | 1 | $encode = ArrayHelper::remove($options, 'encode', true); |
|
237 | |||
238 | 1 | Html::addCssClass($options, ['alert-heading']); |
|
239 | |||
240 | 1 | return Html::tag($this->headerTag, $this->header, $options) |
|
241 | 1 | ->encode($encode) |
|
242 | 1 | ->render(); |
|
243 | } |
||
244 | |||
245 | /** |
||
246 | * Prepare the widget options. |
||
247 | * |
||
248 | * This method returns the default values for various options. |
||
249 | */ |
||
250 | 18 | private function prepareOptions(): array |
|
251 | { |
||
252 | 18 | $options = $this->options; |
|
253 | 18 | $options['id'] = $this->getId(); |
|
254 | 18 | $classNames = array_merge(['alert'], $this->classNames); |
|
255 | |||
256 | 18 | if ($this->showCloseButton) { |
|
257 | 8 | $classNames[] = 'alert-dismissible'; |
|
258 | } |
||
259 | |||
260 | 18 | if ($this->fade) { |
|
261 | 2 | $classNames[] = 'fade show'; |
|
262 | } |
||
263 | |||
264 | 18 | Html::addCssClass($options, $classNames); |
|
265 | |||
266 | 18 | if (!isset($options['role'])) { |
|
267 | 18 | $options['role'] = 'alert'; |
|
268 | } |
||
269 | |||
270 | 18 | return $options; |
|
271 | } |
||
272 | } |
||
273 |
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.
If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.