Completed
Push — refonte ( 2cad75...548acb )
by Arnaud
06:10
created

AdminSubscriber::getRedirectionUrl()   B

Complexity

Conditions 5
Paths 5

Size

Total Lines 53

Duplication

Lines 20
Ratio 37.74 %

Importance

Changes 0
Metric Value
dl 20
loc 53
rs 8.7143
c 0
b 0
f 0
cc 5
nc 5
nop 4

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace LAG\AdminBundle\Event\Subscriber;
4
5
use Doctrine\Common\Collections\ArrayCollection;
6
use LAG\AdminBundle\Admin\ActionInterface;
7
use LAG\AdminBundle\Admin\AdminInterface;
8
use LAG\AdminBundle\Configuration\AdminConfiguration;
9
use LAG\AdminBundle\Event\Events\AdminEvent;
10
use LAG\AdminBundle\Event\Events;
11
use LAG\AdminBundle\Event\EntityEvent;
12
use LAG\AdminBundle\Event\MenuEvent;
13
use LAG\AdminBundle\Event\ViewEvent;
14
use LAG\AdminBundle\Exception\Exception;
15
use LAG\AdminBundle\Factory\ActionFactory;
16
use LAG\AdminBundle\Factory\DataProviderFactory;
17
use LAG\AdminBundle\Factory\ViewFactory;
18
use LAG\AdminBundle\LAGAdminBundle;
19
use LAG\AdminBundle\Routing\RoutingLoader;
20
use LAG\AdminBundle\Utils\StringUtils;
21
use LAG\AdminBundle\View\RedirectView;
22
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
23
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
24
use Symfony\Component\Form\FormInterface;
25
use Symfony\Component\HttpFoundation\Request;
26
use Symfony\Component\HttpFoundation\Session\Session;
27
use Symfony\Component\HttpFoundation\Session\SessionInterface;
28
use Symfony\Component\Routing\RouterInterface;
29
use Symfony\Component\Translation\TranslatorInterface;
30
31
class AdminSubscriber implements EventSubscriberInterface
32
{
33
    /**
34
     * @var ActionFactory
35
     */
36
    private $actionFactory;
37
38
    /**
39
     * @var ViewFactory
40
     */
41
    private $viewFactory;
42
43
    /**
44
     * @var EventDispatcherInterface
45
     */
46
    private $eventDispatcher;
47
48
    /**
49
     * @var DataProviderFactory
50
     */
51
    private $dataProviderFactory;
52
53
    /**
54
     * @var Session
55
     */
56
    private $session;
57
58
    /**
59
     * @var TranslatorInterface
60
     */
61
    private $translator;
62
63
    /**
64
     * @var RouterInterface
65
     */
66
    private $router;
67
68
    /**
69
     * @return array
70
     */
71
    public static function getSubscribedEvents()
72
    {
73
        return [
74
            Events::HANDLE_REQUEST => 'handleRequest',
75
            Events::VIEW => 'createView',
76
            Events::ENTITY_LOAD => 'loadEntities',
77
            Events::ENTITY_SAVE => 'saveEntity',
78
        ];
79
    }
80
81
    /**
82
     * AdminSubscriber constructor.
83
     *
84
     * @param ActionFactory            $actionFactory
85
     * @param ViewFactory              $viewFactory
86
     * @param DataProviderFactory      $dataProviderFactory
87
     * @param EventDispatcherInterface $eventDispatcher
88
     * @param SessionInterface         $session
89
     * @param TranslatorInterface      $translator
90
     * @param RouterInterface          $router
91
     */
92
    public function __construct(
93
        ActionFactory $actionFactory,
94
        ViewFactory $viewFactory,
95
        DataProviderFactory $dataProviderFactory,
96
        EventDispatcherInterface $eventDispatcher,
97
        SessionInterface $session,
98
        TranslatorInterface $translator,
99
        RouterInterface $router
100
    ) {
101
        $this->actionFactory = $actionFactory;
102
        $this->viewFactory = $viewFactory;
103
        $this->eventDispatcher = $eventDispatcher;
104
        $this->dataProviderFactory = $dataProviderFactory;
105
        $this->session = $session;
0 ignored issues
show
Documentation Bug introduced by
$session is of type object<Symfony\Component...ssion\SessionInterface>, but the property $session was declared to be of type object<Symfony\Component...dation\Session\Session>. Are you sure that you always receive this specific sub-class here, or does it make sense to add an instanceof check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a given class or a super-class is assigned to a property that is type hinted more strictly.

Either this assignment is in error or an instanceof check should be added for that assignment.

class Alien {}

class Dalek extends Alien {}

class Plot
{
    /** @var  Dalek */
    public $villain;
}

$alien = new Alien();
$plot = new Plot();
if ($alien instanceof Dalek) {
    $plot->villain = $alien;
}
Loading history...
106
        $this->translator = $translator;
107
        $this->router = $router;
108
    }
109
110
    /**
111
     * Define the current action according to the routing configuration.
112
     *
113
     * @param AdminEvent $event
114
     *
115
     * @throws Exception
116
     */
117
    public function handleRequest(AdminEvent $event)
118
    {
119
        $actionName = $event->getRequest()->get('_action');
120
121
        if (null === $actionName) {
122
            throw new Exception('The _action was not found in the request');
123
        }
124
        $admin = $event->getAdmin();
125
        $action = $this->actionFactory->create($actionName, $admin->getName(), $admin->getConfiguration());
126
127
        $event->setAction($action);
128
    }
129
130
    /**
131
     * Create a view using the view factory.
132
     *
133
     * @param ViewEvent $event
134
     */
135
    public function createView(ViewEvent $event)
136
    {
137
        $admin = $event->getAdmin();
138
        $action = $admin->getAction();
139
        $menuEvent = new MenuEvent($admin->getAction()->getConfiguration()->getParameter('menus'));
140
        $this->eventDispatcher->dispatch(Events::MENU, $menuEvent);
141
        $formName = '';
142
143
        // The form name is different according to the current action
144
        if ('edit' === $action->getName()) {
145
            $formName = 'entity';
146
        } else if ('create' === $action->getName()) {
147
            $formName = 'entity';
148
        } else if ('delete' === $action->getName()) {
149
            $formName = 'delete';
150
        }
151
152
        if ($admin->hasForm($formName) &&
153
            $this->shouldRedirect(
154
                $action,
155
                $admin->getForm($formName),
156
                $event->getRequest(),
157
                $admin->getConfiguration())
158
        ) {
159
            $url = $this->getRedirectionUrl(
160
                $admin,
161
                $action,
162
                $admin->getConfiguration(),
163
                $event->getRequest()
164
            );
165
166
            $view = new RedirectView(
167
                $action->getName(),
168
                $admin->getName(),
169
                $action->getConfiguration(),
170
                $admin->getConfiguration()
171
            );
172
            $view->setUrl($url);
173
        } else {
174
            $view = $this->viewFactory->create(
175
                $event->getRequest(),
176
                $action->getName(),
177
                $admin->getName(),
178
                $admin->getConfiguration(),
179
                $action->getConfiguration(),
180
                $admin->getEntities(),
181
                $admin->getForms()
182
            );
183
        }
184
        $event->setView($view);
185
    }
186
187
    /**
188
     * Load entities into the event data to pass them to the Admin.
189
     *
190
     * @param EntityEvent $event
191
     *
192
     * @throws Exception
193
     */
194
    public function loadEntities(EntityEvent $event)
195
    {
196
        $admin = $event->getAdmin();
197
        $configuration = $admin->getConfiguration();
198
        $actionConfiguration = $admin->getAction()->getConfiguration();
199
200
        $dataProvider = $this->dataProviderFactory->get($configuration->getParameter('data_provider'));
201
        $strategy = $actionConfiguration->getParameter('load_strategy');
202
        $class = $configuration->getParameter('entity');
203
204
        if (LAGAdminBundle::LOAD_STRATEGY_NONE === $strategy) {
205
            return;
206
        } else if (LAGAdminBundle::LOAD_STRATEGY_MULTIPLE === $strategy) {
207
            $entities = $dataProvider->getCollection($admin, $event->getFilters());
208
            $event->setEntities($entities);
209
        } else if (LAGAdminBundle::LOAD_STRATEGY_UNIQUE === $strategy) {
210
            $requirements = $actionConfiguration->getParameter('route_requirements');
211
            $identifier = null;
212
213
            foreach ($requirements as $name => $requirement) {
214
                if (null !== $event->getRequest()->get($name)) {
215
                    $identifier = $event->getRequest()->get($name);
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $identifier is correct as $event->getRequest()->get($name) (which targets Symfony\Component\HttpFoundation\Request::get()) seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
216
                    break;
217
                }
218
            }
219
220
            if (null === $identifier) {
221
                throw new Exception('Unable to find a identifier for the class "'.$class.'"');
222
            }
223
            $entity = $dataProvider->get($admin, $identifier);
224
225
            $event->setEntities(new ArrayCollection([
226
                $entity,
227
            ]));
228
        }
229
230
    }
231
232
    /**
233
     * Save an entity.
234
     *
235
     * @param EntityEvent $event
236
     */
237
    public function saveEntity(EntityEvent $event)
238
    {
239
        $admin = $event->getAdmin();
240
        $configuration = $admin->getConfiguration();
241
242
        // Save the entity changes using the configured data provider
243
        $dataProvider = $this
244
            ->dataProviderFactory
245
            ->get($configuration->getParameter('data_provider'))
246
        ;
247
        $dataProvider->save($admin);
248
249
        // Inform the user that the save is successful
250
        $message = $this->translateMessage('save_success', $admin->getName(), $configuration);
251
252
        $this
253
            ->session
254
            ->getFlashBag()
255
            ->add('success', $message)
256
        ;
257
    }
258
259
    /**
260
     * @param string             $message
261
     * @param string             $adminName
262
     * @param AdminConfiguration $configuration
263
     *
264
     * @return string
265
     */
266
    private function translateMessage(string $message, string $adminName, AdminConfiguration $configuration): string
267
    {
268
        $pattern = $configuration->getParameter('translation_pattern');
269
        $message = StringUtils::getTranslationKey($pattern, $adminName, $message);
270
271
        return $this->translator->trans($message);
272
    }
273
274
    /**
275
     * Return true if a redirection view should be created.
276
     *
277
     * @param ActionInterface    $action
278
     * @param FormInterface      $form
279
     * @param Request            $request
280
     * @param AdminConfiguration $configuration
281
     *
282
     * @return bool
283
     */
284
    private function shouldRedirect(
285
        ActionInterface $action,
286
        FormInterface $form,
287
        Request $request,
288
        AdminConfiguration $configuration
289
    ) {
290
        if (!$form->isSubmitted()) {
291
            return false;
292
        }
293
294
        if (!$form->isValid()) {
295
            return false;
296
        }
297
298
        if (!key_exists('list', $configuration->getParameter('actions'))) {
299
            return false;
300
        }
301
302
        // When the create form is submitted, the user should be redirected to the edit action after saving the form
303
        // data
304
        if ('create' === $action->getName()) {
305
            return true;
306
        }
307
308
        // When the delete form is submitted, we should redirect to the list action
309
        if ('delete' === $action->getName()) {
310
            return true;
311
        }
312
313
        if (!$request->get('submit_and_redirect')) {
314
            return false;
315
        }
316
317
        if ('submit_and_redirect' !== $request->get('submit_and_redirect')) {
318
            return false;
319
        }
320
321
        return true;
322
    }
323
324
    /**
325
     * Return the url where the user should be redirected to. An exception will be thrown if no url can be generated.
326
     *
327
     * @param AdminInterface     $admin
328
     * @param ActionInterface    $action
329
     * @param AdminConfiguration $configuration
330
     * @param Request            $request
331
     *
332
     * @return string
333
     *
334
     * @throws Exception
335
     */
336
    private function getRedirectionUrl(
337
        AdminInterface $admin,
338
        ActionInterface $action,
339
        AdminConfiguration $configuration,
340
        Request $request
341
    ): string
342
    {
343 View Code Duplication
        if ('edit' === $action->getName()) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
344
            $routeName = RoutingLoader::generateRouteName(
345
                $admin->getName(),
346
                'list',
347
                $configuration->get('routing_name_pattern')
348
            );
349
            $url = $this->router->generate($routeName);
350
351
            return $url;
352
        }
353
354
        // When the create form is submitted, the user should be redirected to the edit action after saving the form
355
        // data
356
        if ('create' === $action->getName()) {
357
            $targetAction = 'list';
358
            $routeParameters = [];
359
360
            if (!$request->get('submit_and_redirect')) {
361
                $targetAction = 'edit';
362
                $routeParameters = [
363
                    'id' => $admin->getEntities()->first()->getId(),
364
                ];
365
            }
366
            $routeName = RoutingLoader::generateRouteName(
367
                $admin->getName(),
368
                $targetAction,
369
                $configuration->get('routing_name_pattern')
370
            );
371
            $url = $this->router->generate($routeName, $routeParameters);
372
373
            return $url;
374
        }
375
376 View Code Duplication
        if ('delete' === $action->getName()) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
377
            $routeName = RoutingLoader::generateRouteName(
378
                $admin->getName(),
379
                'list',
380
                $configuration->get('routing_name_pattern')
381
            );
382
            $url = $this->router->generate($routeName);
383
384
            return $url;
385
        }
386
387
        throw new Exception('Unable to generate an redirection url for the current action');
388
    }
389
}
390