Completed
Pull Request — master (#154)
by Arnaud
04:40
created

MenuFactory   A

Complexity

Total Complexity 14

Size/Duplication

Total Lines 132
Duplicated Lines 0 %

Test Coverage

Coverage 0%

Importance

Changes 3
Bugs 0 Features 0
Metric Value
eloc 45
c 3
b 0
f 0
dl 0
loc 132
ccs 0
cts 48
cp 0
rs 10
wmc 14

7 Methods

Rating   Name   Duplication   Size   Complexity  
A getMenus() 0 3 1
A hasMenu() 0 3 1
A getMenu() 0 7 2
A __construct() 0 8 1
A addExtraMenuItemConfiguration() 0 23 5
A create() 0 18 2
A createMenuItem() 0 14 2
1
<?php
2
3
namespace LAG\AdminBundle\Factory;
4
5
use LAG\AdminBundle\Configuration\ApplicationConfiguration;
6
use LAG\AdminBundle\Configuration\ApplicationConfigurationStorage;
7
use LAG\AdminBundle\Configuration\MenuConfiguration;
8
use LAG\AdminBundle\Configuration\MenuItemConfiguration;
9
use LAG\AdminBundle\Event\Events;
10
use LAG\AdminBundle\Event\Menu\MenuEvent;
11
use LAG\AdminBundle\Exception\Exception;
12
use LAG\AdminBundle\Menu\Menu;
13
use LAG\AdminBundle\Menu\MenuItem;
14
use LAG\AdminBundle\Routing\RoutingLoader;
15
use Symfony\Component\HttpFoundation\RequestStack;
16
use Symfony\Component\OptionsResolver\OptionsResolver;
17
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
18
19
class MenuFactory
20
{
21
    /**
22
     * @var Menu[]
23
     */
24
    private $menus = [];
25
26
    /**
27
     * @var RequestStack
28
     */
29
    private $requestStack;
30
31
    /**
32
     * @var ApplicationConfiguration
33
     */
34
    private $applicationConfiguration;
35
36
    /**
37
     * @var EventDispatcherInterface
38
     */
39
    private $eventDispatcher;
40
41
    /**
42
     * MenuFactory constructor.
43
     */
44
    public function __construct(
45
        RequestStack $requestStack,
46
        ApplicationConfigurationStorage $applicationConfigurationStorage,
47
        EventDispatcherInterface $eventDispatcher
48
    ) {
49
        $this->requestStack = $requestStack;
50
        $this->applicationConfiguration = $applicationConfigurationStorage->getConfiguration();
51
        $this->eventDispatcher = $eventDispatcher;
52
    }
53
54
    /**
55
     * Create a menu item from a configuration array.
56
     */
57
    public function create(string $name, array $configuration): Menu
58
    {
59
        $resolver = new OptionsResolver();
60
        $menuConfiguration = new MenuConfiguration($name, $this->applicationConfiguration->getParameter('title'));
0 ignored issues
show
Unused Code introduced by
The call to LAG\AdminBundle\Configur...guration::__construct() has too many arguments starting with $this->applicationConfig...->getParameter('title'). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

60
        $menuConfiguration = /** @scrutinizer ignore-call */ new MenuConfiguration($name, $this->applicationConfiguration->getParameter('title'));

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
61
        $menuConfiguration->configureOptions($resolver);
62
63
        $menuConfiguration->setParameters($resolver->resolve($configuration));
64
        $menu = new Menu($name, $menuConfiguration);
65
66
        $this->eventDispatcher->dispatch(Events::MENU_CREATE, new MenuEvent($name, $menu));
0 ignored issues
show
Unused Code introduced by
The call to Symfony\Contracts\EventD...erInterface::dispatch() has too many arguments starting with new LAG\AdminBundle\Even...MenuEvent($name, $menu). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

66
        $this->eventDispatcher->/** @scrutinizer ignore-call */ 
67
                                dispatch(Events::MENU_CREATE, new MenuEvent($name, $menu));

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
Bug introduced by
LAG\AdminBundle\Event\Events::MENU_CREATE of type string is incompatible with the type object expected by parameter $event of Symfony\Contracts\EventD...erInterface::dispatch(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

66
        $this->eventDispatcher->dispatch(/** @scrutinizer ignore-type */ Events::MENU_CREATE, new MenuEvent($name, $menu));
Loading history...
67
68
        foreach ($menuConfiguration->getParameter('items') as $itemName => $item) {
69
            $menu->addItem($this->createMenuItem($itemName, $item, $menuConfiguration));
70
        }
71
        $this->eventDispatcher->dispatch(Events::MENU_CREATED, new MenuEvent($name, $menu));
72
        $this->menus[$name] = $menu;
73
74
        return $menu;
75
    }
76
77
    /**
78
     * Create a menu item according to the given configuration.
79
     */
80
    public function createMenuItem(string $name, array $configuration, MenuConfiguration $parentConfiguration): MenuItem
81
    {
82
        // Resolve configuration for the current item
83
        $resolver = new OptionsResolver();
84
        $menuItemConfiguration = new MenuItemConfiguration($name, $parentConfiguration->getParameter('position'));
0 ignored issues
show
Unused Code introduced by
The call to LAG\AdminBundle\Configur...guration::__construct() has too many arguments starting with $parentConfiguration->getParameter('position'). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

84
        $menuItemConfiguration = /** @scrutinizer ignore-call */ new MenuItemConfiguration($name, $parentConfiguration->getParameter('position'));

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
85
        $menuItemConfiguration->configureOptions($resolver);
86
        $resolvedConfiguration = $resolver->resolve($configuration);
87
88
        if ($this->applicationConfiguration->getParameter('enable_extra_configuration')) {
89
            $this->addExtraMenuItemConfiguration($resolvedConfiguration);
90
        }
91
        $menuItemConfiguration->setParameters($resolvedConfiguration);
92
93
        return new MenuItem($menuItemConfiguration);
94
    }
95
96
    /**
97
     * Return true if the menu exists.
98
     */
99
    public function hasMenu(string $name): bool
100
    {
101
        return array_key_exists($name, $this->menus);
102
    }
103
104
    /**
105
     * Return a menu with the given name.
106
     *
107
     * @throws Exception
108
     */
109
    public function getMenu(string $name): Menu
110
    {
111
        if (!$this->hasMenu($name)) {
112
            throw new Exception('Invalid menu name "'.$name.'"');
113
        }
114
115
        return $this->menus[$name];
116
    }
117
118
    /**
119
     * Return all the menus.
120
     *
121
     * @return Menu[]
122
     */
123
    public function getMenus(): array
124
    {
125
        return $this->menus;
126
    }
127
128
    private function addExtraMenuItemConfiguration(&$resolvedConfiguration): void
129
    {
130
        // Determine the current route to add an active css class if the current item route is the current route
131
        $route = $this->requestStack->getCurrentRequest()->attributes->get('_route');
132
        $itemRoute = null;
133
134
        // A route string is not required, an admin and an action can also be provided
135
        if ($resolvedConfiguration['route']) {
136
            $itemRoute = $resolvedConfiguration['route'];
137
        } elseif (null !== $resolvedConfiguration['admin']) {
138
            $itemRoute = RoutingLoader::generateRouteName(
139
                $resolvedConfiguration['admin'],
140
                $resolvedConfiguration['action'],
141
                $this->applicationConfiguration->getParameter('routing_name_pattern')
142
            );
143
        }
144
145
        // Add an "active" css class dor the current route
146
        if ($route === $itemRoute) {
147
            if (!key_exists('class', $resolvedConfiguration['attr'])) {
148
                $resolvedConfiguration['attr']['class'] = '';
149
            }
150
            $resolvedConfiguration['attr']['class'] .= ' active';
151
        }
152
    }
153
}
154