Completed
Pull Request — master (#317)
by Łukasz
02:15
created

MainMenuListener   A

Complexity

Total Complexity 22

Size/Duplication

Total Lines 141
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 6

Importance

Changes 0
Metric Value
wmc 22
lcom 1
cbo 6
dl 0
loc 141
rs 10
c 0
b 0
f 0

7 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 1
B createMainMenu() 0 29 3
B populateMenu() 0 25 6
B buildSingleItem() 0 19 6
A isSingleItem() 0 4 1
A hasEntry() 0 4 2
A buildItemElements() 0 13 3
1
<?php
2
3
declare(strict_types=1);
4
5
namespace FSi\Bundle\AdminBundle\EventListener;
6
7
use FSi\Bundle\AdminBundle\Admin\Element;
8
use FSi\Bundle\AdminBundle\Admin\ManagerInterface;
9
use FSi\Bundle\AdminBundle\Event\MenuEvent;
10
use FSi\Bundle\AdminBundle\Menu\Builder\Exception\InvalidYamlStructureException;
11
use FSi\Bundle\AdminBundle\Menu\Item\ElementItem;
12
use FSi\Bundle\AdminBundle\Menu\Item\Item;
13
use Symfony\Component\Yaml\Yaml;
14
15
class MainMenuListener
16
{
17
    /**
18
     * @var string
19
     */
20
    private $configFilePath;
21
22
    /**
23
     * @var Yaml
24
     */
25
    private $yaml;
26
27
    /**
28
     * @var ManagerInterface
29
     */
30
    private $manager;
31
32
    public function __construct(ManagerInterface $manager, string $configFilePath)
33
    {
34
        $this->configFilePath = $configFilePath;
35
        $this->yaml = new Yaml();
36
        $this->manager = $manager;
37
    }
38
39
    public function createMainMenu(MenuEvent $event): Item
40
    {
41
        if (defined('Symfony\Component\Yaml\Yaml::PARSE_OBJECT')) {
42
            $config = $this->yaml->parse(
43
                file_get_contents($this->configFilePath),
44
                Yaml::PARSE_OBJECT | Yaml::PARSE_EXCEPTION_ON_INVALID_TYPE
45
            );
46
        } else {
47
            $config = $this->yaml->parse(file_get_contents($this->configFilePath), true, true);
48
        }
49
50
        if (!isset($config['menu'])) {
51
            throw new InvalidYamlStructureException(
52
                sprintf('File "%s" should contain top level "menu:" key', $this->configFilePath)
53
            );
54
        }
55
56
        $menu = $event->getMenu();
57
        $menu->setOptions([
58
            'attr' => [
59
                'id' => 'top-menu',
60
                'class' => 'nav navbar-nav',
61
            ]
62
        ]);
63
64
        $this->populateMenu($menu, $config['menu']);
65
66
        return $menu;
67
    }
68
69
    private function populateMenu(Item $menu, array $configs): void
70
    {
71
        foreach ($configs as $itemConfig) {
72
            $item = $this->buildSingleItem($itemConfig);
73
74
            if (null !== $item) {
75
                $options = ['attr' => ['class' => 'admin-element']];
76
                if ($item instanceof ElementItem) {
77
                    $options['elements'] = $this->buildItemElements($itemConfig);
78
                }
79
                $item->setOptions($options);
80
            }
81
82
            if (null === $item) {
83
                if ($this->isSingleItem($itemConfig)) {
84
                    continue;
85
                }
86
                $item = new Item(key($itemConfig));
87
                $group = array_values($itemConfig);
88
                $this->populateMenu($item, $group[0]);
89
            }
90
91
            $menu->addChild($item);
92
        }
93
    }
94
95
    /**
96
     * @param array|string $itemConfig
97
     * @return Item|null
98
     */
99
    private function buildSingleItem($itemConfig): ?Item
100
    {
101
        if (is_string($itemConfig)) {
102
            if ($this->manager->hasElement($itemConfig)) {
103
                return new ElementItem($itemConfig, $this->manager->getElement($itemConfig));
104
            }
105
106
            return new Item($itemConfig);
107
        }
108
109
        if (!$this->isSingleItem($itemConfig) || !$this->manager->hasElement($itemConfig['id'])) {
110
            return null;
111
        }
112
113
        return new ElementItem(
114
            $this->hasEntry($itemConfig, 'name') ? $itemConfig['name'] : $itemConfig['id'],
115
            $this->manager->getElement($itemConfig['id'])
116
        );
117
    }
118
119
    /**
120
     * @param array|string $itemConfig
121
     * @return bool
122
     */
123
    private function isSingleItem($itemConfig): bool
124
    {
125
        return $this->hasEntry($itemConfig, 'id');
126
    }
127
128
    /**
129
     * @param array|string $itemConfig
130
     * @param string $keyName
131
     * @return bool
132
     */
133
    private function hasEntry($itemConfig, string $keyName): bool
134
    {
135
        return is_array($itemConfig) && array_key_exists($keyName, $itemConfig);
136
    }
137
138
    /**
139
     * @param array|string $itemConfig
140
     * @return Element[]
141
     */
142
    private function buildItemElements($itemConfig): array
143
    {
144
        $elements = [];
145
146
        if ($this->hasEntry($itemConfig, 'elements')) {
147
            $elementIds = (array)$itemConfig['elements'];
148
            foreach ($elementIds as $elementId) {
149
                $elements[] = $this->manager->getElement($elementId);
150
            }
151
        }
152
153
        return $elements;
154
    }
155
}
156