Completed
Push — master ( 67bb58...4e1c5d )
by Grégoire
03:35
created

GroupMenuProvider   A

Complexity

Total Complexity 25

Size/Duplication

Total Lines 138
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 5

Importance

Changes 0
Metric Value
wmc 25
lcom 1
cbo 5
dl 0
loc 138
rs 10
c 0
b 0
f 0

5 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 1
B get() 0 31 9
A has() 0 4 1
B canGenerateMenuItem() 0 36 11
A generateMenuItem() 0 23 3
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of the Sonata Project package.
7
 *
8
 * (c) Thomas Rabaix <[email protected]>
9
 *
10
 * For the full copyright and license information, please view the LICENSE
11
 * file that was distributed with this source code.
12
 */
13
14
namespace Sonata\AdminBundle\Menu\Provider;
15
16
use Knp\Menu\FactoryInterface;
17
use Knp\Menu\ItemInterface;
18
use Knp\Menu\Provider\MenuProviderInterface;
19
use Sonata\AdminBundle\Admin\Pool;
20
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
21
22
/**
23
 * Menu provider based on group options.
24
 *
25
 * @final since sonata-project/admin-bundle 3.52
26
 *
27
 * @author Alexandru Furculita <[email protected]>
28
 */
29
class GroupMenuProvider implements MenuProviderInterface
30
{
31
    /**
32
     * @var FactoryInterface
33
     */
34
    private $menuFactory;
35
36
    /**
37
     * @var Pool
38
     */
39
    private $pool;
40
41
    /**
42
     * @var AuthorizationCheckerInterface
43
     */
44
    private $checker;
45
46
    public function __construct(FactoryInterface $menuFactory, Pool $pool, AuthorizationCheckerInterface $checker)
47
    {
48
        $this->menuFactory = $menuFactory;
49
        $this->pool = $pool;
50
        $this->checker = $checker;
51
    }
52
53
    /**
54
     * Retrieves the menu based on the group options.
55
     *
56
     * @param string $name
57
     *
58
     * @throws \InvalidArgumentException if the menu does not exists
59
     *
60
     * @return \Knp\Menu\ItemInterface
61
     */
62
    public function get($name, array $options = [])
63
    {
64
        $group = $options['group'];
65
66
        $menuItem = $this->menuFactory->createItem($options['name']);
67
68
        if (empty($group['on_top']) || false === $group['on_top']) {
69
            foreach ($group['items'] as $item) {
70
                if ($this->canGenerateMenuItem($item, $group)) {
71
                    $menuItem->addChild($this->generateMenuItem($item, $group));
72
                }
73
            }
74
75
            if (false === $menuItem->hasChildren()) {
76
                $menuItem->setDisplay(false);
77
            } elseif (!empty($group['keep_open'])) {
78
                $menuItem->setAttribute('class', 'keep-open');
79
                $menuItem->setExtra('keep_open', $group['keep_open']);
80
            }
81
        } elseif (1 === \count($group['items'])) {
82
            if ($this->canGenerateMenuItem($group['items'][0], $group)) {
83
                $menuItem = $this->generateMenuItem($group['items'][0], $group);
84
                $menuItem->setExtra('on_top', $group['on_top']);
85
            } else {
86
                $menuItem->setDisplay(false);
87
            }
88
        }
89
        $menuItem->setLabel($group['label']);
90
91
        return $menuItem;
92
    }
93
94
    /**
95
     * Checks whether a menu exists in this provider.
96
     *
97
     * @param string $name
98
     *
99
     * @return bool
100
     */
101
    public function has($name, array $options = [])
102
    {
103
        return 'sonata_group_menu' === $name;
104
    }
105
106
    private function canGenerateMenuItem(array $item, array $group): bool
107
    {
108
        if (isset($item['admin']) && !empty($item['admin'])) {
109
            $admin = $this->pool->getInstance($item['admin']);
110
111
            // skip menu item if no `list` url is available or user doesn't have the LIST access rights
112
            return $admin->hasRoute('list') && $admin->hasAccess('list');
113
        }
114
115
        // Making the checker behave affirmatively even if it's globally unanimous
116
        // Still must be granted unanimously to group and item
117
118
        $isItemGranted = true;
119
        if (!empty($item['roles'])) {
120
            $isItemGranted = false;
121
            foreach ($item['roles'] as $role) {
122
                if ($this->checker->isGranted([$role])) {
123
                    $isItemGranted = true;
124
                    break;
125
                }
126
            }
127
        }
128
129
        $isGroupGranted = true;
130
        if (!empty($group['roles'])) {
131
            $isGroupGranted = false;
132
            foreach ($group['roles'] as $role) {
133
                if ($this->checker->isGranted([$role])) {
134
                    $isGroupGranted = true;
135
                    break;
136
                }
137
            }
138
        }
139
140
        return $isItemGranted && $isGroupGranted;
141
    }
142
143
    private function generateMenuItem(array $item, array $group): ItemInterface
144
    {
145
        if (isset($item['admin']) && !empty($item['admin'])) {
146
            $admin = $this->pool->getInstance($item['admin']);
147
148
            $options = $admin->generateMenuUrl('list', [], $item['route_absolute']);
149
            $options['extras'] = [
150
                'label_catalogue' => $admin->getTranslationDomain(),
151
                'admin' => $admin,
152
            ];
153
154
            return $this->menuFactory->createItem($admin->getLabel(), $options);
155
        }
156
157
        return $this->menuFactory->createItem($item['label'], [
158
            'route' => $item['route'],
159
            'routeParameters' => $item['route_params'],
160
            'routeAbsolute' => $item['route_absolute'],
161
            'extras' => [
162
                'label_catalogue' => $group['label_catalogue'],
163
            ],
164
        ]);
165
    }
166
}
167