Completed
Push — master ( a682ba...4851b3 )
by Paweł
40:50
created

MenuItem::offsetGet()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 0
cts 2
cp 0
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 1
crap 2
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of the Superdesk Web Publisher Menu Bundle.
7
 *
8
 * Copyright 2016 Sourcefabric z.ú. and contributors.
9
 *
10
 * For the full copyright and license information, please see the
11
 * AUTHORS and LICENSE files distributed with this source code.
12
 *
13
 * @copyright 2016 Sourcefabric z.ú
14
 * @license http://www.superdesk.org/license
15
 */
16
17
namespace SWP\Bundle\MenuBundle\Model;
18
19
use Doctrine\Common\Collections\ArrayCollection;
20
use Knp\Menu\FactoryInterface;
21
use Knp\Menu\ItemInterface;
22
23
class MenuItem implements MenuItemInterface
24
{
25
    /**
26
     * @var mixed
27
     */
28
    protected $id;
29
30
    /**
31
     * @var MenuItemInterface
32
     */
33
    protected $root;
34
35
    /**
36
     * @var int
37
     */
38
    protected $lft;
39
40
    /**
41
     * @var int
42
     */
43
    protected $rgt;
44
45
    /**
46
     * @var int
47
     */
48
    protected $level;
49
50
    /**
51
     * Name of this menu item (used for id by parent menu).
52
     *
53
     * @var string
54
     */
55
    protected $name = null;
56
57
    /**
58
     * Label to output, name is used by default.
59
     *
60
     * @var string
61
     */
62
    protected $label = null;
63
64
    /**
65
     * Attributes for the item link.
66
     *
67
     * @var array
68
     */
69
    protected $linkAttributes = [];
70
71
    /**
72
     * Attributes for the children list.
73
     *
74
     * @var array
75
     */
76
    protected $childrenAttributes = [];
77
78
    /**
79
     * Attributes for the item text.
80
     *
81
     * @var array
82
     */
83
    protected $labelAttributes = [];
84
85
    /**
86
     * Uri to use in the anchor tag.
87
     *
88
     * @var string
89
     */
90
    protected $uri = null;
91
92
    /**
93
     * Attributes for the item.
94
     *
95
     * @var array
96
     */
97
    protected $attributes = [];
98
99
    /**
100
     * Extra stuff associated to the item.
101
     *
102
     * @var array
103
     */
104
    protected $extras = [];
105
106
    /**
107
     * Whether the item is displayed.
108
     *
109
     * @var bool
110
     */
111
    protected $display = true;
112
113
    /**
114
     * Whether the children of the item are displayed.
115
     *
116
     * @var bool
117
     */
118
    protected $displayChildren = true;
119
120
    /**
121
     * Child items.
122
     *
123
     * @var ItemInterface[]
124
     */
125
    protected $children = [];
126
127
    /**
128
     * Parent item.
129
     *
130
     * @var ItemInterface|null
131
     */
132
    protected $parent = null;
133
134
    /**
135
     * whether the item is current. null means unknown.
136
     *
137
     * @var bool|null
138
     */
139
    protected $isCurrent = null;
140
141
    /**
142
     * MenuItem constructor.
143
     */
144 12
    public function __construct()
145
    {
146 12
        $this->setChildren([]);
147 12
    }
148
149
    /**
150
     * {@inheritdoc}
151
     */
152 7
    public function getId()
153
    {
154 7
        return $this->id;
155
    }
156
157
    /**
158
     * {@inheritdoc}
159
     */
160
    public function getRoot()
161
    {
162
        return $this->root;
163
    }
164
165
    /**
166
     * {@inheritdoc}
167
     */
168
    public function getLeft(): int
169
    {
170
        return $this->lft;
171
    }
172
173
    /**
174
     * {@inheritdoc}
175
     */
176
    public function setLeft(int $left)
177
    {
178
        $this->lft = $left;
179
    }
180
181
    /**
182
     * {@inheritdoc}
183
     */
184
    public function getRight(): int
185
    {
186
        return $this->rgt;
187
    }
188
189
    /**
190
     * @param int $right
191
     */
192
    public function setRight(int $right)
193
    {
194
        $this->rgt = $right;
195
    }
196
197
    /**
198
     * {@inheritdoc}
199
     */
200 3
    public function getLevel(): int
201
    {
202 3
        return $this->level;
203
    }
204
205
    /**
206
     * {@inheritdoc}
207
     */
208
    public function setLevel(int $level)
209
    {
210
        $this->level = $level;
211
    }
212
213
    public function setFactory(FactoryInterface $factory)
214
    {
215
    }
216
217 8
    public function getName()
218
    {
219 8
        return $this->name;
220
    }
221
222 12
    public function setName($name)
223
    {
224 12
        $this->name = $name;
225
226 12
        return $this;
227
    }
228
229 8
    public function getUri()
230
    {
231 8
        return $this->uri;
232
    }
233
234 12
    public function setUri($uri)
235
    {
236 12
        $this->uri = $uri;
237
238 12
        return $this;
239
    }
240
241 8
    public function getLabel()
242
    {
243 8
        return null !== $this->label ? $this->label : $this->name;
244
    }
245
246 12
    public function setLabel($label)
247
    {
248 12
        $this->label = $label;
249
250 12
        return $this;
251
    }
252
253 3
    public function getAttributes()
254
    {
255 3
        return $this->attributes;
256
    }
257
258 12
    public function setAttributes(array $attributes)
259
    {
260 12
        $this->attributes = $attributes;
261
262 12
        return $this;
263
    }
264
265 3
    public function getAttribute($name, $default = null)
266
    {
267 3
        if (isset($this->attributes[$name])) {
268
            return $this->attributes[$name];
269
        }
270
271 3
        return $default;
272
    }
273
274
    public function setAttribute($name, $value)
275
    {
276
        $this->attributes[$name] = $value;
277
278
        return $this;
279
    }
280
281 3
    public function getLinkAttributes()
282
    {
283 3
        return $this->linkAttributes;
284
    }
285
286 12
    public function setLinkAttributes(array $linkAttributes)
287
    {
288 12
        $this->linkAttributes = $linkAttributes;
289
290 12
        return $this;
291
    }
292
293
    public function getLinkAttribute($name, $default = null)
294
    {
295
        if (isset($this->linkAttributes[$name])) {
296
            return $this->linkAttributes[$name];
297
        }
298
299
        return $default;
300
    }
301
302
    public function setLinkAttribute($name, $value)
303
    {
304
        $this->linkAttributes[$name] = $value;
305
306
        return $this;
307
    }
308
309 3
    public function getChildrenAttributes()
310
    {
311 3
        return $this->childrenAttributes;
312
    }
313
314 12
    public function setChildrenAttributes(array $childrenAttributes)
315
    {
316 12
        $this->childrenAttributes = $childrenAttributes;
317
318 12
        return $this;
319
    }
320
321 3
    public function getChildrenAttribute($name, $default = null)
322
    {
323 3
        if (isset($this->childrenAttributes[$name])) {
324
            return $this->childrenAttributes[$name];
325
        }
326
327 3
        return $default;
328
    }
329
330
    public function setChildrenAttribute($name, $value)
331
    {
332
        $this->childrenAttributes[$name] = $value;
333
334
        return $this;
335
    }
336
337
    public function getLabelAttributes()
338
    {
339
        return $this->labelAttributes;
340
    }
341
342 12
    public function setLabelAttributes(array $labelAttributes)
343
    {
344 12
        $this->labelAttributes = $labelAttributes;
345
346 12
        return $this;
347
    }
348
349
    public function getLabelAttribute($name, $default = null)
350
    {
351
        if (isset($this->labelAttributes[$name])) {
352
            return $this->labelAttributes[$name];
353
        }
354
355
        return $default;
356
    }
357
358
    public function setLabelAttribute($name, $value)
359
    {
360
        $this->labelAttributes[$name] = $value;
361
362
        return $this;
363
    }
364
365
    public function getExtras()
366
    {
367
        return $this->extras;
368
    }
369
370
    public function setExtras(array $extras)
371
    {
372
        $this->extras = $extras;
373
374
        return $this;
375
    }
376
377 3
    public function getExtra($name, $default = null)
378
    {
379 3
        if (isset($this->extras[$name])) {
380
            return $this->extras[$name];
381
        }
382
383 3
        return $default;
384
    }
385
386
    public function setExtra($name, $value)
387
    {
388
        $this->extras[$name] = $value;
389
390
        return $this;
391
    }
392
393 3
    public function getDisplayChildren()
394
    {
395 3
        return $this->displayChildren;
396
    }
397
398 12
    public function setDisplayChildren($bool)
399
    {
400 12
        $this->displayChildren = (bool) $bool;
401
402 12
        return $this;
403
    }
404
405 3
    public function isDisplayed()
406
    {
407 3
        return $this->display;
408
    }
409
410 12
    public function setDisplay($bool)
411
    {
412 12
        $this->display = (bool) $bool;
413
414 12
        return $this;
415
    }
416
417
    /**
418
     * @param ItemInterface $menuItem
419
     *
420
     * @return bool
421
     */
422
    public function hasChild(ItemInterface $menuItem): bool
423
    {
424
        return $this->children->contains($menuItem);
0 ignored issues
show
Bug introduced by
The method contains cannot be called on $this->children (of type array<integer,object<Knp\Menu\ItemInterface>>).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
425
    }
426
427
    /**
428
     * {@inheritdoc}
429
     */
430
    public function addChild($child, array $options = array())
431
    {
432
        if (!$this->hasChild($child)) {
0 ignored issues
show
Bug introduced by
It seems like $child defined by parameter $child on line 430 can also be of type string; however, SWP\Bundle\MenuBundle\Model\MenuItem::hasChild() does only seem to accept object<Knp\Menu\ItemInterface>, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
433
            $child->setParent($this);
0 ignored issues
show
Bug introduced by
It seems like $child is not always an object, but can also be of type string. Maybe add an additional type check?

If a variable is not always an object, we recommend to add an additional type check to ensure your method call is safe:

function someFunction(A $objectMaybe = null)
{
    if ($objectMaybe instanceof A) {
        $objectMaybe->doSomething();
    }
}
Loading history...
434
            $this->children->set($child->getName(), $child);
0 ignored issues
show
Bug introduced by
The method set cannot be called on $this->children (of type array<integer,object<Knp\Menu\ItemInterface>>).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
435
        }
436
437
        return $child;
0 ignored issues
show
Bug Compatibility introduced by
The expression return $child; of type Knp\Menu\ItemInterface|string is incompatible with the return type declared by the interface Knp\Menu\ItemInterface::addChild of type Knp\Menu\ItemInterface as it can also be of type string which is not included in this return type.
Loading history...
438
    }
439
440
    /**
441
     * {@inheritdoc}
442
     */
443
    public function getChild($name)
444
    {
445
        return $this->children->get($name);
0 ignored issues
show
Bug introduced by
The method get cannot be called on $this->children (of type array<integer,object<Knp\Menu\ItemInterface>>).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
446
    }
447
448
    public function reorderChildren($order)
449
    {
450
        if (count($order) != $this->count()) {
451
            throw new \InvalidArgumentException('Cannot reorder children, order does not contain all children.');
452
        }
453
454
        $newChildren = array();
455
        foreach ($order as $name) {
456
            if (!$this->children->containsKey($name)) {
0 ignored issues
show
Bug introduced by
The method containsKey cannot be called on $this->children (of type array<integer,object<Knp\Menu\ItemInterface>>).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
457
                throw new \InvalidArgumentException('Cannot find children named '.$name);
458
            }
459
            $child
460
                = $this->getChild($name);
461
            $newChildren[$name] = $child;
462
        }
463
464
        $this->setChildren($newChildren);
465
466
        return $this;
467
    }
468
469
    public function copy()
470
    {
471
        $newMenu = clone $this;
472
        $newMenu->children = new ArrayCollection();
0 ignored issues
show
Documentation Bug introduced by
It seems like new \Doctrine\Common\Collections\ArrayCollection() of type object<Doctrine\Common\C...ctions\ArrayCollection> is incompatible with the declared type array<integer,object<Knp\Menu\ItemInterface>> of property $children.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
473
        $newMenu->setParent(null);
474
        foreach ($this->getChildren() as $child) {
475
            $newMenu->addChild($child->copy());
476
        }
477
478
        return $newMenu;
479
    }
480
481 3
    public function isRoot()
482
    {
483 3
        return null === $this->parent;
484
    }
485
486 8
    public function getParent()
487
    {
488 8
        return $this->parent;
489
    }
490
491 6
    public function setParent(ItemInterface $parent = null)
492
    {
493 6
        if ($parent === $this) {
494
            throw new \InvalidArgumentException('Item cannot be a child of itself');
495
        }
496
497 6
        $this->parent = $parent;
498
499 6
        return $this;
500
    }
501
502 3
    public function getChildren()
503
    {
504 3
        if (is_array($this->children)) {
505
            return $this->children;
506
        }
507
508 3
        return $this->children->toArray();
509
    }
510
511 12
    public function setChildren(array $children)
512
    {
513 12
        $this->children = new ArrayCollection($children);
0 ignored issues
show
Documentation Bug introduced by
It seems like new \Doctrine\Common\Col...ayCollection($children) of type object<Doctrine\Common\C...ctions\ArrayCollection> is incompatible with the declared type array<integer,object<Knp\Menu\ItemInterface>> of property $children.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
514
515 12
        return $this;
516
    }
517
518
    public function removeChild($name)
519
    {
520
        $name = $name instanceof ItemInterface ? $name->getName() : $name;
521
        $child = $this->getChild($name);
522
523
        if ($child !== null) {
524
            $child->setParent(null);
525
            $this->children->remove($name);
0 ignored issues
show
Bug introduced by
The method remove cannot be called on $this->children (of type array<integer,object<Knp\Menu\ItemInterface>>).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
526
        }
527
528
        return $this;
529
    }
530
531
    /**
532
     * {@inheritdoc}
533
     */
534 3
    public function getFirstChild()
535
    {
536 3
        return $this->children->first();
0 ignored issues
show
Bug introduced by
The method first cannot be called on $this->children (of type array<integer,object<Knp\Menu\ItemInterface>>).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
537
    }
538
539
    /**
540
     * {@inheritdoc}
541
     */
542 3
    public function getLastChild()
543
    {
544 3
        return $this->children->last();
0 ignored issues
show
Bug introduced by
The method last cannot be called on $this->children (of type array<integer,object<Knp\Menu\ItemInterface>>).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
545
    }
546
547 3
    public function hasChildren()
548
    {
549 3
        foreach ($this->children as $child) {
550 3
            if ($child->isDisplayed()) {
551 3
                return true;
552
            }
553
        }
554
555 3
        return false;
556
    }
557
558 12
    public function setCurrent($bool)
559
    {
560 12
        $this->isCurrent = $bool;
561
562 12
        return $this;
563
    }
564
565 3
    public function isCurrent()
566
    {
567 3
        return $this->isCurrent;
568
    }
569
570 3
    public function isLast()
571
    {
572
        // if this is root, then return false
573 3
        if ($this->isRoot()) {
574
            return false;
575
        }
576
577 3
        return $this->getParent()->getLastChild() === $this;
578
    }
579
580 3
    public function isFirst()
581
    {
582
        // if this is root, then return false
583 3
        if ($this->isRoot()) {
584
            return false;
585
        }
586
587 3
        return $this->getParent()->getFirstChild() === $this;
588
    }
589
590 3 View Code Duplication
    public function actsLikeFirst()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
591
    {
592
        // root items are never "marked" as first
593 3
        if ($this->isRoot()) {
594
            return false;
595
        }
596
597
        // A menu acts like first only if it is displayed
598 3
        if (!$this->isDisplayed()) {
599
            return false;
600
        }
601
602
        // if we're first and visible, we're first, period.
603 3
        if ($this->isFirst()) {
604 3
            return true;
605
        }
606
607 3
        $children = $this->getParent()->getChildren();
608 3
        foreach ($children as $child) {
609
            // loop until we find a visible menu. If its this menu, we're first
610 3
            if ($child->isDisplayed()) {
611 3
                return $child->getName() === $this->getName();
612
            }
613
        }
614
615
        return false;
616
    }
617
618 3 View Code Duplication
    public function actsLikeLast()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
619
    {
620
        // root items are never "marked" as last
621 3
        if ($this->isRoot()) {
622
            return false;
623
        }
624
625
        // A menu acts like last only if it is displayed
626 3
        if (!$this->isDisplayed()) {
627
            return false;
628
        }
629
630
        // if we're last and visible, we're last, period.
631 3
        if ($this->isLast()) {
632 3
            return true;
633
        }
634
635 3
        $children = array_reverse($this->getParent()->getChildren());
636 3
        foreach ($children as $child) {
637
            // loop until we find a visible menu. If its this menu, we're first
638 3
            if ($child->isDisplayed()) {
639 3
                return $child->getName() === $this->getName();
640
            }
641
        }
642
643
        return false;
644
    }
645
646
    /**
647
     * Implements Countable.
648
     */
649
    public function count()
650
    {
651
        return count($this->children);
652
    }
653
654
    /**
655
     * Implements IteratorAggregate.
656
     */
657 5
    public function getIterator()
658
    {
659 5
        return new \ArrayIterator($this->children);
660
    }
661
662
    /**
663
     * Implements ArrayAccess.
664
     */
665 3
    public function offsetExists($name)
666
    {
667 3
        return isset($this->children[$name]);
668
    }
669
670
    /**
671
     * Implements ArrayAccess.
672
     */
673
    public function offsetGet($name)
674
    {
675
        return $this->getChild($name);
676
    }
677
678
    /**
679
     * Implements ArrayAccess.
680
     */
681
    public function offsetSet($name, $value)
682
    {
683
        return $this->addChild($name)->setLabel($value);
684
    }
685
686
    /**
687
     * Implements ArrayAccess.
688
     */
689
    public function offsetUnset($name)
690
    {
691
        $this->removeChild($name);
692
    }
693
}
694