Completed
Push — refonte ( 8ee569...42f1aa )
by Arnaud
03:35 queued 01:09
created

AdminExtension::getFunctions()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 13
rs 9.8333
c 0
b 0
f 0
cc 1
nc 1
nop 0
1
<?php
2
3
namespace LAG\AdminBundle\Bridge\Twig\Extension;
4
5
use LAG\AdminBundle\Configuration\ApplicationConfiguration;
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\Field\EntityAwareFieldInterface;
12
use LAG\AdminBundle\Field\FieldInterface;
13
use LAG\AdminBundle\Routing\RoutingLoader;
14
use LAG\AdminBundle\Utils\StringUtilTrait;
15
use LAG\AdminBundle\View\ViewInterface;
16
use Symfony\Component\PropertyAccess\PropertyAccess;
17
use Symfony\Component\Routing\RouterInterface;
18
use Symfony\Component\Translation\TranslatorInterface;
19
use Twig_Environment;
20
use Twig_Extension;
21
use Twig_SimpleFunction;
22
23
class AdminExtension extends Twig_Extension
24
{
25
    use StringUtilTrait;
26
27
    /**
28
     * @var ApplicationConfiguration
29
     */
30
    private $applicationConfiguration;
31
32
    /**
33
     * @var MenuFactory
34
     */
35
    private $menuFactory;
36
37
    /**
38
     * @var Twig_Environment
39
     */
40
    private $twig;
41
42
    /**
43
     * @var RouterInterface
44
     */
45
    private $router;
46
47
    /**
48
     * @var TranslatorInterface
49
     */
50
    private $translator;
51
52
    /**
53
     * @var ConfigurationFactory
54
     */
55
    private $configurationFactory;
56
57
    /**
58
     * AdminExtension constructor.
59
     *
60
     * @param ApplicationConfigurationStorage $applicationConfigurationStorage
61
     * @param MenuFactory                     $menuFactory
62
     * @param Twig_Environment                $twig
63
     * @param RouterInterface                 $router
64
     * @param TranslatorInterface             $translator
65
     * @param ConfigurationFactory            $configurationFactory
66
     */
67
    public function __construct(
68
        ApplicationConfigurationStorage $applicationConfigurationStorage,
69
        MenuFactory $menuFactory,
70
        Twig_Environment $twig,
71
        RouterInterface $router,
72
        TranslatorInterface $translator,
73
        ConfigurationFactory $configurationFactory
74
    ) {
75
        $this->applicationConfiguration = $applicationConfigurationStorage->getConfiguration();
76
        $this->menuFactory = $menuFactory;
77
        $this->twig = $twig;
78
        $this->router = $router;
79
        $this->translator = $translator;
80
        $this->configurationFactory = $configurationFactory;
81
    }
82
83
    public function getFunctions()
84
    {
85
        return [
86
            new Twig_SimpleFunction('admin_config', [$this, 'getApplicationParameter']),
87
            new Twig_SimpleFunction('admin_menu', [$this, 'getMenu'], ['is_safe' => ['html']]),
88
            new Twig_SimpleFunction('admin_has_menu', [$this, 'hasMenu']),
89
            new Twig_SimpleFunction('admin_menu_action', [$this, 'getMenuAction']),
90
            new Twig_SimpleFunction('admin_field_header', [$this, 'getFieldHeader']),
91
            new Twig_SimpleFunction('admin_field', [$this, 'getField']),
92
            new Twig_SimpleFunction('admin_url', [$this, 'getAdminUrl']),
93
            new Twig_SimpleFunction('admin_action_allowed', [$this, 'isAdminActionAllowed']),
94
        ];
95
    }
96
97
    public function getApplicationParameter($name)
98
    {
99
        return $this->applicationConfiguration->getParameter($name);
100
    }
101
102
    /**
103
     * Render a menu according to given name.
104
     *
105
     * @param string             $name
106
     * @param ViewInterface|null $view
107
     *
108
     * @return string
109
     */
110
    public function getMenu(string $name, ViewInterface $view = null)
111
    {
112
        $menu = $this->menuFactory->getMenu($name);
113
114
        return $this->twig->render($menu->get('template'), [
0 ignored issues
show
Bug introduced by
The method get() does not seem to exist on object<LAG\AdminBundle\Menu\Menu>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
115
            'menu' => $menu,
116
            'admin' => $view,
117
        ]);
118
    }
119
120
    /**
121
     * Return true if a menu with the given name exists.
122
     *
123
     * @param string $name
124
     *
125
     * @return bool
126
     */
127
    public function hasMenu(string $name)
128
    {
129
        return $this->menuFactory->hasMenu($name);
130
    }
131
132
    /**
133
     * Return the url of an menu item.
134
     *
135
     * @param MenuItemConfiguration $configuration
136
     * @param ViewInterface         $view
137
     *
138
     * @return string
139
     *
140
     * @throws Exception
141
     */
142
    public function getMenuAction(MenuItemConfiguration $configuration, ViewInterface $view = null)
143
    {
144
        if ($configuration->getParameter('url')) {
145
            return $configuration->getParameter('url');
146
        }
147
148
        if ($configuration->getParameter('admin')) {
149
            $routeName = RoutingLoader::generateRouteName(
150
                $configuration->getParameter('admin'),
151
                $configuration->getParameter('action'),
152
                $this->applicationConfiguration->getParameter('routing_name_pattern')
153
            );
154
        } else {
155
            $routeName = $configuration->getParameter('route');
156
        }
157
        // Map the eventual parameters to the entity
158
        $routeParameters = [];
159
        $configuredParameters = $configuration->getParameter('parameters');
160
161
        if (0 !== count($configuredParameters)) {
162
            if (null === $view) {
163
                throw new Exception('A view should be provided if the menu item route requires parameters');
164
            }
165
            $entity = $view->getEntities()->first();
0 ignored issues
show
Bug introduced by
The method first does only exist in Doctrine\Common\Collections\Collection, but not in Pagerfanta\Pagerfanta.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
166
            $accessor = PropertyAccess::createPropertyAccessor();
167
168
            if (1 !== $view->getEntities()->count()) {
169
                throw new Exception('You can not map route parameters if multiple entities are loaded');
170
            }
171
172
            foreach ($configuredParameters as $name => $requirements) {
173
                $routeParameters[$name] = $accessor->getValue($entity, $name);
174
            }
175
        }
176
177
        return $this->router->generate($routeName, $routeParameters);
178
    }
179
180
    /**
181
     * @param FieldInterface $field
182
     * @return string
183
     *
184
     * @throws Exception
185
     */
186
    public function getFieldHeader(FieldInterface $field)
187
    {
188
        if ($this->startWith($field->getName(), '_')) {
189
            return '';
190
        }
191
192
        if ($this->applicationConfiguration->getParameter('enable_translation')) {
193
            throw new Exception('Translation is not implemented yet');
194
        } else {
195
            $title = $this->camelize($field->getName());
196
            $title = preg_replace('/(?<!\ )[A-Z]/', ' $0', $title);
197
            $title = trim($title);
198
199
            if ('Id' === $title) {
200
                $title = '#';
201
            }
202
        }
203
204
        return $title;
205
    }
206
207
    /**
208
     * Render a field of an entity.
209
     *
210
     * @param FieldInterface $field
211
     * @param                $entity
212
     *
213
     * @return string
214
     */
215
    public function getField(FieldInterface $field, $entity)
216
    {
217
        $value = null;
218
        $accessor = PropertyAccess::createPropertyAccessor();
219
220
        // if name starts with a underscore, it is a custom field, not mapped to the entity
221 View Code Duplication
        if (substr($field->getName(), 0, 1) !== '_') {
222
            // get raw value from object
223
            $value = $accessor->getValue($entity, $field->getName());
224
        }
225
226
        if ($field instanceof EntityAwareFieldInterface) {
227
            $field->setEntity($entity);
228
        }
229
        $render = $field->render($value);
230
231
        return $render;
232
    }
233
234
    /**
235
     * Return the url of an Admin action.
236
     *
237
     * @param ViewInterface $view
238
     * @param string        $actionName
239
     * @param mixed|null    $entity
240
     *
241
     * @return string
242
     *
243
     * @throws Exception
244
     */
245
    public function getAdminUrl(ViewInterface $view, string $actionName, $entity = null)
246
    {
247
        if (!$this->isAdminActionAllowed($view, $actionName)) {
248
            throw new Exception('The action "'.$actionName.'" is not allowed for the admin "'.$view->getName().'"');
249
        }
250
        $configuration = $view->getAdminConfiguration();
251
        $parameters = [];
252
        $routeName = RoutingLoader::generateRouteName(
253
            $view->getName(),
254
            $actionName,
255
            $configuration->getParameter('routing_name_pattern')
256
        );
257
258
        if (null !== $entity) {
259
            $accessor = PropertyAccess::createPropertyAccessor();
260
            $actionConfiguration = $this->configurationFactory->createActionConfiguration(
261
                $actionName,
262
                $configuration->getParameter('actions')[$actionName],
263
                $view->getName(),
264
                $view->getAdminConfiguration()
265
            );
266
267
            foreach ($actionConfiguration->getParameter('route_requirements') as $name => $requirements) {
268
                $parameters[$name] = $accessor->getValue($entity, $name);
269
            }
270
        }
271
272
        return $this->router->generate($routeName, $parameters);
273
    }
274
275
    /**
276
     * Return true if the given action is allowed for the given Admin.
277
     *
278
     * @param ViewInterface $view
279
     * @param string        $actionName
280
     *
281
     * @return bool
282
     */
283
    public function isAdminActionAllowed(ViewInterface $view, string $actionName)
284
    {
285
        $configuration = $view->getAdminConfiguration();
286
287
        return key_exists($actionName, $configuration->getParameter('actions'));
288
    }
289
}
290