GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Pull Request — master (#74)
by
unknown
01:40
created

Menu::setExactActive()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 6
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
1
<?php
2
3
namespace Spatie\Menu;
4
5
use Countable;
6
use Spatie\Menu\Html\Tag;
7
use Spatie\Menu\Html\Attributes;
8
use Spatie\Menu\Helpers\Reflection;
9
use Spatie\Menu\Traits\Conditions as ConditionsTrait;
10
use Spatie\Menu\Traits\HasTextAttributes as HasAttributesTrait;
11
use Spatie\Menu\Traits\HasHtmlAttributes as HasHtmlAttributesTrait;
12
use Spatie\Menu\Traits\HasParentAttributes as HasParentAttributesTrait;
13
14
class Menu implements Item, Countable, HasHtmlAttributes, HasParentAttributes
15
{
16
    use HasHtmlAttributesTrait, HasParentAttributesTrait, ConditionsTrait, HasAttributesTrait;
17
18
    /** @var array */
19
    protected $items = [];
20
21
    /** @var array */
22
    protected $filters = [];
23
24
    /** @var string */
25
    protected $prepend, $append = '';
26
27
    /** @var array */
28
    protected $wrap = [];
29
30
    /** @var string */
31
    protected $activeClass = 'active';
32
33
    /** @var string */
34
    protected $exactActiveClass = 'exact-active';
35
36
    /** @var string */
37
    protected $wrapperTagName = 'ul';
38
39
    /** @var bool */
40
    protected $parentTagName = 'li';
41
42
    /** @var bool */
43
    protected $activeClassOnParent = true;
44
45
    /** @var bool */
46
    protected $activeClassOnLink = false;
47
48
    /** @var bool */
49
    protected $exactActive = false;
50
51
    /** @var \Spatie\Menu\Html\Attributes */
52
    protected $htmlAttributes, $parentAttributes;
53
54
    protected function __construct(Item ...$items)
55
    {
56
        $this->items = $items;
57
58
        $this->htmlAttributes = new Attributes();
59
        $this->parentAttributes = new Attributes();
60
    }
61
62
    /**
63
     * Create a new menu, optionally prefilled with items.
64
     *
65
     * @param array $items
66
     *
67
     * @return static
68
     */
69
    public static function new($items = [])
70
    {
71
        return new static(...array_values($items));
72
    }
73
74
    /**
75
     * Build a new menu from an array. The callback receives a menu instance as
76
     * the accumulator, the array item as the second parameter, and the item's
77
     * key as the third.
78
     *
79
     * @param array|\Iterator $items
80
     * @param callable $callback
81
     * @param \Spatie\Menu\Menu|null $initial
82
     *
83
     * @return static
84
     */
85
    public static function build($items, callable $callback, self $initial = null)
86
    {
87
        return ($initial ?: static::new())->fill($items, $callback);
88
    }
89
90
    /**
91
     * Fill a menu from an array. The callback receives a menu instance as
92
     * the accumulator, the array item as the second parameter, and the item's
93
     * key as the third.
94
     *
95
     * @param array|\Iterator $items
96
     * @param callable $callback
97
     *
98
     * @return static
99
     */
100
    public function fill($items, callable $callback)
101
    {
102
        $menu = $this;
103
104
        foreach ($items as $key => $item) {
105
            $menu = $callback($menu, $item, $key) ?: $menu;
106
        }
107
108
        return $menu;
109
    }
110
111
    /**
112
     * Add an item to the menu. This also applies all registered filters to the
113
     * item.
114
     *
115
     * @param \Spatie\Menu\Item $item
116
     *
117
     * @return $this
118
     */
119
    public function add(Item $item)
120
    {
121
        foreach ($this->filters as $filter) {
122
            $this->applyFilter($filter, $item);
123
        }
124
125
        $this->items[] = $item;
126
127
        return $this;
128
    }
129
130
    /**
131
     * Add an item to the menu if a (non-strict) condition is met.
132
     *
133
     * @param bool $condition
134
     * @param \Spatie\Menu\Item $item
135
     *
136
     * @return $this
137
     */
138
    public function addIf($condition, Item $item)
139
    {
140
        if ($this->resolveCondition($condition)) {
141
            $this->add($item);
142
        }
143
144
        return $this;
145
    }
146
147
    /**
148
     * Shortcut function to add a plain link to the menu.
149
     *
150
     * @param string $url
151
     * @param string $text
152
     *
153
     * @return $this
154
     */
155
    public function link(string $url, string $text)
156
    {
157
        return $this->add(Link::to($url, $text));
158
    }
159
160
    /**
161
     * Shortcut function to add an empty item to the menu.
162
     *
163
     * @return $this
164
     */
165
    public function empty()
166
    {
167
        return $this->add(Html::empty());
168
    }
169
170
    /**
171
     * Add a link to the menu if a (non-strict) condition is met.
172
     *
173
     * @param bool $condition
174
     * @param string $url
175
     * @param string $text
176
     *
177
     * @return $this
178
     */
179
    public function linkIf($condition, string $url, string $text)
180
    {
181
        if ($this->resolveCondition($condition)) {
182
            $this->link($url, $text);
183
        }
184
185
        return $this;
186
    }
187
188
    /**
189
     * Shortcut function to add raw html to the menu.
190
     *
191
     * @param string $html
192
     * @param array $parentAttributes
193
     *
194
     * @return $this
195
     */
196
    public function html(string $html, array $parentAttributes = [])
197
    {
198
        return $this->add(Html::raw($html)->setParentAttributes($parentAttributes));
199
    }
200
201
    /**
202
     * Add a chunk of html if a (non-strict) condition is met.
203
     *
204
     * @param bool $condition
205
     * @param string $html
206
     * @param array $parentAttributes
207
     *
208
     * @return $this
209
     */
210
    public function htmlIf($condition, string $html, array $parentAttributes = [])
211
    {
212
        if ($this->resolveCondition($condition)) {
213
            $this->html($html, $parentAttributes);
214
        }
215
216
        return $this;
217
    }
218
219
    /**
220
     * @param callable|\Spatie\Menu\Menu|\Spatie\Menu\Item $header
221
     * @param callable|\Spatie\Menu\Menu|null $menu
222
     *
223
     * @return $this
224
     */
225
    public function submenu($header, $menu = null)
0 ignored issues
show
Unused Code introduced by
The parameter $header is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $menu is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
226
    {
227
        list($header, $menu) = $this->parseSubmenuArgs(func_get_args());
228
229
        $menu = $this->createSubmenuMenu($menu);
230
        $header = $this->createSubmenuHeader($header);
231
232
        return $this->add($menu->prependIf($header, $header));
0 ignored issues
show
Documentation introduced by
$header is of type string, but the function expects a boolean.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
233
    }
234
235
    /**
236
     * @param bool $condition
237
     * @param callable|\Spatie\Menu\Menu|\Spatie\Menu\Item $header
238
     * @param callable|\Spatie\Menu\Menu|null $menu
239
     *
240
     * @return $this
241
     */
242
    public function submenuIf($condition, $header, $menu = null)
243
    {
244
        if ($condition) {
245
            $this->submenu($header, $menu);
246
        }
247
248
        return $this;
249
    }
250
251
    protected function parseSubmenuArgs($args): array
252
    {
253
        if (count($args) === 1) {
254
            return ['', $args[0]];
255
        }
256
257
        return [$args[0], $args[1]];
258
    }
259
260
    /**
261
     * @param \Spatie\Menu\Menu|callable $menu
262
     *
263
     * @return \Spatie\Menu\Menu
264
     */
265
    protected function createSubmenuMenu($menu): self
266
    {
267
        if (is_callable($menu)) {
268
            $transformer = $menu;
269
            $menu = $this->blueprint();
270
            $transformer($menu);
271
        }
272
273
        return $menu;
274
    }
275
276
    /**
277
     * @param \Spatie\Menu\Item|string $header
278
     *
279
     * @return string
280
     */
281
    protected function createSubmenuHeader($header): string
282
    {
283
        if ($header instanceof Item) {
284
            $header = $header->render();
285
        }
286
287
        return $header;
288
    }
289
290
    /**
291
     * Iterate over all the items and apply a callback. If you typehint the
292
     * item parameter in the callable, it wil only be applied to items of that
293
     * type.
294
     *
295
     * @param callable $callable
296
     *
297
     * @return $this
298
     */
299
    public function each(callable $callable)
300
    {
301
        $type = Reflection::firstParameterType($callable);
302
303
        foreach ($this->items as $item) {
304
            if (! Reflection::itemMatchesType($item, $type)) {
305
                continue;
306
            }
307
308
            $callable($item);
309
        }
310
311
        return $this;
312
    }
313
314
    /**
315
     * Register a filter to the menu. When an item is added, all filters will be
316
     * applied to the item. If you typehint the item parameter in the callable, it
317
     * will only be applied to items of that type.
318
     *
319
     * @param callable $callable
320
     *
321
     * @return $this
322
     */
323
    public function registerFilter(callable $callable)
324
    {
325
        $this->filters[] = $callable;
326
327
        return $this;
328
    }
329
330
    /**
331
     * Apply a filter to an item. Returns the result of the filter.
332
     *
333
     * @param callable $filter
334
     * @param \Spatie\Menu\Item $item
335
     */
336
    protected function applyFilter(callable $filter, Item $item)
337
    {
338
        $type = Reflection::firstParameterType($filter);
339
340
        if (! Reflection::itemMatchesType($item, $type)) {
341
            return;
342
        }
343
344
        $filter($item);
345
    }
346
347
    /**
348
     * Apply a callable to all existing items, and register it as a filter so it
349
     * will get applied to all new items too. If you typehint the item parameter
350
     * in the callable, it wil only be applied to items of that type.
351
     *
352
     * @param callable $callable
353
     *
354
     * @return $this
355
     */
356
    public function applyToAll(callable $callable)
357
    {
358
        $this->each($callable);
359
        $this->registerFilter($callable);
360
361
        return $this;
362
    }
363
364
    /**
365
     * Wrap the entire menu in an html element. This is another level of
366
     * wrapping above the `wrapperTag`.
367
     *
368
     * @param string $element
369
     * @param array $attributes
370
     *
371
     * @return $this
372
     */
373
    public function wrap(string $element, $attributes = [])
374
    {
375
        $this->wrap = [$element, $attributes];
376
377
        return $this;
378
    }
379
380
    /**
381
     * Determine whether the menu is active.
382
     *
383
     * @return bool
384
     */
385
    public function isActive(): bool
386
    {
387
        foreach ($this->items as $item) {
388
            if ($item->isActive()) {
389
                return true;
390
            }
391
        }
392
393
        return false;
394
    }
395
396
    /**
397
     * Set multiple items in the menu as active based on a callable that filters
398
     * through items. If you typehint the item parameter in the callable, it will
399
     * only be applied to items of that type.
400
     *
401
     * @param callable|string $urlOrCallable
402
     * @param string $root
403
     *
404
     * @return $this
405
     */
406
    public function setActive($urlOrCallable, string $root = '/')
407
    {
408
        if (is_string($urlOrCallable)) {
409
            return $this->setActiveFromUrl($urlOrCallable, $root);
410
        }
411
412
        if (is_callable($urlOrCallable)) {
413
            return $this->setActiveFromCallable($urlOrCallable);
414
        }
415
416
        throw new \InvalidArgumentException('`setActive` requires a pattern or a callable');
417
    }
418
419
    /**
420
     * Set if the menu should add an extra class for exact url matches.
421
     *
422
     * @param bool @exactActive
423
     *
424
     * @return $this
425
     */
426
    public function setExactActive(bool $exactActive = true)
427
    {
428
        $this->exactActive = $exactActive;
429
430
        return $this;
431
    }
432
433
    /**
434
     * Set the class name that will be used on exact-active items for this menu.
435
     *
436
     * @param string $class
437
     *
438
     * @return $this
439
     */
440
    public function setExactActiveClass(string $class)
441
    {
442
        $this->exactActiveClass = $class;
443
444
        return $this;
445
    }
446
447
    /**
448
     * Set all relevant children active based on the current request's URL.
449
     *
450
     * /, /about, /contact => request to /about will set the about link active.
451
     *
452
     * /en, /en/about, /en/contact => request to /en won't set /en active if the
453
     *                                request root is set to /en.
454
     *
455
     * @param string $url  The current request url.
456
     * @param string $root If the link's URL is an exact match with the request
457
     *                     root, the link won't be set active. This behavior is
458
     *                     to avoid having home links active on every request.
459
     *
460
     * @return $this
461
     */
462
    public function setActiveFromUrl(string $url, string $root = '/')
463
    {
464
        $this->applyToAll(function (Menu $menu) use ($url, $root) {
465
            $menu->setActiveFromUrl($url, $root);
466
        });
467
468
        $this->applyToAll(function (Activatable $item) use ($url, $root) {
469
            $item->determineActiveForUrl($url, $root);
470
        });
471
472
        return $this;
473
    }
474
475
    /**
476
     * @param callable $callable
477
     *
478
     * @return $this
479
     */
480
    public function setActiveFromCallable(callable $callable)
481
    {
482
        $this->applyToAll(function (Menu $menu) use ($callable) {
483
            $menu->setActiveFromCallable($callable);
484
        });
485
486
        $type = Reflection::firstParameterType($callable);
487
488
        $this->applyToAll(function (Activatable $item) use ($callable, $type) {
489
            if (! Reflection::itemMatchesType($item, $type)) {
0 ignored issues
show
Documentation introduced by
$item is of type object<Spatie\Menu\Activatable>, but the function expects a object<Spatie\Menu\Item>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
490
                return;
491
            }
492
493
            if ($callable($item)) {
494
                $item->setActive();
495
            }
496
        });
497
498
        return $this;
499
    }
500
501
    /**
502
     * Set the class name that will be used on active items for this menu.
503
     *
504
     * @param string $class
505
     *
506
     * @return $this
507
     */
508
    public function setActiveClass(string $class)
509
    {
510
        $this->activeClass = $class;
511
512
        return $this;
513
    }
514
515
    /**
516
     * Add a class to all items in the menu.
517
     *
518
     * @param string $class
519
     *
520
     * @return $this
521
     */
522
    public function addItemClass(string $class)
523
    {
524
        $this->applyToAll(function (HasHtmlAttributes $link) use ($class) {
525
            $link->addClass($class);
526
        });
527
528
        return $this;
529
    }
530
531
    /**
532
     * Set an attribute on all items in the menu.
533
     *
534
     * @param string $attribute
535
     * @param string $value
536
     *
537
     * @return $this
538
     */
539
    public function setItemAttribute(string $attribute, string $value = '')
540
    {
541
        $this->applyToAll(function (HasHtmlAttributes $link) use ($attribute, $value) {
542
            $link->setAttribute($attribute, $value);
543
        });
544
545
        return $this;
546
    }
547
548
    /**
549
     * Add a parent class to all items in the menu.
550
     *
551
     * @param string $class
552
     *
553
     * @return $this
554
     */
555
    public function addItemParentClass(string $class)
556
    {
557
        $this->applyToAll(function (HasParentAttributes $item) use ($class) {
558
            $item->addParentClass($class);
559
        });
560
561
        return $this;
562
    }
563
564
    /**
565
     * Add a parent attribute to all items in the menu.
566
     *
567
     * @param string $attribute
568
     * @param string $value
569
     *
570
     * @return $this
571
     */
572
    public function setItemParentAttribute(string $attribute, string $value = '')
573
    {
574
        $this->applyToAll(function (HasParentAttributes $item) use ($attribute, $value) {
575
            $item->setParentAttribute($attribute, $value);
576
        });
577
578
        return $this;
579
    }
580
581
    /**
582
     * Set tag for items wrapper.
583
     *
584
     * @param string|null $wrapperTagName
585
     * @return $this
586
     */
587
    public function setWrapperTag($wrapperTagName = null)
588
    {
589
        $this->wrapperTagName = $wrapperTagName;
590
591
        return $this;
592
    }
593
594
    /**
595
     * Set tag for items wrapper.
596
     *
597
     * @param string|null $wrapperTagName
0 ignored issues
show
Bug introduced by
There is no parameter named $wrapperTagName. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
598
     * @return $this
599
     */
600
    public function withoutWrapperTag()
601
    {
602
        $this->wrapperTagName = null;
603
604
        return $this;
605
    }
606
607
    /**
608
     * Set the parent tag name.
609
     *
610
     * @param string|null $parentTagName
611
     * @return $this
612
     */
613
    public function setParentTag($parentTagName = null)
614
    {
615
        $this->parentTagName = $parentTagName;
0 ignored issues
show
Documentation Bug introduced by
It seems like $parentTagName can also be of type string. However, the property $parentTagName is declared as type boolean. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
616
617
        return $this;
618
    }
619
620
    /**
621
     * Render items without a parent tag.
622
     *
623
     * @return $this
624
     */
625
    public function withoutParentTag()
626
    {
627
        $this->parentTagName = null;
628
629
        return $this;
630
    }
631
632
    /**
633
     * Set whether active class should (also) be on link.
634
     *
635
     * @param $activeClassOnLink
636
     * @return $this
637
     */
638
    public function setActiveClassOnLink(bool $activeClassOnLink = true)
639
    {
640
        $this->activeClassOnLink = $activeClassOnLink;
641
642
        return $this;
643
    }
644
645
    /**
646
     * Set whether active class should (also) be on parent.
647
     *
648
     * @param $activeClassOnParent
649
     * @return $this
650
     */
651
    public function setActiveClassOnParent(bool $activeClassOnParent = true)
652
    {
653
        $this->activeClassOnParent = $activeClassOnParent;
654
655
        return $this;
656
    }
657
658
    /**
659
     * @param bool $condition
660
     * @param callable $callable
661
     *
662
     * @return $this
663
     */
664
    public function if(bool $condition, callable $callable)
665
    {
666
        return $condition ? $callable($this) : $this;
667
    }
668
669
    /**
670
     * Create a empty blueprint of the menu (copies `filters` and `activeClass`).
671
     *
672
     * @return static
673
     */
674
    public function blueprint()
675
    {
676
        $clone = new static();
677
678
        $clone->filters = $this->filters;
679
        $clone->activeClass = $this->activeClass;
680
681
        return $clone;
682
    }
683
684
    /**
685
     * Render the menu.
686
     *
687
     * @return string
688
     */
689
    public function render(): string
690
    {
691
        $tag = $this->wrapperTagName
692
            ? new Tag($this->wrapperTagName, $this->htmlAttributes)
693
            : null;
694
695
        $contents = array_map([$this, 'renderItem'], $this->items);
696
697
        $wrappedContents = $tag ? $tag->withContents($contents) : implode('', $contents);
698
699
        $menu = $this->prepend.$wrappedContents.$this->append;
700
701
        if (! empty($this->wrap)) {
702
            return Tag::make($this->wrap[0], new Attributes($this->wrap[1]))->withContents($menu);
703
        }
704
705
        return $menu;
706
    }
707
708
    protected function renderItem(Item $item): string
709
    {
710
        $attributes = new Attributes();
711
712
        if(method_exists($item, 'beforeRender')) {
713
            $item->beforeRender();
0 ignored issues
show
Bug introduced by
The method beforeRender() does not exist on Spatie\Menu\Item. Did you maybe mean render()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
714
        }
715
716
        if (method_exists($item, 'willRender') && $item->willRender() === false) {
0 ignored issues
show
Bug introduced by
The method willRender() does not exist on Spatie\Menu\Item. Did you maybe mean render()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
717
            return '';
718
        }
719
720
        if ($item->isActive()) {
721
            if ($this->activeClassOnParent) {
722
                $attributes->addClass($this->activeClass);
723
724
                if ($this->exactActive && $item->isExactActive()) {
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Spatie\Menu\Item as the method isExactActive() does only exist in the following implementations of said interface: Spatie\Menu\Html, Spatie\Menu\Link.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
725
                    $attributes->addClass($this->exactActiveClass);
726
                }
727
            }
728
729
            if ($this->activeClassOnLink && $item instanceof HasHtmlAttributes) {
730
                $item->addClass($this->activeClass);
731
732
                if ($this->exactActive && $item->isExactActive()) {
733
                    $item->addClass($this->exactActiveClass);
734
                }
735
            }
736
        }
737
738
        if ($item instanceof HasParentAttributes) {
739
            $attributes->setAttributes($item->parentAttributes());
740
        }
741
742
        if (! $this->parentTagName) {
743
            return $item->render();
744
        }
745
746
        return Tag::make($this->parentTagName, $attributes)->withContents($item->render());
0 ignored issues
show
Documentation introduced by
$this->parentTagName is of type boolean, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
747
    }
748
749
    /**
750
     * The amount of items in the menu.
751
     *
752
     * @return int
753
     */
754
    public function count(): int
755
    {
756
        return count($this->items);
757
    }
758
759
    /**
760
     * @return string
761
     */
762
    public function __toString(): string
763
    {
764
        return $this->render();
765
    }
766
}
767