Completed
Push — refonte ( a2a436...c098ff )
by Arnaud
07:46
created

AdminSubscriber::shouldRedirect()   B

Complexity

Conditions 7
Paths 7

Size

Total Lines 32

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 32
rs 8.4746
c 0
b 0
f 0
cc 7
nc 7
nop 4
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\AdminEvent;
10
use LAG\AdminBundle\Event\AdminEvents;
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
            AdminEvents::HANDLE_REQUEST => 'handleRequest',
75
            AdminEvents::VIEW => 'createView',
76
            AdminEvents::ENTITY_LOAD => 'loadEntities',
77
            AdminEvents::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(AdminEvents::MENU, $menuEvent);
141
142
        if ($admin->hasForm('entity') &&
143
            $this->shouldRedirect($action, $admin->getForm('entity'), $event->getRequest(), $admin->getConfiguration())) {
144
            $url = $this->getRedirectionUrl(
145
                $admin,
146
                $action,
147
                $admin->getConfiguration(),
148
                $event->getRequest()
149
            );
150
151
            $view = new RedirectView(
152
                $action->getName(),
153
                $admin->getName(),
154
                $action->getConfiguration(),
155
                $admin->getConfiguration()
156
            );
157
            $view->setUrl($url);
158
        } else {
159
            $view = $this->viewFactory->create(
160
                $event->getRequest(),
161
                $action->getName(),
162
                $admin->getName(),
163
                $admin->getConfiguration(),
164
                $action->getConfiguration(),
165
                $admin->getEntities(),
166
                $admin->getForms()
167
            );
168
        }
169
        $event->setView($view);
170
    }
171
172
    /**
173
     * Load entities into the event data to pass them to the Admin.
174
     *
175
     * @param EntityEvent $event
176
     *
177
     * @throws Exception
178
     */
179
    public function loadEntities(EntityEvent $event)
180
    {
181
        $admin = $event->getAdmin();
182
        $configuration = $admin->getConfiguration();
183
        $actionConfiguration = $admin->getAction()->getConfiguration();
184
185
        $dataProvider = $this->dataProviderFactory->get($configuration->getParameter('data_provider'));
186
        $strategy = $actionConfiguration->getParameter('load_strategy');
187
        $class = $configuration->getParameter('entity');
188
189
        if (LAGAdminBundle::LOAD_STRATEGY_NONE === $strategy) {
190
            return;
191
        } else if (LAGAdminBundle::LOAD_STRATEGY_MULTIPLE === $strategy) {
192
            $entities = $dataProvider->getCollection($admin, $event->getFilters());
193
            $event->setEntities($entities);
194
        } else if (LAGAdminBundle::LOAD_STRATEGY_UNIQUE === $strategy) {
195
            $requirements = $actionConfiguration->getParameter('route_requirements');
196
            $identifier = null;
197
198
            foreach ($requirements as $name => $requirement) {
199
                if (null !== $event->getRequest()->get($name)) {
200
                    $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...
201
                    break;
202
                }
203
            }
204
205
            if (null === $identifier) {
206
                throw new Exception('Unable to find a identifier for the class "'.$class.'"');
207
            }
208
            $entity = $dataProvider->get($admin, $identifier);
209
210
            $event->setEntities(new ArrayCollection([
211
                $entity,
212
            ]));
213
        }
214
215
    }
216
217
    /**
218
     * Save an entity.
219
     *
220
     * @param EntityEvent $event
221
     */
222
    public function saveEntity(EntityEvent $event)
223
    {
224
        $admin = $event->getAdmin();
225
        $configuration = $admin->getConfiguration();
226
227
        // Save the entity changes using the configured data provider
228
        $dataProvider = $this
229
            ->dataProviderFactory
230
            ->get($configuration->getParameter('data_provider'))
231
        ;
232
        $dataProvider->save($admin);
233
234
        // Inform the user that the save is successful
235
        $message = $this->translateMessage('save_success', $admin->getName(), $configuration);
236
237
        $this
238
            ->session
239
            ->getFlashBag()
240
            ->add('success', $message)
241
        ;
242
    }
243
244
    private function translateMessage(string $message, string $adminName, AdminConfiguration $configuration): string
245
    {
246
        $pattern = $configuration->getParameter('translation_pattern');
247
        $message = StringUtils::getTranslationKey($pattern, $adminName, $message);
248
249
        return $this->translator->trans($message);
250
    }
251
252
    /**
253
     * Return true if a redirection view should be created.
254
     *
255
     * @param FormInterface      $form
256
     * @param Request            $request
257
     * @param AdminConfiguration $configuration
258
     *
259
     * @return bool
260
     */
261
    private function shouldRedirect(
262
        ActionInterface $action,
263
        FormInterface $form,
264
        Request $request,
265
        AdminConfiguration $configuration
266
    ) {
267
        if (!$form->isSubmitted()) {
268
            return false;
269
        }
270
271
        if (!$form->isValid()) {
272
            return false;
273
        }
274
275
        if (!key_exists('list', $configuration->getParameter('actions'))) {
276
            return false;
277
        }
278
279
        if ('create' === $action->getName()) {
280
            return true;
281
        }
282
283
        if (!$request->get('submit_and_redirect')) {
284
            return false;
285
        }
286
287
        if ('submit_and_redirect' !== $request->get('submit_and_redirect')) {
288
            return false;
289
        }
290
291
        return true;
292
    }
293
294
    private function getRedirectionUrl(
295
        AdminInterface $admin,
296
        ActionInterface $action,
297
        AdminConfiguration $configuration,
298
        Request $request
299
    ): string
300
    {
301
        $url = '';
302
303
        if ('edit' === $action->getName()) {
304
            $routeName = RoutingLoader::generateRouteName(
305
                $admin->getName(),
306
                'list',
307
                $configuration->get('routing_name_pattern')
308
            );
309
            $url = $this->router->generate($routeName);
310
        } else if ('create' === $action->getName()) {
311
            $targetAction = 'list';
312
            $routeParameters = [];
313
314
            if (!$request->get('submit_and_redirect')) {
315
                $targetAction = 'edit';
316
                $routeParameters = [
317
                    'id' => $admin->getEntities()->first()->getId(),
318
                ];
319
            }
320
            $routeName = RoutingLoader::generateRouteName(
321
                $admin->getName(),
322
                $targetAction,
323
                $configuration->get('routing_name_pattern')
324
            );
325
            $url = $this->router->generate($routeName, $routeParameters);
326
        }
327
328
        return $url;
329
    }
330
}
331