Passed
Pull Request — master (#116)
by Arnaud
03:38
created

AdminExtension::getMenu()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 4
nc 1
nop 2
dl 0
loc 7
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace LAG\AdminBundle\Bridge\Twig\Extension;
4
5
use Doctrine\Common\Collections\Collection;
6
use LAG\AdminBundle\Configuration\ApplicationConfigurationStorage;
7
use LAG\AdminBundle\Configuration\MenuItemConfiguration;
8
use LAG\AdminBundle\Exception\Exception;
9
use LAG\AdminBundle\Factory\ConfigurationFactory;
10
use LAG\AdminBundle\Routing\RoutingLoader;
11
use LAG\AdminBundle\View\ViewInterface;
12
use Symfony\Component\PropertyAccess\PropertyAccess;
13
use Symfony\Component\Routing\RouterInterface;
14
use Twig\Extension\AbstractExtension;
15
use Twig\TwigFunction;
16
17
class AdminExtension extends AbstractExtension
18
{
19
    /**
20
     * @var RouterInterface
21
     */
22
    private $router;
23
24
    /**
25
     * @var ConfigurationFactory
26
     */
27
    private $configurationFactory;
28
29
    /**
30
     * @var ApplicationConfigurationStorage
31
     */
32
    private $applicationConfigurationStorage;
33
34
    /**
35
     * AdminExtension constructor.
36
     *
37
     * @param ApplicationConfigurationStorage $applicationConfigurationStorage
38
     * @param RouterInterface                 $router
39
     * @param ConfigurationFactory            $configurationFactory
40
     */
41
    public function __construct(
42
        ApplicationConfigurationStorage $applicationConfigurationStorage,
43
        RouterInterface $router,
44
        ConfigurationFactory $configurationFactory
45
    ) {
46
        $this->router = $router;
47
        $this->configurationFactory = $configurationFactory;
48
        $this->applicationConfigurationStorage = $applicationConfigurationStorage;
49
    }
50
51
    public function getFunctions(): array
52
    {
53
        return [
54
            new TwigFunction('admin_config', [$this, 'getApplicationParameter']),
55
            new TwigFunction('admin_menu_action', [$this, 'getMenuAction']),
56
            new TwigFunction('admin_url', [$this, 'getAdminUrl']),
57
            new TwigFunction('admin_action_allowed', [$this, 'isAdminActionAllowed']),
58
        ];
59
    }
60
61
    public function getApplicationParameter($name)
62
    {
63
        return $this
64
            ->applicationConfigurationStorage
65
            ->getConfiguration()
66
            ->get($name)
67
        ;
68
    }
69
70
    /**
71
     * Return the url of an menu item.
72
     *
73
     * @param MenuItemConfiguration $configuration
74
     * @param ViewInterface         $view
75
     *
76
     * @return string
77
     *
78
     * @throws Exception
79
     */
80
    public function getMenuAction(MenuItemConfiguration $configuration, ViewInterface $view = null): string
81
    {
82
        if ($configuration->getParameter('url')) {
83
            return $configuration->getParameter('url');
84
        }
85
        $routeName = $configuration->getParameter('route');
86
87
        if ($configuration->getParameter('admin')) {
88
            $routeName = RoutingLoader::generateRouteName(
89
                $configuration->getParameter('admin'),
90
                $configuration->getParameter('action'),
91
                $this
92
                    ->applicationConfigurationStorage
93
                    ->getConfiguration()
94
                    ->getParameter('routing_name_pattern')
95
            );
96
        }
97
        // Map the potential parameters to the entity
98
        $routeParameters = [];
99
        $configuredParameters = $configuration->getParameter('parameters');
100
101
        if (0 !== count($configuredParameters)) {
102
            if (null === $view) {
103
                throw new Exception('A view should be provided if the menu item route requires parameters');
104
            }
105
106
            if (!$view->getEntities() instanceof Collection) {
107
                throw new Exception(
108
                    'Entities returned by the view should be a instance of "'.Collection::class.'" to be used in menu action'
109
                );
110
            }
111
112
            if (1 !== $view->getEntities()->count()) {
113
                throw new Exception('You can not map route parameters if multiple entities are loaded');
114
            }
115
            $entity = $view->getEntities()->first();
116
            $accessor = PropertyAccess::createPropertyAccessor();
117
118
            foreach ($configuredParameters as $name => $requirements) {
119
                $routeParameters[$name] = $accessor->getValue($entity, $name);
120
            }
121
        }
122
123
        return $this->router->generate($routeName, $routeParameters);
124
    }
125
126
    /**
127
     * Return the url of an Admin action.
128
     *
129
     * @param ViewInterface $view
130
     * @param string        $actionName
131
     * @param mixed|null    $entity
132
     *
133
     * @return string
134
     *
135
     * @throws Exception
136
     */
137
    public function getAdminUrl(ViewInterface $view, string $actionName, $entity = null)
138
    {
139
        if (!$this->isAdminActionAllowed($view, $actionName)) {
140
            throw new Exception('The action "'.$actionName.'" is not allowed for the admin "'.$view->getName().'"');
141
        }
142
        $configuration = $view->getAdminConfiguration();
143
        $parameters = [];
144
        $routeName = RoutingLoader::generateRouteName(
145
            $view->getName(),
146
            $actionName,
147
            $configuration->getParameter('routing_name_pattern')
148
        );
149
150
        if (null !== $entity) {
151
            $accessor = PropertyAccess::createPropertyAccessor();
152
            $actionConfiguration = $this->configurationFactory->createActionConfiguration(
153
                $actionName,
154
                $configuration->getParameter('actions')[$actionName],
155
                $view->getName(),
156
                $view->getAdminConfiguration()
157
            );
158
159
            foreach ($actionConfiguration->getParameter('route_requirements') as $name => $requirements) {
160
                $parameters[$name] = $accessor->getValue($entity, $name);
161
            }
162
        }
163
164
        return $this->router->generate($routeName, $parameters);
165
    }
166
167
    /**
168
     * Return true if the given action is allowed for the given Admin.
169
     *
170
     * @param ViewInterface $view
171
     * @param string        $actionName
172
     *
173
     * @return bool
174
     */
175
    public function isAdminActionAllowed(ViewInterface $view, string $actionName)
176
    {
177
        $configuration = $view->getAdminConfiguration();
178
179
        return key_exists($actionName, $configuration->getParameter('actions'));
180
    }
181
}
182