Completed
Push — master ( 6d6774...64f3ed )
by Jeroen
11:23 queued 05:13
created

MenuBuilder   A

Complexity

Total Complexity 23

Size/Duplication

Total Lines 186
Duplicated Lines 11.83 %

Coupling/Cohesion

Components 1
Dependencies 3

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 23
lcom 1
cbo 3
dl 22
loc 186
ccs 65
cts 65
cp 1
rs 10
c 0
b 0
f 0

9 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 13 13 2
A addAdaptMenu() 0 5 1
A getCurrent() 0 24 5
A getBreadCrumb() 0 11 2
A getLowestTopChild() 0 12 3
A getTopChildren() 0 13 3
A getChildren() 0 14 3
A getAdaptors() 0 8 2
A sortAdaptors() 9 9 2

How to fix   Duplicated Code   

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:

1
<?php
2
3
namespace Kunstmaan\AdminBundle\Helper\Menu;
4
5
use Symfony\Component\DependencyInjection\ContainerInterface;
6
use Symfony\Component\HttpFoundation\Request;
7
use Symfony\Component\HttpFoundation\RequestStack;
8
9
/**
10
 * The MenuBuilder will build the top menu and the side menu of the admin interface
11
 */
12
class MenuBuilder
13
{
14
    /**
15
     * @var MenuAdaptorInterface[]
16
     */
17
    private $adaptors = array();
18
19
    /**
20
     * @var MenuAdaptorInterface[]
21
     */
22
    private $sorted = array();
23
24
    /**
25
     * @var TopMenuItem[]
26
     */
27
    private $topMenuItems = null;
28
29
    /**
30
     * @var ContainerInterface
31
     */
32
    private $container;
33
34
    /**
35
     * @var MenuItem|null
36
     */
37
    private $currentCache = null;
38
39
    /** @var RequestStack */
40
    private $requestStack;
41
42
    /**
43
     * @param ContainerInterface|RequestStack $requestStack
44
     */
45 7 View Code Duplication
    public function __construct(/* RequestStack */ $requestStack)
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...
46
    {
47 7
        if ($requestStack instanceof ContainerInterface) {
48 1
            @trigger_error(sprintf('Passing the container as the first argument of "%s" is deprecated in KunstmaanAdminBundle 5.4 and will be removed in KunstmaanAdminBundle 6.0. Inject the "request_stack" service instead.', __CLASS__), E_USER_DEPRECATED);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
49
50 1
            $this->container = $requestStack;
51 1
            $this->requestStack = $this->container->get('request_stack');
52
53 1
            return;
54
        }
55
56 6
        $this->requestStack = $requestStack;
57 6
    }
58
59
    /**
60
     * Add menu adaptor
61
     *
62
     * @param MenuAdaptorInterface $adaptor
63
     */
64 2
    public function addAdaptMenu(MenuAdaptorInterface $adaptor, $priority = 0)
65
    {
66 2
        $this->adaptors[$priority][] = $adaptor;
67 2
        unset($this->sorted);
68 2
    }
69
70
    /**
71
     * Get current menu item
72
     *
73
     * @return MenuItem|null
74
     */
75 4
    public function getCurrent()
76
    {
77 4
        if ($this->currentCache !== null) {
78 1
            return $this->currentCache;
79
        }
80
        /* @var $active MenuItem */
81 4
        $active = null;
82
        do {
83
            /* @var MenuItem[] $children */
84 4
            $children = $this->getChildren($active);
85 4
            $foundActiveChild = false;
86 4
            foreach ($children as $child) {
87 4
                if ($child->getActive()) {
88 3
                    $foundActiveChild = true;
89 3
                    $active = $child;
90
91 3
                    break;
92
                }
93
            }
94 4
        } while ($foundActiveChild);
95 4
        $this->currentCache = $active;
96
97 4
        return $active;
98
    }
99
100
    /**
101
     * Get breadcrumb path for current menu item
102
     *
103
     * @return MenuItem[]
104
     */
105 1
    public function getBreadCrumb()
106
    {
107 1
        $result = array();
108 1
        $current = $this->getCurrent();
109 1
        while (!\is_null($current)) {
110 1
            array_unshift($result, $current);
111 1
            $current = $current->getParent();
112
        }
113
114 1
        return $result;
115
    }
116
117
    /**
118
     * Get top parent menu of current menu item
119
     *
120
     * @return TopMenuItem|null
121
     */
122 3
    public function getLowestTopChild()
123
    {
124 3
        $current = $this->getCurrent();
125 3
        while (!\is_null($current)) {
126 2
            if ($current instanceof TopMenuItem) {
127 2
                return $current;
128
            }
129 1
            $current = $current->getParent();
130
        }
131
132 1
        return null;
133
    }
134
135
    /**
136
     * Get all top menu items
137
     *
138
     * @return MenuItem[]
139
     */
140 2
    public function getTopChildren()
141
    {
142 2
        if (\is_null($this->topMenuItems)) {
143
            /* @var $request Request */
144 2
            $request = $this->requestStack->getCurrentRequest();
145 2
            $this->topMenuItems = array();
146 2
            foreach ($this->getAdaptors() as $menuAdaptor) {
0 ignored issues
show
Bug introduced by
The expression $this->getAdaptors() of type null|array<integer,objec...\MenuAdaptorInterface>> is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
147 2
                $menuAdaptor->adaptChildren($this, $this->topMenuItems, null, $request);
148
            }
149
        }
150
151 2
        return $this->topMenuItems;
152
    }
153
154
    /**
155
     * Get immediate children of the specified menu item
156
     *
157
     * @param MenuItem $parent
0 ignored issues
show
Documentation introduced by
Should the type for parameter $parent not be null|MenuItem?

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...
158
     *
159
     * @return MenuItem[]
160
     */
161 1
    public function getChildren(MenuItem $parent = null)
162
    {
163 1
        if ($parent === null) {
164 1
            return $this->getTopChildren();
165
        }
166
        /* @var $request Request */
167 1
        $request = $this->requestStack->getCurrentRequest();
168 1
        $result = array();
169 1
        foreach ($this->getAdaptors() as $menuAdaptor) {
0 ignored issues
show
Bug introduced by
The expression $this->getAdaptors() of type null|array<integer,objec...\MenuAdaptorInterface>> is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
170 1
            $menuAdaptor->adaptChildren($this, $result, $parent, $request);
171
        }
172
173 1
        return $result;
174
    }
175
176 2
    private function getAdaptors()
177
    {
178 2
        if (!isset($this->sorted)) {
179 2
            $this->sortAdaptors();
180
        }
181
182 2
        return $this->sorted;
183
    }
184
185
    /**
186
     * Sorts the internal list of adaptors by priority.
187
     */
188 2 View Code Duplication
    private function sortAdaptors()
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...
189
    {
190 2
        $this->sorted = array();
191
192 2
        if (isset($this->adaptors)) {
193 2
            krsort($this->adaptors);
194 2
            $this->sorted = array_merge(...$this->adaptors);
0 ignored issues
show
Documentation Bug introduced by
It seems like array_merge(...$this->adaptors) of type array is incompatible with the declared type array<integer,object<Kun...\MenuAdaptorInterface>> of property $sorted.

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...
195
        }
196 2
    }
197
}
198