NodeMenu   F
last analyzed

Complexity

Total Complexity 89

Size/Duplication

Total Lines 680
Duplicated Lines 9.56 %

Coupling/Cohesion

Components 2
Dependencies 7

Test Coverage

Coverage 0%

Importance

Changes 0
Metric Value
wmc 89
lcom 2
cbo 7
dl 65
loc 680
ccs 0
cts 245
cp 0
rs 1.92
c 0
b 0
f 0

30 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 11 1
A setLocale() 0 4 1
A setCurrentNode() 0 4 1
A setPermission() 0 8 2
A setIncludeOffline() 0 4 1
A setIncludeHiddenFromNav() 0 8 2
B init() 0 40 5
A getTopNodes() 9 26 5
A getCurrent() 10 10 2
A getActiveForDepth() 9 9 2
A getSiblings() 0 17 4
A getPreviousSibling() 0 16 5
A getNextSibling() 0 19 5
A getParent() 0 13 3
A getNodeBySlug() 0 5 1
A getBreadCrumb() 0 33 4
B getChildren() 23 37 6
F getNodeByInternalName() 0 89 21
A getRootNodeMenuItem() 0 22 3
A isIncludeOffline() 0 4 1
A getPermission() 0 4 1
A getUser() 0 4 1
A getEntityManager() 0 4 1
A getTokenStorage() 0 4 1
A getAclHelper() 0 4 1
A getLocale() 0 4 1
A isIncludeHiddenFromNav() 0 4 1
A getActive() 0 11 3
A isInitialized() 0 4 1
A getTopNodeMenuItems() 14 22 3

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like NodeMenu often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use NodeMenu, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace Kunstmaan\NodeBundle\Helper;
4
5
use Doctrine\ORM\EntityManagerInterface;
6
use Kunstmaan\AdminBundle\Helper\DomainConfigurationInterface;
7
use Kunstmaan\AdminBundle\Helper\Security\Acl\AclHelper;
8
use Kunstmaan\AdminBundle\Helper\Security\Acl\Permission\PermissionMap;
9
use Kunstmaan\NodeBundle\Entity\HasNodeInterface;
10
use Kunstmaan\NodeBundle\Entity\Node;
11
use Kunstmaan\NodeBundle\Entity\NodeTranslation;
12
use Kunstmaan\NodeBundle\Repository\NodeRepository;
13
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
14
15
class NodeMenu
16
{
17
    /**
18
     * @var EntityManagerInterface
19
     */
20
    private $em;
21
22
    /**
23
     * @var TokenStorageInterface
24
     */
25
    private $tokenStorage;
26
27
    /**
28
     * @var AclHelper
29
     */
30
    private $aclHelper;
31
32
    /**
33
     * @var string
34
     */
35
    private $locale;
36
37
    /**
38
     * @var Node
39
     */
40
    private $currentNode;
41
42
    /**
43
     * @var string
44
     */
45
    private $permission = PermissionMap::PERMISSION_VIEW;
46
47
    /**
48
     * @var bool
49
     */
50
    private $includeOffline = false;
51
52
    /**
53
     * @var bool
54
     */
55
    private $includeHiddenFromNav = false;
56
57
    /**
58
     * @var NodeMenuItem[]
59
     */
60
    private $topNodeMenuItems;
61
62
    /**
63
     * @var NodeMenuItem[]
64
     */
65
    private $breadCrumb;
66
67
    /**
68
     * @var Node[]
69
     */
70
    private $allNodes = array();
71
72
    /**
73
     * @var Node[]
74
     */
75
    private $childNodes = array();
76
77
    /**
78
     * @var Node[]
79
     */
80
    private $nodesByInternalName = array();
81
82
    /**
83
     * @var bool
84
     */
85
    private $initialized = false;
86
87
    /**
88
     * @var NodeMenuItem
89
     */
90
    private $rootNodeMenuItem;
91
92
    /**
93
     * @var DomainConfigurationInterface
94
     */
95
    private $domainConfiguration;
96
97
    /**
98
     * @param EntityManagerInterface       $em                  The entity manager
99
     * @param TokenStorageInterface        $tokenStorage        The security token storage
100
     * @param AclHelper                    $aclHelper           The ACL helper pages
101
     * @param DomainConfigurationInterface $domainConfiguration The current domain configuration
102
     */
103
    public function __construct(
104
        EntityManagerInterface $em,
105
        TokenStorageInterface $tokenStorage,
106
        AclHelper $aclHelper,
107
        DomainConfigurationInterface $domainConfiguration
108
    ) {
109
        $this->em = $em;
110
        $this->tokenStorage = $tokenStorage;
111
        $this->aclHelper = $aclHelper;
112
        $this->domainConfiguration = $domainConfiguration;
113
    }
114
115
    /**
116
     * @param string $locale
117
     */
118
    public function setLocale($locale)
119
    {
120
        $this->locale = $locale;
121
    }
122
123
    /**
124
     * @param Node $currentNode
0 ignored issues
show
Documentation introduced by Wim Vandersmissen
Should the type for parameter $currentNode not be null|Node?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
125
     */
126
    public function setCurrentNode(Node $currentNode = null)
127
    {
128
        $this->currentNode = $currentNode;
129
    }
130
131
    /**
132
     * @param string $permission
133
     */
134
    public function setPermission($permission)
135
    {
136
        if ($this->permission !== $permission) {
137
            // For now reset initialized flag when cached data has to be reset ...
138
            $this->initialized = false;
139
        }
140
        $this->permission = $permission;
141
    }
142
143
    /**
144
     * @param bool $includeOffline
145
     */
146
    public function setIncludeOffline($includeOffline)
147
    {
148
        $this->includeOffline = $includeOffline;
149
    }
150
151
    /**
152
     * @param bool $includeHiddenFromNav
153
     */
154
    public function setIncludeHiddenFromNav($includeHiddenFromNav)
155
    {
156
        if ($this->includeHiddenFromNav !== $includeHiddenFromNav) {
157
            // For now reset initialized flag when cached data has to be reset ...
158
            $this->initialized = false;
159
        }
160
        $this->includeHiddenFromNav = $includeHiddenFromNav;
161
    }
162
163
    /**
164
     * This method initializes the nodemenu only once, the method may be
165
     * executed multiple times
166
     */
167
    private function init()
168
    {
169
        if ($this->initialized) {
170
            return;
171
        }
172
173
        $this->allNodes = array();
174
        $this->breadCrumb = null;
0 ignored issues
show
Documentation Bug introduced by Wim Vandersmissen
It seems like null of type null is incompatible with the declared type array<integer,object<Kun...e\Helper\NodeMenuItem>> of property $breadCrumb.

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...
175
        $this->childNodes = array();
176
        $this->topNodeMenuItems = null;
0 ignored issues
show
Documentation Bug introduced by Wim Vandersmissen
It seems like null of type null is incompatible with the declared type array<integer,object<Kun...e\Helper\NodeMenuItem>> of property $topNodeMenuItems.

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...
177
        $this->nodesByInternalName = array();
178
179
        /* @var NodeRepository $repo */
180
        $repo = $this->em->getRepository(Node::class);
181
182
        // Get all possible menu items in one query (also fetch offline nodes)
183
        $nodes = $repo->getChildNodes(
184
            false,
0 ignored issues
show
Documentation introduced by Wim Vandersmissen
false is of type boolean, but the function expects a integer|null.

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...
185
            $this->locale,
186
            $this->permission,
187
            $this->aclHelper,
188
            $this->includeHiddenFromNav,
189
            true,
190
            $this->domainConfiguration->getRootNode()
191
        );
192
        foreach ($nodes as $node) {
193
            $this->allNodes[$node->getId()] = $node;
194
195
            if ($node->getParent()) {
196
                $this->childNodes[$node->getParent()->getId()][] = $node;
197
            } else {
198
                $this->childNodes[0][] = $node;
199
            }
200
            $internalName = $node->getInternalName();
201
            if ($internalName) {
202
                $this->nodesByInternalName[$internalName][] = $node;
203
            }
204
        }
205
        $this->initialized = true;
206
    }
207
208
    /**
209
     * @return NodeMenuItem[]
210
     */
211
    public function getTopNodes()
212
    {
213
        $this->init();
214
        if (!\is_array($this->topNodeMenuItems)) {
215
            $this->topNodeMenuItems = array();
216
217
            // To be backwards compatible we need to create the top node MenuItems
218
            if (\array_key_exists(0, $this->childNodes)) {
219
                $topNodeMenuItems = $this->getTopNodeMenuItems();
220
221
                $includeHiddenFromNav = $this->includeHiddenFromNav;
222
                $this->topNodeMenuItems = array_filter(
223
                    $topNodeMenuItems,
224 View Code Duplication
                    function (NodeMenuItem $entry) use ($includeHiddenFromNav) {
0 ignored issues
show
Duplication introduced by Wim Vandersmissen
This code seems to be duplicated across 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...
225
                        if ($entry->getNode()->isHiddenFromNav() && !$includeHiddenFromNav) {
226
                            return false;
227
                        }
228
229
                        return true;
230
                    }
231
                );
232
            }
233
        }
234
235
        return $this->topNodeMenuItems;
236
    }
237
238
    /**
239
     * @return NodeMenuItem[]
240
     */
241
    public function getBreadCrumb()
242
    {
243
        $this->init();
244
        if (!\is_array($this->breadCrumb)) {
245
            $this->breadCrumb = array();
246
247
            /* @var NodeRepository $repo */
248
            $repo = $this->em->getRepository(Node::class);
249
250
            // Generate breadcrumb MenuItems - fetch *all* languages so you can link translations if needed
251
            $parentNodes = $repo->getAllParents($this->currentNode);
252
            $parentNodeMenuItem = null;
253
            /* @var Node $parentNode */
254
            foreach ($parentNodes as $parentNode) {
255
                $nodeTranslation = $parentNode->getNodeTranslation(
256
                    $this->locale,
257
                    $this->includeOffline
258
                );
259
                if (!\is_null($nodeTranslation)) {
260
                    $nodeMenuItem = new NodeMenuItem(
261
                        $parentNode,
262
                        $nodeTranslation,
263
                        $parentNodeMenuItem,
264
                        $this
265
                    );
266
                    $this->breadCrumb[] = $nodeMenuItem;
267
                    $parentNodeMenuItem = $nodeMenuItem;
268
                }
269
            }
270
        }
271
272
        return $this->breadCrumb;
273
    }
274
275
    /**
276
     * @return NodeMenuItem|null
277
     */
278 View Code Duplication
    public function getCurrent()
0 ignored issues
show
Duplication introduced by Kris Pypen
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...
279
    {
280
        $this->init();
281
        $breadCrumb = $this->getBreadCrumb();
282
        if (\count($breadCrumb) > 0) {
283
            return $breadCrumb[\count($breadCrumb) - 1];
284
        }
285
286
        return null;
287
    }
288
289
    /**
290
     * @param int $depth
291
     *
292
     * @return NodeMenuItem|null
293
     */
294 View Code Duplication
    public function getActiveForDepth($depth)
0 ignored issues
show
Duplication introduced by Kris Pypen
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...
295
    {
296
        $breadCrumb = $this->getBreadCrumb();
297
        if (\count($breadCrumb) >= $depth) {
298
            return $breadCrumb[$depth - 1];
299
        }
300
301
        return null;
302
    }
303
304
    /**
305
     * @param Node $node
306
     * @param bool $includeHiddenFromNav
307
     *
308
     * @return NodeMenuItem[]
309
     */
310
    public function getChildren(Node $node, $includeHiddenFromNav = true)
311
    {
312
        $this->init();
313
        $children = array();
314
315
        if (\array_key_exists($node->getId(), $this->childNodes)) {
316
            $nodes = $this->childNodes[$node->getId()];
317
            /* @var Node $childNode */
318 View Code Duplication
            foreach ($nodes as $childNode) {
0 ignored issues
show
Bug introduced by Wim Vandersmissen
The expression $nodes of type object<Kunstmaan\NodeBundle\Entity\Node> is not traversable.
Loading history...
Duplication introduced by Wim Vandersmissen
This code seems to be duplicated across 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...
319
                $nodeTranslation = $childNode->getNodeTranslation(
320
                    $this->locale,
321
                    $this->includeOffline
322
                );
323
                if (!\is_null($nodeTranslation)) {
324
                    $children[] = new NodeMenuItem(
325
                        $childNode,
326
                        $nodeTranslation,
327
                        false,
328
                        $this
329
                    );
330
                }
331
            }
332
333
            $children = array_filter(
334
                $children,
335 View Code Duplication
                function (NodeMenuItem $entry) use ($includeHiddenFromNav) {
0 ignored issues
show
Duplication introduced by Wim Vandersmissen
This code seems to be duplicated across 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...
336
                    if ($entry->getNode()->isHiddenFromNav() && !$includeHiddenFromNav) {
337
                        return false;
338
                    }
339
340
                    return true;
341
                }
342
            );
343
        }
344
345
        return $children;
346
    }
347
348
    /**
349
     * @param Node $node
350
     * @param bool $includeHiddenFromNav
351
     *
352
     * @return array|\Kunstmaan\NodeBundle\Helper\NodeMenuItem[]
353
     */
354
    public function getSiblings(Node $node, $includeHiddenFromNav = true)
355
    {
356
        $this->init();
357
        $siblings = array();
358
359
        if (false !== $parent = $this->getParent($node)) {
360
            $siblings = $this->getChildren($parent, $includeHiddenFromNav);
361
362
            foreach ($siblings as $index => $child) {
363
                if ($child === $node) {
364
                    unset($siblings[$index]);
365
                }
366
            }
367
        }
368
369
        return $siblings;
370
    }
371
372
    /**
373
     * @param Node $node
374
     * @param bool $includeHiddenFromNav
375
     *
376
     * @return bool|\Kunstmaan\NodeBundle\Helper\NodeMenuItem
0 ignored issues
show
Documentation introduced by blair
Consider making the return type a bit more specific; maybe use NodeMenuItem|false.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
377
     */
378
    public function getPreviousSibling(Node $node, $includeHiddenFromNav = true)
379
    {
380
        $this->init();
381
382
        if (false !== $parent = $this->getParent($node)) {
383
            $siblings = $this->getChildren($parent, $includeHiddenFromNav);
384
385
            foreach ($siblings as $index => $child) {
386
                if ($child->getNode() === $node && ($index - 1 >= 0)) {
387
                    return $siblings[$index - 1];
388
                }
389
            }
390
        }
391
392
        return false;
393
    }
394
395
    /**
396
     * @param Node $node
397
     * @param bool $includeHiddenFromNav
398
     *
399
     * @return bool|\Kunstmaan\NodeBundle\Helper\NodeMenuItem
0 ignored issues
show
Documentation introduced by blair
Consider making the return type a bit more specific; maybe use NodeMenuItem|false.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
400
     */
401
    public function getNextSibling(Node $node, $includeHiddenFromNav = true)
402
    {
403
        $this->init();
404
405
        if (false !== $parent = $this->getParent($node)) {
406
            $siblings = $this->getChildren($parent, $includeHiddenFromNav);
407
408
            foreach ($siblings as $index => $child) {
409
                if ($child->getNode() === $node && (($index + 1) < \count(
410
                            $siblings
411
                        ))
412
                ) {
413
                    return $siblings[$index + 1];
414
                }
415
            }
416
        }
417
418
        return false;
419
    }
420
421
    /**
422
     * @param Node $node
423
     *
424
     * @return NodeMenuItem
0 ignored issues
show
Documentation introduced by Kristof Jochmans
Should the return type not be Node|false?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
425
     */
426
    public function getParent(Node $node)
427
    {
428
        $this->init();
429
        if ($node->getParent() && \array_key_exists(
430
                $node->getParent()->getId(),
431
                $this->allNodes
432
            )
433
        ) {
434
            return $this->allNodes[$node->getParent()->getId()];
435
        }
436
437
        return false;
438
    }
439
440
    /**
441
     * @param NodeTranslation $parentNode The parent node
442
     * @param string          $slug       The slug
443
     *
444
     * @return NodeTranslation
445
     */
446
    public function getNodeBySlug(NodeTranslation $parentNode, $slug)
447
    {
448
        return $this->em->getRepository(NodeTranslation::class)
0 ignored issues
show
Bug introduced by Jeroen Thora
It seems like you code against a concrete implementation and not the interface Doctrine\Persistence\ObjectRepository as the method getNodeTranslationForSlug() does only exist in the following implementations of said interface: Kunstmaan\NodeBundle\Rep...deTranslationRepository.

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...
449
            ->getNodeTranslationForSlug($slug, $parentNode);
450
    }
451
452
    /**
453
     * @param string                                        $internalName   The
454
     *                                                                      internal
455
     *                                                                      name
456
     * @param NodeTranslation|NodeMenuItem|HasNodeInterface $parent         The
0 ignored issues
show
Documentation introduced by Wim Vandersmissen
Should the type for parameter $parent not be NodeTranslation|NodeMenuItem|HasNodeInterface|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
457
     *                                                                      parent
458
     * @param bool                                          $includeOffline
0 ignored issues
show
Documentation introduced by Kenny Debrauwer
Should the type for parameter $includeOffline not be boolean|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
459
     *
460
     * @return NodeMenuItem|null
461
     */
462
    public function getNodeByInternalName(
463
        $internalName,
464
        $parent = null,
465
        $includeOffline = null
466
    ) {
467
        $this->init();
468
        $resultNode = null;
469
470
        if (\is_null($includeOffline)) {
471
            $includeOffline = $this->includeOffline;
472
        }
473
474
        if (\array_key_exists($internalName, $this->nodesByInternalName)) {
475
            $nodes = $this->nodesByInternalName[$internalName];
476
            $nodes = array_filter(
477
                $nodes,
478
                function (Node $entry) use ($includeOffline) {
479
                    if ($entry->isDeleted() && !$includeOffline) {
480
                        return false;
481
                    }
482
483
                    return true;
484
                }
485
            );
486
487
            if (!\is_null($parent)) {
488
                $parentNode = null;
489
                /** @var Node $parentNode */
490
                if ($parent instanceof NodeTranslation) {
491
                    $parentNode = $parent->getNode();
492
                } elseif ($parent instanceof NodeMenuItem) {
493
                    $parentNode = $parent->getNode();
494
                } elseif ($parent instanceof HasNodeInterface) {
495
                    $repo = $this->em->getRepository(
496
                        Node::class
497
                    );
498
                    $parentNode = $repo->getNodeFor($parent);
499
                }
500
501
                // Look for a node with the same parent id
502
                /** @var Node $node */
503
                foreach ($nodes as $node) {
504
                    if ($parentNode && $node->getParent()->getId() == $parentNode->getId()) {
505
                        $resultNode = $node;
506
507
                        break;
508
                    }
509
                }
510
511
                // Look for a node that has an ancestor with the same parent id
512
                if (\is_null($resultNode)) {
513
                    /* @var Node $n */
514
                    foreach ($nodes as $node) {
515
                        $tempNode = $node;
516
                        while (\is_null($resultNode) && !\is_null(
517
                                $tempNode->getParent()
518
                            )) {
519
                            $tempParent = $tempNode->getParent();
520
                            if ($parentNode && $tempParent->getId() == $parentNode->getId()) {
521
                                $resultNode = $node;
522
523
                                break;
524
                            }
525
                            $tempNode = $tempParent;
526
                        }
527
                    }
528
                }
529
            } elseif (\count($nodes) > 0) {
530
                $resultNode = $nodes[0];
531
            }
532
        }
533
534
        if ($resultNode) {
535
            $nodeTranslation = $resultNode->getNodeTranslation(
536
                $this->locale,
537
                $includeOffline
538
            );
539
            if (!\is_null($nodeTranslation)) {
540
                return new NodeMenuItem(
541
                    $resultNode,
542
                    $nodeTranslation,
543
                    false,
544
                    $this
545
                );
546
            }
547
        }
548
549
        return null;
550
    }
551
552
    /**
553
     * Returns the current root node menu item
554
     */
555
    public function getRootNodeMenuItem()
556
    {
557
        if (\is_null($this->rootNodeMenuItem)) {
558
            $rootNode = $this->domainConfiguration->getRootNode();
559
            if (!\is_null($rootNode)) {
560
                $nodeTranslation = $rootNode->getNodeTranslation(
561
                    $this->locale,
562
                    $this->includeOffline
563
                );
564
                $this->rootNodeMenuItem = new NodeMenuItem(
565
                    $rootNode,
566
                    $nodeTranslation,
0 ignored issues
show
Bug introduced by Wim Vandersmissen
It seems like $nodeTranslation defined by $rootNode->getNodeTransl... $this->includeOffline) on line 560 can be null; however, Kunstmaan\NodeBundle\Hel...MenuItem::__construct() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
567
                    false,
568
                    $this
569
                );
570
            } else {
571
                $this->rootNodeMenuItem = $this->breadCrumb[0];
572
            }
573
        }
574
575
        return $this->rootNodeMenuItem;
576
    }
