Completed
Pull Request — master (#116)
by Arnaud
09:48 queued 07:12
created

AdminExtension::getField()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 17
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 8
nc 4
nop 2
dl 0
loc 17
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\Factory\MenuFactory;
11
use LAG\AdminBundle\Routing\RoutingLoader;
12
use LAG\AdminBundle\View\ViewInterface;
13
use Symfony\Component\PropertyAccess\PropertyAccess;
14
use Symfony\Component\Routing\RouterInterface;
15
use Twig_Environment;
16
use Twig_Extension;
17
use Twig_SimpleFunction;
18
19
class AdminExtension extends Twig_Extension
0 ignored issues
show
Deprecated Code introduced by
The class Twig_Extension has been deprecated: since Twig 2.7, use "Twig\Extension\AbstractExtension" instead ( Ignorable by Annotation )

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

19
class AdminExtension extends /** @scrutinizer ignore-deprecated */ Twig_Extension
Loading history...
20
{
21
    /**
22
     * @var MenuFactory
23
     */
24
    private $menuFactory;
25
26
    /**
27
     * @var Twig_Environment
28
     */
29
    private $twig;
30
31
    /**
32
     * @var RouterInterface
33
     */
34
    private $router;
35
36
    /**
37
     * @var ConfigurationFactory
38
     */
39
    private $configurationFactory;
40
41
    /**
42
     * @var ApplicationConfigurationStorage
43
     */
44
    private $applicationConfigurationStorage;
45
46
    /**
47
     * AdminExtension constructor.
48
     *
49
     * @param ApplicationConfigurationStorage $applicationConfigurationStorage
50
     * @param MenuFactory                     $menuFactory
51
     * @param Twig_Environment                $twig
52
     * @param RouterInterface                 $router
53
     * @param ConfigurationFactory            $configurationFactory
54
     */
55
    public function __construct(
56
        ApplicationConfigurationStorage $applicationConfigurationStorage,
57
        MenuFactory $menuFactory,
58
        Twig_Environment $twig,
59
        RouterInterface $router,
60
        ConfigurationFactory $configurationFactory
61
    ) {
62
        $this->menuFactory = $menuFactory;
63
        $this->twig = $twig;
64
        $this->router = $router;
65
        $this->configurationFactory = $configurationFactory;
66
        $this->applicationConfigurationStorage = $applicationConfigurationStorage;
67
    }
68
69
    public function getFunctions()
70
    {
71
        return [
72
            new Twig_SimpleFunction('admin_config', [$this, 'getApplicationParameter']),
0 ignored issues
show
Deprecated Code introduced by
The class Twig_SimpleFunction has been deprecated: since Twig 2.7, use "Twig\TwigFunction" instead ( Ignorable by Annotation )

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

72
            /** @scrutinizer ignore-deprecated */ new Twig_SimpleFunction('admin_config', [$this, 'getApplicationParameter']),
Loading history...
73
            new Twig_SimpleFunction('admin_menu', [$this, 'getMenu'], ['is_safe' => ['html']]),
0 ignored issues
show
Deprecated Code introduced by
The class Twig_SimpleFunction has been deprecated: since Twig 2.7, use "Twig\TwigFunction" instead ( Ignorable by Annotation )

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

73
            /** @scrutinizer ignore-deprecated */ new Twig_SimpleFunction('admin_menu', [$this, 'getMenu'], ['is_safe' => ['html']]),
Loading history...
74
            new Twig_SimpleFunction('admin_has_menu', [$this, 'hasMenu']),
0 ignored issues
show
Deprecated Code introduced by
The class Twig_SimpleFunction has been deprecated: since Twig 2.7, use "Twig\TwigFunction" instead ( Ignorable by Annotation )

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

74
            /** @scrutinizer ignore-deprecated */ new Twig_SimpleFunction('admin_has_menu', [$this, 'hasMenu']),
Loading history...
75
            new Twig_SimpleFunction('admin_menu_action', [$this, 'getMenuAction']),
0 ignored issues
show
Deprecated Code introduced by
The class Twig_SimpleFunction has been deprecated: since Twig 2.7, use "Twig\TwigFunction" instead ( Ignorable by Annotation )

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

75
            /** @scrutinizer ignore-deprecated */ new Twig_SimpleFunction('admin_menu_action', [$this, 'getMenuAction']),
Loading history...
76
            new Twig_SimpleFunction('admin_url', [$this, 'getAdminUrl']),
0 ignored issues
show
Deprecated Code introduced by
The class Twig_SimpleFunction has been deprecated: since Twig 2.7, use "Twig\TwigFunction" instead ( Ignorable by Annotation )

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

76
            /** @scrutinizer ignore-deprecated */ new Twig_SimpleFunction('admin_url', [$this, 'getAdminUrl']),
Loading history...
77
            new Twig_SimpleFunction('admin_action_allowed', [$this, 'isAdminActionAllowed']),
0 ignored issues
show
Deprecated Code introduced by
The class Twig_SimpleFunction has been deprecated: since Twig 2.7, use "Twig\TwigFunction" instead ( Ignorable by Annotation )

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

77
            /** @scrutinizer ignore-deprecated */ new Twig_SimpleFunction('admin_action_allowed', [$this, 'isAdminActionAllowed']),
Loading history...
78
        ];
79
    }
80
81
    public function getApplicationParameter($name)
82
    {
83
        return $this
84
            ->applicationConfigurationStorage
85
            ->getConfiguration()
86
            ->getParameter($name)
87
        ;
88
    }
89
90
    /**
91
     * Render a menu according to given name.
92
     *
93
     * @param string             $name
94
     * @param ViewInterface|null $view
95
     *
96
     * @return string
97
     */
98
    public function getMenu(string $name, ViewInterface $view = null)
99
    {
100
        $menu = $this->menuFactory->getMenu($name);
101
102
        return $this->twig->render($menu->get('template'), [
103
            'menu' => $menu,
104
            'admin' => $view,
105
        ]);
106
    }
107
108
    /**
109
     * Return true if a menu with the given name exists.
110
     *
111
     * @param string $name
112
     *
113
     * @return bool
114
     */
115
    public function hasMenu(string $name): bool
116
    {
117
        return $this->menuFactory->hasMenu($name);
118
    }
119
120
    /**
121
     * Return the url of an menu item.
122
     *
123
     * @param MenuItemConfiguration $configuration
124
     * @param ViewInterface         $view
125
     *
126
     * @return string
127
     *
128
     * @throws Exception
129
     */
130
    public function getMenuAction(MenuItemConfiguration $configuration, ViewInterface $view = null): string
131
    {
132
        if ($configuration->getParameter('url')) {
133
            return $configuration->getParameter('url');
134
        }
135
        $routeName = $configuration->getParameter('route');
136
137
        if ($configuration->getParameter('admin')) {
138
            $routeName = RoutingLoader::generateRouteName(
139
                $configuration->getParameter('admin'),
140
                $configuration->getParameter('action'),
141
                $this
142
                    ->applicationConfigurationStorage
143
                    ->getConfiguration()
144
                    ->getParameter('routing_name_pattern')
145
            );
146
        }
147
        // Map the potential parameters to the entity
148
        $routeParameters = [];
149
        $configuredParameters = $configuration->getParameter('parameters');
150
151
        if (0 !== count($configuredParameters)) {
152
            if (null === $view) {
153
                throw new Exception('A view should be provided if the menu item route requires parameters');
154
            }
155
156
            if (!$view->getEntities() instanceof Collection) {
157
                throw new Exception(
158
                    'Entities returned by the view should be a instance of "'.Collection::class.'" to be used in menu action'
159
                );
160
            }
161
162
            if (1 !== $view->getEntities()->count()) {
163
                throw new Exception('You can not map route parameters if multiple entities are loaded');
164
            }
165
            $entity = $view->getEntities()->first();
166
            $accessor = PropertyAccess::createPropertyAccessor();
167
168
            foreach ($configuredParameters as $name => $requirements) {
169
                $routeParameters[$name] = $accessor->getValue($entity, $name);
170
            }
171
        }
172
173
        return $this->router->generate($routeName, $routeParameters);
174
    }
175
176
    /**
177
     * Return the url of an Admin action.
178
     *
179
     * @param ViewInterface $view
180
     * @param string        $actionName
181
     * @param mixed|null    $entity
182
     *
183
     * @return string
184
     *
185
     * @throws Exception
186
     */
187
    public function getAdminUrl(ViewInterface $view, string $actionName, $entity = null)
188
    {
189
        if (!$this->isAdminActionAllowed($view, $actionName)) {
190
            throw new Exception('The action "'.$actionName.'" is not allowed for the admin "'.$view->getName().'"');
191
        }
192
        $configuration = $view->getAdminConfiguration();
193
        $parameters = [];
194
        $routeName = RoutingLoader::generateRouteName(
195
            $view->getName(),
196
            $actionName,
197
            $configuration->getParameter('routing_name_pattern')
198
        );
199
200
        if (null !== $entity) {
201
            $accessor = PropertyAccess::createPropertyAccessor();
202
            $actionConfiguration = $this->configurationFactory->createActionConfiguration(
203
                $actionName,
204
                $configuration->getParameter('actions')[$actionName],
205
                $view->getName(),
206
                $view->getAdminConfiguration()
207
            );
208
209
            foreach ($actionConfiguration->getParameter('route_requirements') as $name => $requirements) {
210
                $parameters[$name] = $accessor->getValue($entity, $name);
211
            }
212
        }
213
214
        return $this->router->generate($routeName, $parameters);
215
    }
216
217
    /**
218
     * Return true if the given action is allowed for the given Admin.
219
     *
220
     * @param ViewInterface $view
221
     * @param string        $actionName
222
     *
223
     * @return bool
224
     */
225
    public function isAdminActionAllowed(ViewInterface $view, string $actionName)
226
    {
227
        $configuration = $view->getAdminConfiguration();
228
229
        return key_exists($actionName, $configuration->getParameter('actions'));
230
    }
231
}
232