Passed
Pull Request — master (#113)
by Arnaud
04:14
created

AdminSubscriber::createView()   A

Complexity

Conditions 5
Paths 8

Size

Total Lines 44
Code Lines 33

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 33
nc 8
nop 1
dl 0
loc 44
rs 9.0808
c 0
b 0
f 0
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\Events\EntityEvent;
12
use LAG\AdminBundle\Event\Events\MenuEvent;
13
use LAG\AdminBundle\Event\Events\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\HttpFoundation\Request;
25
use Symfony\Component\HttpFoundation\Session\Session;
26
use Symfony\Component\HttpFoundation\Session\SessionInterface;
27
use Symfony\Component\Routing\RouterInterface;
28
use Symfony\Component\Translation\TranslatorInterface;
29
30
class AdminSubscriber implements EventSubscriberInterface
31
{
32
    /**
33
     * @var ActionFactory
34
     */
35
    private $actionFactory;
36
37
    /**
38
     * @var ViewFactory
39
     */
40
    private $viewFactory;
41
42
    /**
43
     * @var EventDispatcherInterface
44
     */
45
    private $eventDispatcher;
46
47
    /**
48
     * @var DataProviderFactory
49
     */
50
    private $dataProviderFactory;
51
52
    /**
53
     * @var Session|SessionInterface
54
     */
55
    private $session;
56
57
    /**
58
     * @var TranslatorInterface
59
     */
60
    private $translator;
61
62
    /**
63
     * @var RouterInterface
64
     */
65
    private $router;
66
67
    /**
68
     * @return array
69
     */
70
    public static function getSubscribedEvents()
71
    {
72
        return [
73
            Events::HANDLE_REQUEST => 'handleRequest',
74
            Events::VIEW => 'createView',
75
            Events::ENTITY_LOAD => 'loadEntities',
76
            Events::ENTITY_SAVE => 'saveEntity',
77
        ];
78
    }
79
80
    /**
81
     * AdminSubscriber constructor.
82
     *
83
     * @param ActionFactory            $actionFactory
84
     * @param ViewFactory              $viewFactory
85
     * @param DataProviderFactory      $dataProviderFactory
86
     * @param EventDispatcherInterface $eventDispatcher
87
     * @param SessionInterface         $session
88
     * @param TranslatorInterface      $translator
89
     * @param RouterInterface          $router
90
     */
91
    public function __construct(
92
        ActionFactory $actionFactory,
93
        ViewFactory $viewFactory,
94
        DataProviderFactory $dataProviderFactory,
95
        EventDispatcherInterface $eventDispatcher,
96
        SessionInterface $session,
97
        TranslatorInterface $translator,
98
        RouterInterface $router
99
    ) {
100
        $this->actionFactory = $actionFactory;
101
        $this->viewFactory = $viewFactory;
102
        $this->eventDispatcher = $eventDispatcher;
103
        $this->dataProviderFactory = $dataProviderFactory;
104
        $this->session = $session;
105
        $this->translator = $translator;
106
        $this->router = $router;
107
    }
108
109
    /**
110
     * Define the current action according to the routing configuration.
111
     *
112
     * @param AdminEvent $event
113
     *
114
     * @throws Exception
115
     */
116
    public function handleRequest(AdminEvent $event)
117
    {
118
        $actionName = $event->getRequest()->get('_action');
119
120
        if (null === $actionName) {
121
            throw new Exception('The _action was not found in the request');
122
        }
123
        $admin = $event->getAdmin();
124
        $action = $this->actionFactory->create($actionName, $admin->getName(), $admin->getConfiguration());
125
126
        $event->setAction($action);
127
    }
128
129
    /**
130
     * Create a view using the view factory.
131
     *
132
     * @param ViewEvent $event
133
     */
134
    public function createView(ViewEvent $event)
135
    {
136
        $admin = $event->getAdmin();
137
        $action = $admin->getAction();
138
        $menuEvent = new MenuEvent($admin->getAction()->getConfiguration()->getParameter('menus'));
139
        $this->eventDispatcher->dispatch(Events::MENU, $menuEvent);
140
        $formName = '';
141
142
        // The form name is different according to the current action
143
        if ('edit' === $action->getName()) {
144
            $formName = 'entity';
145
        } elseif ('create' === $action->getName()) {
146
            $formName = 'entity';
147
        } elseif ('delete' === $action->getName()) {
148
            $formName = 'delete';
149
        }
150
151
        if ($this->shouldRedirect($admin, $action, $formName, $event->getRequest(), $admin->getConfiguration())) {
152
            $url = $this->getRedirectionUrl(
153
                $admin,
154
                $action,
155
                $admin->getConfiguration(),
156
                $event->getRequest()
157
            );
158
159
            $view = new RedirectView(
160
                $action->getName(),
161
                $admin->getName(),
162
                $action->getConfiguration(),
163
                $admin->getConfiguration()
164
            );
165
            $view->setUrl($url);
166
        } else {
167
            $view = $this->viewFactory->create(
168
                $event->getRequest(),
169
                $action->getName(),
170
                $admin->getName(),
171
                $admin->getConfiguration(),
172
                $action->getConfiguration(),
173
                $admin->getEntities(),
174
                $admin->getForms()
175
            );
176
        }
177
        $event->setView($view);
178
    }
179
180
    /**
181
     * Load entities into the event data to pass them to the Admin.
182
     *
183
     * @param EntityEvent $event
184
     *
185
     * @throws Exception
186
     */
187
    public function loadEntities(EntityEvent $event)
188
    {
189
        $admin = $event->getAdmin();
190
        $configuration = $admin->getConfiguration();
191
        $actionConfiguration = $admin->getAction()->getConfiguration();
192
193
        $dataProvider = $this->dataProviderFactory->get($configuration->getParameter('data_provider'));
194
        $strategy = $actionConfiguration->getParameter('load_strategy');
195
        $class = $configuration->getParameter('entity');
196
197
        if (LAGAdminBundle::LOAD_STRATEGY_NONE === $strategy) {
198
            return;
199
        } elseif (LAGAdminBundle::LOAD_STRATEGY_MULTIPLE === $strategy) {
200
            $entities = $dataProvider->getCollection($admin, $event->getFilters());
201
            $event->setEntities($entities);
202
        } elseif (LAGAdminBundle::LOAD_STRATEGY_UNIQUE === $strategy) {
203
            $requirements = $actionConfiguration->getParameter('route_requirements');
204
            $identifier = null;
205
206
            foreach ($requirements as $name => $requirement) {
207
                if (null !== $event->getRequest()->get($name)) {
208
                    $identifier = $event->getRequest()->get($name);
209
                    break;
210
                }
211
            }
212
213
            if (null === $identifier) {
214
                throw new Exception('Unable to find a identifier for the class "'.$class.'"');
215
            }
216
            $entity = $dataProvider->get($admin, $identifier);
217
218
            $event->setEntities(new ArrayCollection([
219
                $entity,
220
            ]));
221
        }
222
    }
223
224
    /**
225
     * Save an entity.
226
     *
227
     * @param EntityEvent $event
228
     */
229
    public function saveEntity(EntityEvent $event)
230
    {
231
        $admin = $event->getAdmin();
232
        $configuration = $admin->getConfiguration();
233
234
        // Save the entity changes using the configured data provider
235
        $dataProvider = $this
236
            ->dataProviderFactory
237
            ->get($configuration->getParameter('data_provider'))
238
        ;
239
        $dataProvider->save($admin);
240
241
        // Inform the user that the save is successful
242
        $message = $this->translateMessage('save_success', $admin->getName(), $configuration);
243
244
        $this
245
            ->session
246
            ->getFlashBag()
247
            ->add('success', $message)
248
        ;
249
    }
250
251
    /**
252
     * @param string             $message
253
     * @param string             $adminName
254
     * @param AdminConfiguration $configuration
255
     *
256
     * @return string
257
     */
258
    private function translateMessage(string $message, string $adminName, AdminConfiguration $configuration): string
259
    {
260
        $pattern = $configuration->getParameter('translation_pattern');
261
        $message = StringUtils::getTranslationKey($pattern, $adminName, $message);
262
263
        return $this->translator->trans($message);
264
    }
265
266
    /**
267
     * Return true if a redirection view should be created.
268
     *
269
     * @param AdminInterface     $admin
270
     * @param ActionInterface    $action
271
     * @param string             $formName
272
     * @param Request            $request
273
     * @param AdminConfiguration $configuration
274
     *
275
     * @return bool
276
     */
277
    private function shouldRedirect(
278
        AdminInterface $admin,
279
        ActionInterface $action,
280
        string $formName,
281
        Request $request,
282
        AdminConfiguration $configuration
283
    ) {
284
        if (!$admin->hasForm($formName)) {
285
            return false;
286
        }
287
        $form = $admin->getForm($formName);
288
289
        if (!$form->isSubmitted()) {
290
            return false;
291
        }
292
293
        if (!$form->isValid()) {
294
            return false;
295
        }
296
297
        if (!key_exists('list', $configuration->getParameter('actions'))) {
298
            return false;
299
        }
300
301
        // When the create form is submitted, the user should be redirected to the edit action after saving the form
302
        // data
303
        if ('create' === $action->getName()) {
304
            return true;
305
        }
306
307
        // When the delete form is submitted, we should redirect to the list action
308
        if ('delete' === $action->getName()) {
309
            return true;
310
        }
311
312
        if (!$request->get('submit_and_redirect')) {
313
            return false;
314
        }
315
316
        if ('submit_and_redirect' !== $request->get('submit_and_redirect')) {
317
            return false;
318
        }
319
320
        return true;
321
    }
322
323
    /**
324
     * Return the url where the user should be redirected to. An exception will be thrown if no url can be generated.
325
     *
326
     * @param AdminInterface     $admin
327
     * @param ActionInterface    $action
328
     * @param AdminConfiguration $configuration
329
     * @param Request            $request
330
     *
331
     * @return string
332
     *
333
     * @throws Exception
334
     */
335
    private function getRedirectionUrl(
336
        AdminInterface $admin,
337
        ActionInterface $action,
338
        AdminConfiguration $configuration,
339
        Request $request
340
    ): string {
341
342
        if ('edit' === $action->getName()) {
343
            $routeName = RoutingLoader::generateRouteName(
344
                $admin->getName(),
345
                'list',
346
                $configuration->get('routing_name_pattern')
347
            );
348
            $url = $this->router->generate($routeName);
349
350
            return $url;
351
        }
352
353
        // When the create form is submitted, the user should be redirected to the edit action after saving the form
354
        // data
355
        if ('create' === $action->getName()) {
356
            $targetAction = 'list';
357
            $routeParameters = [];
358
359
            if (!$request->get('submit_and_redirect')) {
360
                $targetAction = 'edit';
361
                $routeParameters = [
362
                    'id' => $admin->getEntities()->first()->getId(),
363
                ];
364
            }
365
            $routeName = RoutingLoader::generateRouteName(
366
                $admin->getName(),
367
                $targetAction,
368
                $configuration->get('routing_name_pattern')
369
            );
370
            $url = $this->router->generate($routeName, $routeParameters);
371
372
            return $url;
373
        }
374
375
        if ('delete' === $action->getName()) {
376
            $routeName = RoutingLoader::generateRouteName(
377
                $admin->getName(),
378
                'list',
379
                $configuration->get('routing_name_pattern')
380
            );
381
            $url = $this->router->generate($routeName);
382
383
            return $url;
384
        }
385
386
        throw new Exception('Unable to generate an redirection url for the current action');
387
    }
388
}
389