BreadCrumbBuilder::overwriteItems()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 6
ccs 3
cts 3
cp 1
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
crap 1
1
<?php
2
3
namespace SumoCoders\FrameworkCoreBundle\BreadCrumb;
4
5
use Knp\Menu\FactoryInterface;
6
use Knp\Menu\MenuItem;
7
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
8
use Symfony\Component\HttpFoundation\RequestStack;
9
use SumoCoders\FrameworkCoreBundle\Event\ConfigureMenuEvent;
10
11
final class BreadCrumbBuilder
12
{
13
    /**
14
     * @var bool
15
     */
16
    private $extractFromRoute = true;
17
18
    /**
19
     * @var EventDispatcherInterface
20
     */
21
    private $eventDispatcher;
22
23
    /**
24
     * @var FactoryInterface
25
     */
26
    private $factory;
27
28
    /**
29
     * @var array
30
     */
31
    private $items = [];
32
33
    /**
34
     * @param FactoryInterface         $factory
35
     * @param EventDispatcherInterface $eventDispatcher
36
     */
37 14
    public function __construct(FactoryInterface $factory, EventDispatcherInterface $eventDispatcher)
38
    {
39 14
        $this->factory = $factory;
40 14
        $this->eventDispatcher = $eventDispatcher;
41 14
    }
42
43
    /**
44
     * @param RequestStack $requestStack
45
     * @return \Knp\Menu\ItemInterface
46
     */
47 14
    public function createBreadCrumb(RequestStack $requestStack)
48
    {
49 14
        $this->extractItemsBasedOnTheRequest($requestStack);
50
51 14
        $menu = $this->factory->createItem('root');
52 14
        $menu->setChildrenAttribute('class', 'breadcrumb');
53
54 14
        foreach ($this->items as $i => $item) {
55
            // the last item shouldn't have a link
56 5
            if ((count($this->items) - 1) == $i) {
57 5
                $item->setUri(null);
58
            }
59
60 5
            $menu->addChild($item);
61
        }
62
63 14
        return $menu;
64
    }
65
66
    /**
67
     * @return BreadCrumbBuilder
68
     */
69 14
    public function dontExtractFromTheRequest()
70
    {
71 14
        $this->extractFromRoute = false;
72
73 14
        return $this;
74
    }
75
76
    /**
77
     * Extract the items for the breadcrumb based on a uri
78
     *
79
     * @param string $uri
80
     * @param string $locale
81
     * @return BreadCrumbBuilder
82
     */
83 11
    public function extractItemsBasedOnUri($uri, $locale)
84
    {
85 11
        $this->dontExtractFromTheRequest();
86
87 11
        $item = $this->findItemBasedOnUri(
88 11
            $this->getTheMenu(),
0 ignored issues
show
Compatibility introduced by
$this->getTheMenu() of type object<Knp\Menu\ItemInterface> is not a sub-type of object<Knp\Menu\MenuItem>. It seems like you assume a concrete implementation of the interface Knp\Menu\ItemInterface to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
89 11
            $uri
90
        );
91
92 11
        if ($item !== null) {
93 3
            $this->addItemsBasedOnTheChild($item, $locale);
94
        }
95
96 11
        return $this;
97
    }
98
99
    /**
100
     * Add an item into the breadcrumb
101
     *
102
     * @param MenuItem $item
103
     * @return BreadCrumbBuilder
104
     */
105 1
    public function addItem(MenuItem $item)
106
    {
107 1
        $this->items[] = $item;
108
109 1
        return $this;
110
    }
111
112
    /**
113
     * Add a item into the breadcrumb by passing the label and an optional URI.
114
     *
115
     * @param string $label
116
     * @param string $uri
117
     * @return BreadCrumbBuilder
118
     */
119 2
    public function addSimpleItem($label, $uri = null)
120
    {
121 2
        $item = new MenuItem($label, $this->factory);
122 2
        $item->setLabel($label);
123 2
        if ($uri !== null) {
124 2
            $item->setUri($uri);
125
        }
126
127 2
        $this->items[] = $item;
128
129 2
        return $this;
130
    }
131
132
    /**
133
     * Reset the items and add the given items all at once
134
     *
135
     * @param array $items
136
     * @return BreadCrumbBuilder
137
     */
138 1
    public function overwriteItems(array $items)
139
    {
140 1
        $this->items = $items;
141
142 1
        return $this;
143
    }
144
145
    /**
146
     * Add items into the breadcrumb based on a given child.
147
     *
148
     * @param MenuItem $item
149
     * @param string   $locale
150
     */
151 3
    private function addItemsBasedOnTheChild(MenuItem $item, $locale)
152
    {
153 3
        if ($item !== null) {
154 3
            $items = [];
155 3
            $temporaryItem = $item;
156
157 3
            while ($temporaryItem->getParent() !== null) {
158
                $breadCrumb = new MenuItem($temporaryItem->getName(), $this->factory);
159
                $breadCrumb->setLabel($temporaryItem->getLabel());
160
161
                if ($temporaryItem->getUri() !== '#' && $temporaryItem->getUri() !== null) {
162
                    $breadCrumb->setUri($temporaryItem->getUri());
163
                }
164
                $items[] = $breadCrumb;
165
166
                $temporaryItem = $temporaryItem->getParent();
167
            }
168
169 3
            $home = new MenuItem('core.menu.home', $this->factory);
170 3
            $home->setLabel('core.menu.home');
171 3
            $home->setUri('/' . $locale);
172 3
            $this->items[] = $home;
173
174 3
            $this->items = array_merge($this->items, array_reverse($items));
175
        }
176 3
    }
177
178
    /**
179
     * Grab the menu
180
     *
181
     * This method will use the ConfigureMenuEvent to get all the items
182
     *
183
     * @return \Knp\Menu\ItemInterface
184
     */
185 11
    private function getTheMenu()
186
    {
187 11
        $menu = $this->factory->createItem('root');
188
189 11
        $this->eventDispatcher->dispatch(
190 11
            ConfigureMenuEvent::EVENT_NAME,
191 11
            new ConfigureMenuEvent(
192 11
                $this->factory,
193 11
                $menu
194
            )
195
        );
196
197 11
        return $menu;
198
    }
199
200
    /**
201
     * Find an item in the menu based on its URI
202
     *
203
     * @param MenuItem $menuItem
204
     * @param          $uri
205
     * @return MenuItem|null
206
     */
207 11
    private function findItemBasedOnUri(MenuItem $menuItem, $uri)
208
    {
209 11
        if ($uri === $menuItem->getUri()) {
210 3
            return $menuItem;
211
        }
212
213 8
        if (!$menuItem->hasChildren()) {
214 8
            return null;
215
        }
216
217
        foreach ($menuItem->getChildren() as $child) {
218
            $item = $this->findItemBasedOnUri(
219
                $child,
0 ignored issues
show
Compatibility introduced by
$child of type object<Knp\Menu\ItemInterface> is not a sub-type of object<Knp\Menu\MenuItem>. It seems like you assume a concrete implementation of the interface Knp\Menu\ItemInterface to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
220
                $uri
221
            );
222
223
            if ($item !== null) {
224
                return $item;
225
            }
226
        }
227
228
        return null;
229
    }
230
231
    /**
232
     * Extract the items for the breadcrumb based on request
233
     *
234
     * @param RequestStack $requestStack
235
     */
236 14
    private function extractItemsBasedOnTheRequest(RequestStack $requestStack)
237
    {
238 14
        if (!$this->extractFromRoute) {
239 3
            return;
240
        }
241
242 11
        $this->extractItemsBasedOnUri(
243 11
            $requestStack->getCurrentRequest()->getPathInfo(),
244 11
            $requestStack->getCurrentRequest()->getLocale()
245
        );
246 11
    }
247
}
248