577
578
    /**
579
     * @return bool
580
     */
581
    public function isIncludeOffline()
582
    {
583
        return $this->includeOffline;
584
    }
585
586
    /**
587
     * @return string
588
     */
589
    public function getPermission()
590
    {
591
        return $this->permission;
592
    }
593
594
    /**
595
     * @return BaseUser
596
     */
597
    public function getUser()
598
    {
599
        return $this->tokenStorage->getToken()->getUser();
600
    }
601
602
    /**
603
     * @return EntityManagerInterface
604
     */
605
    public function getEntityManager()
606
    {
607
        return $this->em;
608
    }
609
610
    /**
611
     * @return TokenStorageInterface
612
     */
613
    public function getTokenStorage()
614
    {
615
        return $this->tokenStorage;
616
    }
617
618
    /**
619
     * @return AclHelper
620
     */
621
    public function getAclHelper()
622
    {
623
        return $this->aclHelper;
624
    }
625
626
    /**
627
     * @return string
628
     */
629
    public function getLocale()
630
    {
631
        return $this->locale;
632
    }
633
634
    /**
635
     * @return bool
636
     */
637
    public function isIncludeHiddenFromNav()
638
    {
639
        return $this->includeHiddenFromNav;
640
    }
641
642
    /**
643
     * Check if provided slug is in active path
644
     *
645
     * @param string $slug
646
     *
647
     * @return bool
648
     */
