Completed
Pull Request — master (#5091)
by Marko
03:59
created

GroupMenuProvider::generateMenuItem()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 23
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 23
rs 9.0856
c 0
b 0
f 0
cc 3
eloc 14
nc 2
nop 2
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
 * @author Alexandru Furculita <[email protected]>
26
 */
27
class GroupMenuProvider implements MenuProviderInterface
28
{
29
    /**
30
     * @var FactoryInterface
31
     */
32
    private $menuFactory;
33
34
    /**
35
     * @var Pool
36
     */
37
    private $pool;
38
39
    /**
40
     * @var AuthorizationCheckerInterface
41
     */
42
    private $checker;
43
44
    /**
45
     * NEXT_MAJOR: Remove default value null of $checker.
46
     *
47
     * @param AuthorizationCheckerInterface|null $checker
48
     */
49
    public function __construct(FactoryInterface $menuFactory, Pool $pool, $checker = null)
50
    {
51
        $this->menuFactory = $menuFactory;
52
        $this->pool = $pool;
53
54
        /*
55
         * NEXT_MAJOR: Remove this if blocks.
56
         * NEXT_MAJOR: Move AuthorizationCheckerInterface check to method signature.
57
         */
58
        if (null === $checker) {
59
            @trigger_error(
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...
60
                'Passing no 3rd argument is deprecated since version 3.10 and will be mandatory in 4.0.
61
                Pass Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface as 3rd argument.',
62
                E_USER_DEPRECATED
63
            );
64
        } elseif (!$checker instanceof AuthorizationCheckerInterface) {
65
            throw new \InvalidArgumentException(
66
                'Argument 3 must be an instance of \Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface'
67
            );
68
        }
69
70
        $this->checker = $checker;
71
    }
72
73
    /**
74
     * Retrieves the menu based on the group options.
75
     *
76
     * @param string $name
77
     *
78
     * @throws \InvalidArgumentException if the menu does not exists
79
     *
80
     * @return \Knp\Menu\ItemInterface
81
     */
82
    public function get($name, array $options = [])
83
    {
84
        $group = $options['group'];
85
86
        $menuItem = $this->menuFactory->createItem($options['name']);
87
88
        if (empty($group['on_top']) || false === $group['on_top']) {
89
            foreach ($group['items'] as $item) {
90
                if ($this->canGenerateMenuItem($item, $group)) {
91
                    $menuItem->addChild($this->generateMenuItem($item, $group));
92
                }
93
            }
94
95
            if (false === $menuItem->hasChildren()) {
96
                $menuItem->setDisplay(false);
97
            } elseif (!empty($group['keep_open'])) {
98
                $menuItem->setAttribute('class', 'keep-open');
99
                $menuItem->setExtra('keep_open', $group['keep_open']);
100
            }
101
        } elseif (1 === count($group['items'])) {
102
            if ($this->canGenerateMenuItem($group['items'][0], $group)) {
103
                $menuItem = $this->generateMenuItem($group['items'][0], $group);
104
                $menuItem->setExtra('on_top', $group['on_top']);
105
            } else {
106
                $menuItem->setDisplay(false);
107
            }
108
        }
109
        $menuItem->setLabel($group['label']);
110
111
        return $menuItem;
112
    }
113
114
    /**
115
     * Checks whether a menu exists in this provider.
116
     *
117
     * @param string $name
118
     *
119
     * @return bool
120
     */
121
    public function has($name, array $options = [])
122
    {
123
        return 'sonata_group_menu' === $name;
124
    }
125
126
    /**
127
     * @return bool
128
     */
129
    private function canGenerateMenuItem(array $item, array $group)
130
    {
131
        if (isset($item['admin']) && !empty($item['admin'])) {
132
            $admin = $this->pool->getInstance($item['admin']);
133
134
            // skip menu item if no `list` url is available or user doesn't have the LIST access rights
135
            return $admin->hasRoute('list') && $admin->hasAccess('list');
136
        }
137
138
        //NEXT_MAJOR: Remove if statement of null checker.
139
        return null === $this->checker || (
140
            (empty($item['roles']) || $this->checker->isGranted($item['roles'])) &&
141
            (empty($group['roles']) || $this->checker->isGranted($group['roles']))
142
        );
143
    }
144
145
    /**
146
     * @return ItemInterface
147
     */
148
    private function generateMenuItem(array $item, array $group)
149
    {
150
        if (isset($item['admin']) && !empty($item['admin'])) {
151
            $admin = $this->pool->getInstance($item['admin']);
152
153
            $options = $admin->generateMenuUrl('list', [], $item['route_absolute']);
154
            $options['extras'] = [
155
                'label_catalogue' => $admin->getTranslationDomain(),
156
                'admin' => $admin,
157
            ];
158
159
            return $this->menuFactory->createItem($admin->getLabel(), $options);
160
        }
161
162
        return $this->menuFactory->createItem($item['label'], [
163
            'route' => $item['route'],
164
            'routeParameters' => $item['route_params'],
165
            'routeAbsolute' => $item['route_absolute'],
166
            'extras' => [
167
                'label_catalogue' => $group['label_catalogue'],
168
            ],
169
        ]);
170
    }
171
}
172