Test Failed
Pull Request — master (#32)
by Sergei
03:07
created

NavBar::itemsOptions()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 3
c 0
b 0
f 0
nc 1
nop 1
dl 0
loc 5
ccs 0
cts 0
cp 0
crap 2
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Yii\Bulma;
6
7
use InvalidArgumentException;
8
use JsonException;
9
use Yiisoft\Arrays\ArrayHelper;
10
use Yiisoft\Html\Html;
11
12
use function strpos;
13
14
/**
15
 * The navbar component is a responsive and versatile horizontal navigation bar.
16
 *
17
 * @link https://bulma.io/documentation/components/navbar/
18
 */
19
final class NavBar extends Widget
20
{
21
    private string $brand = '';
22
    private string $brandLabel = '';
23
    private string $brandImage = '';
24
    private string $brandUrl = '/';
25
    private string $toggleIcon = '';
26
    private array $options = [];
27
    private array $brandOptions = [];
28
    private array $brandLabelOptions = [];
29
    private array $brandImageOptions = [];
30
    private array $itemsOptions = [];
31
    private array $menuOptions = [];
32
    private array $toggleOptions = [
33
        'aria-expanded' => 'false',
34
        'aria-label' => 'menu',
35
        'class' => 'navbar-burger',
36
        'role' => 'button',
37
    ];
38
    private bool $encodeTags = false;
39
40 17
    public function begin(): ?string
41
    {
42 17
        parent::begin();
43
44 17
        $this->buildOptions();
45 17
        $this->renderBrand();
46
47 17
        $navOptions = $this->options;
48 17
        $navTag = ArrayHelper::remove($navOptions, 'tag', 'nav');
49
        $this->checkNavTag($navTag);
50 17
51 1
        return
52
            (is_string($navTag) ? Html::openTag($navTag, $navOptions) : '') . "\n" .
0 ignored issues
show
Bug introduced by
The method openTag() does not exist on Yiisoft\Html\Html. ( Ignorable by Annotation )

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

52
            (is_string($navTag) ? Html::/** @scrutinizer ignore-call */ openTag($navTag, $navOptions) : '') . "\n" .

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
53
            $this->brand . "\n" .
54
            Html::openTag('div', $this->menuOptions) .
55 16
            Html::openTag('div', $this->itemsOptions);
56 16
    }
57 16
58 16
    protected function run(): string
59
    {
60
        $tag = ArrayHelper::remove($this->options, 'tag', 'nav');
61 17
        $this->checkNavTag($tag);
62
63 17
        return
64 17
            Html::closeTag('div') . "\n" .
0 ignored issues
show
Bug introduced by
The method closeTag() does not exist on Yiisoft\Html\Html. ( Ignorable by Annotation )

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

64
            Html::/** @scrutinizer ignore-call */ 
65
                  closeTag('div') . "\n" .

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
65 1
            Html::closeTag('div') . "\n" .
66
            (is_string($tag) ? Html::closeTag($tag) : '');
67
    }
68
69 16
    /**
70 16
     * @param mixed $navTag
71 16
     */
72
    private function checkNavTag($navTag): void
73
    {
74
        if (
75
            (!is_string($navTag) || $navTag === '') &&
76
            !is_bool($navTag) &&
77
            $navTag !== null
78
        ) {
79
            throw new InvalidArgumentException('Tag should be either non empty string, bool or null.');
80
        }
81 1
    }
82
83 1
    /**
84 1
     * Set render brand custom, {@see brandLabel} and {@see brandImage} are not generated.
85 1
     *
86
     * @param string $value
87
     *
88
     * @return self
89
     */
90
    public function brand(string $value): self
91
    {
92
        $new = clone $this;
93
        $new->brand = $value;
94
        return $new;
95 15
    }
96
97 15
    /**
98 15
     * The text of the brand label or empty if it's not used. Note that this is not HTML-encoded.
99 15
     *
100
     * @param string $value
101
     *
102
     * @return self
103
     */
104
    public function brandLabel(string $value): self
105
    {
106
        $new = clone $this;
107
        $new->brandLabel = $value;
108
        return $new;
109 14
    }
110
111 14
    /**
112 14
     * The image of the brand or empty if it's not used.
113 14
     *
114
     * @param string $value
115
     *
116
     * @return self
117
     */
118
    public function brandImage(string $value): self
119
    {
120
        $new = clone $this;
121
        $new->brandImage = $value;
122
        return $new;
123
    }
124 13
125
    /**
126 13
     * The URL for the brand's hyperlink tag and will be used for the "href" attribute of the brand link. Default value
127 13
     * is '/' will be used. You may set it to `null` if you want to have no link at all.
128 13
     *
129
     * @param string $value
130
     *
131
     * @return self
132
     */
133
    public function brandUrl(string $value): self
134
    {
135
        $new = clone $this;
136
        $new->brandUrl = $value;
137
        return $new;
138 1
    }
139
140 1
    /**
141 1
     * Set toggle icon.
142 1
     *
143
     * @param string $value .
144
     *
145
     * @return self
146
     */
147
    public function toggleIcon(string $value): self
148
    {
149
        $new = clone $this;
150
        $new->toggleIcon = $value;
151
        return $new;
152
    }
153
154 5
    /**
155
     * Options HTML attributes for the tag nav.
156 5
     *
157 5
     * @param array $value
158 5
     *
159
     * @return self
160
     *
161
     * {@see Html::renderTagAttributes()} for details on how attributes are being rendered.
162
     */
163
    public function options(array $value): self
164
    {
165
        $new = clone $this;
166
        $new->options = $value;
167
        return $new;
168
    }
169
170 1
    /**
171
     * Options HTML attributes of the tag div brand.
172 1
     *
173 1
     * @param array $value default value `navbar-item`.
174 1
     *
175
     * @return self
176
     *
177
     * {@see Html::renderTagAttributes()} for details on how attributes are being rendered.
178
     */
179
    public function brandOptions(array $value): self
180
    {
181
        $new = clone $this;
182
        $new->brandOptions = $value;
183
        return $new;
184
    }
185
186 1
    /**
187
     * Options HTML attributes of the tag div brand label.
188 1
     *
189 1
     * @param array $value default value `navbar-item`.
190 1
     *
191
     * @return self
192
     *
193
     * {@see Html::renderTagAttributes()} for details on how attributes are being rendered.
194
     */
195
    public function brandLabelOptions(array $value): self
196
    {
197
        $new = clone $this;
198
        $new->brandLabelOptions = $value;
199
        return $new;
200
    }
201
202 1
    /**
203
     * Options HTML attributes of the tag div brand link.
204 1
     *
205 1
     * @param array $value default value `navbar-item`.
206 1
     *
207
     * @return self
208
     *
209
     * {@see Html::renderTagAttributes()} for details on how attributes are being rendered.
210
     */
211
    public function brandImageOptions(array $value): self
212
    {
213
        $new = clone $this;
214
        $new->brandImageOptions = $value;
215
        return $new;
216
    }
217
218 3
    /**
219
     * Options HTML attributes of the tag div items nav, values `navbar-start`, `navbar-end`.
220 3
     *
221 3
     * @param array $value default value `navbar-start`.
222 3
     *
223
     * @return self
224
     *
225
     * {@see Html::renderTagAttributes()} for details on how attributes are being rendered.
226
     */
227
    public function itemsOptions(array $value): self
228
    {
229
        $new = clone $this;
230
        $new->itemsOptions = $value;
231
        return $new;
232
    }
233
234 1
    /**
235
     * Options HTML attributes of the tag div nav menu.
236 1
     *
237 1
     * @param array $value default value `navbar-menu`.
238 1
     *
239
     * @return self
240
     *
241
     * {@see Html::renderTagAttributes()} for details on how attributes are being rendered.
242
     */
243
    public function menuOptions(array $value): self
244
    {
245
        $new = clone $this;
246
        $new->menuOptions = $value;
247
        return $new;
248
    }
249
250 1
    /**
251
     * The HTML attributes of the navbar toggler button.
252 1
     *
253 1
     * @param array $value
254 1
     *
255
     * @return self
256
     *
257 17
     * {@see Html::renderTagAttributes()} for details on how attributes are being rendered.
258
     */
259 17
    public function toggleOptions(array $value): self
260
    {
261 17
        $new = clone $this;
262 17
        $new->toggleOptions = $value;
263 17
        return $new;
264
    }
265
266 17
    private function buildOptions(): void
267 17
    {
268 17
        $id = '';
269 17
270 17
        if (!isset($this->options['id'])) {
271
            $id = $this->getId();
272 17
            $this->options['id'] = "{$id}-navbar";
273 17
        }
274
275
        $this->options = $this->addOptions($this->options, 'navbar');
276 17
        $this->brandOptions = $this->addOptions($this->brandOptions, 'navbar-brand');
277
        $this->brandLabelOptions = $this->addOptions($this->brandLabelOptions, 'navbar-item');
278 17
        $this->brandImageOptions = $this->addOptions($this->brandImageOptions, 'navbar-item');
279 17
        $this->menuOptions = $this->addOptions($this->menuOptions, 'navbar-menu');
280
281 17
        $this->menuOptions['id'] = "{$id}-navbar-Menu";
282
283 17
        $this->initItemsOptions();
284
    }
285 17
286 3
    private function initItemsOptions(): void
287 3
    {
288
        $itemsClass = '';
289 3
290 1
        if (isset($this->itemsOptions['class'])) {
291
            $itemsClass = $this->itemsOptions['class'];
292
            unset($this->itemsOptions['class']);
293
294
            if (is_array($itemsClass)) {
295 17
                $itemsClass = implode(' ', $itemsClass);
296 16
            }
297
        }
298
299 17
        /** @var string $itemsClass */
300 3
        if (strpos($itemsClass, 'navbar-end') === false) {
301
            Html::addCssClass($this->itemsOptions, 'navbar-start');
302 17
        }
303
304 17
        if (!empty($itemsClass)) {
305
            Html::addCssClass($this->itemsOptions, $itemsClass);
306 17
        }
307 16
    }
308
309 16
    private function renderBrand(): void
310 13
    {
311
        if ($this->brand === '') {
312
            $this->brand = Html::openTag('div', $this->brandOptions);
313 16
314 1
            if ($this->brandImage !== '' && $this->brandLabel !== '') {
315
                $this->brand .= Html::tag(
316
                    'span',
317 16
                    Html::img($this->brandImage)->render(),
318 14
                    $this->brandImageOptions
319
                )->encode($this->encodeTags);
320
            }
321 16
322 16
            if ($this->brandImage !== '' && $this->brandLabel === '') {
323
                $this->brand .= Html::a(
324 17
                    Html::img($this->brandImage)->render(),
325
                    $this->brandUrl,
326
                    $this->brandImageOptions
327
                )->encode($this->encodeTags);
328
            }
329
330
            if ($this->brandLabel !== '') {
331
                $this->brand .= Html::a($this->brandLabel, $this->brandUrl, $this->brandLabelOptions);
332
            }
333 16
334
            $this->brand .= $this->renderToggleButton();
335
            $this->brand .= Html::closeTag('div');
336 16
        }
337 16
    }
338
339 16
    /**
340
     * Renders collapsible toggle button.
341
     *
342
     * @throws JsonException
343
     *
344
     * @return string the rendering toggle button.
345
     */
346
    private function renderToggleButton(): string
347
    {
348
        return
349 16
            Html::openTag('a', $this->toggleOptions) .
350
            $this->renderToggleIcon() .
351 16
352 15
            Html::closeTag('a');
353 15
    }
354 15
355
    /**
356
     * Render icon toggle.
357 16
     *
358
     * @throws JsonException
359
     *
360
     * @return string
361
     */
362
    private function renderToggleIcon(): string
363
    {
364
        if ($this->toggleIcon === '') {
365
            $this->toggleIcon = Html::tag('span', '', ['aria-hidden' => 'true']) .
366
                Html::tag('span', '', ['aria-hidden' => 'true']) .
367
                Html::tag('span', '', ['aria-hidden' => 'true']);
368
        }
369
370
        return $this->toggleIcon;
371
    }
372
}
373