649
    public function getActive($slug)
650
    {
651
        $bc = $this->getBreadCrumb();
652
        foreach ($bc as $bcItem) {
653
            if ($bcItem->getSlug() == $slug) {
654
                return true;
655
            }
656
        }
657
658
        return false;
659
    }
660
661
    /**
662
     * @return bool
663
     */
664
    public function isInitialized()
665
    {
666
        return $this->initialized;
667
    }
668
669
    /**
670
     * @return array
671
     */
672
    private function getTopNodeMenuItems()
673
    {
674
        $topNodeMenuItems = array();
675
        $topNodes = $this->childNodes[0];
676
        /* @var Node $topNode */
677 View Code Duplication
        foreach ($topNodes as $topNode) {
0 ignored issues
show
Bug introduced by Wim Vandersmissen
The expression $topNodes of type object<Kunstmaan\NodeBundle\Entity\Node> is not traversable.
Loading history...
Duplication introduced by Wim Vandersmissen
This code seems to be duplicated across 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...
678
            $nodeTranslation = $topNode->getNodeTranslation(
679
                $this->locale,
680
                $this->includeOffline
681
            );
682
            if (!\is_null($nodeTranslation)) {
683
                $topNodeMenuItems[] = new NodeMenuItem(
684
                    $topNode,
685
                    $nodeTranslation,
686
                    null,
687
                    $this
688
                );
689
            }
690
        }
691
692
        return $topNodeMenuItems;
693
    }
694
}
695