Completed
Push — checkout-optimisation ( 4a6bfb...756f29 )
by Kamil
18:24
created

applyStateMachineTransitionAction()   C

Complexity

Conditions 8
Paths 7

Size

Total Lines 47
Code Lines 26

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 47
rs 5.7377
c 0
b 0
f 0
cc 8
eloc 26
nc 7
nop 1
1
<?php
2
3
/*
4
 * This file is part of the Sylius package.
5
 *
6
 * (c) Paweł Jędrzejewski
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Sylius\Bundle\ResourceBundle\Controller;
13
14
use Doctrine\Common\Persistence\ObjectManager;
15
use FOS\RestBundle\View\View;
16
use Sylius\Bundle\ResourceBundle\Event\ResourceControllerEvent;
17
use Sylius\Component\Resource\Exception\UpdateHandlingException;
18
use Sylius\Component\Resource\Factory\FactoryInterface;
19
use Sylius\Component\Resource\Metadata\MetadataInterface;
20
use Sylius\Component\Resource\Repository\RepositoryInterface;
21
use Sylius\Component\Resource\ResourceActions;
22
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
23
use Symfony\Component\HttpFoundation\RedirectResponse;
24
use Symfony\Component\HttpFoundation\Request;
25
use Symfony\Component\HttpFoundation\Response;
26
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
27
use Symfony\Component\HttpKernel\Exception\HttpException;
28
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
29
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
30
31
/**
32
 * @author Paweł Jędrzejewski <[email protected]>
33
 * @author Saša Stamenković <[email protected]>
34
 */
35
class ResourceController extends Controller
36
{
37
    /**
38
     * @var MetadataInterface
39
     */
40
    protected $metadata;
41
42
    /**
43
     * @var RequestConfigurationFactoryInterface
44
     */
45
    protected $requestConfigurationFactory;
0 ignored issues
show
Comprehensibility Naming introduced by
The variable name $requestConfigurationFactory exceeds the maximum configured length of 20.

Very long variable names usually make code harder to read. It is therefore recommended not to make variable names too verbose.

Loading history...
46
47
    /**
48
     * @var ViewHandlerInterface
49
     */
50
    protected $viewHandler;
51
52
    /**
53
     * @var RepositoryInterface
54
     */
55
    protected $repository;
56
57
    /**
58
     * @var FactoryInterface
59
     */
60
    protected $factory;
61
62
    /**
63
     * @var NewResourceFactoryInterface
64
     */
65
    protected $newResourceFactory;
66
67
    /**
68
     * @var ObjectManager
69
     */
70
    protected $manager;
71
72
    /**
73
     * @var SingleResourceProviderInterface
74
     */
75
    protected $singleResourceProvider;
0 ignored issues
show
Comprehensibility Naming introduced by
The variable name $singleResourceProvider exceeds the maximum configured length of 20.

Very long variable names usually make code harder to read. It is therefore recommended not to make variable names too verbose.

Loading history...
76
77
    /**
78
     * @var ResourcesCollectionProviderInterface
79
     */
80
    protected $resourcesCollectionProvider;
0 ignored issues
show
Comprehensibility Naming introduced by
The variable name $resourcesCollectionProvider exceeds the maximum configured length of 20.

Very long variable names usually make code harder to read. It is therefore recommended not to make variable names too verbose.

Loading history...
81
82
    /**
83
     * @var ResourceFormFactoryInterface
84
     */
85
    protected $resourceFormFactory;
86
87
    /**
88
     * @var RedirectHandlerInterface
89
     */
90
    protected $redirectHandler;
91
92
    /**
93
     * @var FlashHelperInterface
94
     */
95
    protected $flashHelper;
96
97
    /**
98
     * @var AuthorizationCheckerInterface
99
     */
100
    protected $authorizationChecker;
101
102
    /**
103
     * @var EventDispatcherInterface
104
     */
105
    protected $eventDispatcher;
106
107
    /**
108
     * @var StateMachineInterface
109
     */
110
    protected $stateMachine;
111
112
    /**
113
     * @var ResourceUpdateHandlerInterface
114
     */
115
    protected $resourceUpdateHandler;
0 ignored issues
show
Comprehensibility Naming introduced by
The variable name $resourceUpdateHandler exceeds the maximum configured length of 20.

Very long variable names usually make code harder to read. It is therefore recommended not to make variable names too verbose.

Loading history...
116
117
    /**
118
     * @param MetadataInterface $metadata
119
     * @param RequestConfigurationFactoryInterface $requestConfigurationFactory
120
     * @param ViewHandlerInterface $viewHandler
121
     * @param RepositoryInterface $repository
122
     * @param FactoryInterface $factory
123
     * @param NewResourceFactoryInterface $newResourceFactory
124
     * @param ObjectManager $manager
125
     * @param SingleResourceProviderInterface $singleResourceProvider
126
     * @param ResourcesCollectionProviderInterface $resourcesFinder
127
     * @param ResourceFormFactoryInterface $resourceFormFactory
128
     * @param RedirectHandlerInterface $redirectHandler
129
     * @param FlashHelperInterface $flashHelper
130
     * @param AuthorizationCheckerInterface $authorizationChecker
131
     * @param EventDispatcherInterface $eventDispatcher
132
     * @param StateMachineInterface $stateMachine
133
     * @param ResourceUpdateHandlerInterface $resourceUpdateHandler
134
     */
135
    public function __construct(
136
        MetadataInterface $metadata,
137
        RequestConfigurationFactoryInterface $requestConfigurationFactory,
0 ignored issues
show
Comprehensibility Naming introduced by
The variable name $requestConfigurationFactory exceeds the maximum configured length of 20.

Very long variable names usually make code harder to read. It is therefore recommended not to make variable names too verbose.

Loading history...
138
        ViewHandlerInterface $viewHandler,
139
        RepositoryInterface $repository,
140
        FactoryInterface $factory,
141
        NewResourceFactoryInterface $newResourceFactory,
142
        ObjectManager $manager,
143
        SingleResourceProviderInterface $singleResourceProvider,
0 ignored issues
show
Comprehensibility Naming introduced by
The variable name $singleResourceProvider exceeds the maximum configured length of 20.

Very long variable names usually make code harder to read. It is therefore recommended not to make variable names too verbose.

Loading history...
144
        ResourcesCollectionProviderInterface $resourcesFinder,
145
        ResourceFormFactoryInterface $resourceFormFactory,
146
        RedirectHandlerInterface $redirectHandler,
147
        FlashHelperInterface $flashHelper,
148
        AuthorizationCheckerInterface $authorizationChecker,
149
        EventDispatcherInterface $eventDispatcher,
150
        StateMachineInterface $stateMachine,
151
        ResourceUpdateHandlerInterface $resourceUpdateHandler
0 ignored issues
show
Comprehensibility Naming introduced by
The variable name $resourceUpdateHandler exceeds the maximum configured length of 20.

Very long variable names usually make code harder to read. It is therefore recommended not to make variable names too verbose.

Loading history...
152
    ) {
153
        $this->metadata = $metadata;
154
        $this->requestConfigurationFactory = $requestConfigurationFactory;
155
        $this->viewHandler = $viewHandler;
156
        $this->repository = $repository;
157
        $this->factory = $factory;
158
        $this->newResourceFactory = $newResourceFactory;
159
        $this->manager = $manager;
160
        $this->singleResourceProvider = $singleResourceProvider;
161
        $this->resourcesCollectionProvider = $resourcesFinder;
162
        $this->resourceFormFactory = $resourceFormFactory;
163
        $this->redirectHandler = $redirectHandler;
164
        $this->flashHelper = $flashHelper;
165
        $this->authorizationChecker = $authorizationChecker;
166
        $this->eventDispatcher = $eventDispatcher;
167
        $this->stateMachine = $stateMachine;
168
        $this->resourceUpdateHandler = $resourceUpdateHandler;
169
    }
170
171
    /**
172
     * @param Request $request
173
     *
174
     * @return Response
175
     */
176
    public function showAction(Request $request)
177
    {
178
        $configuration = $this->requestConfigurationFactory->create($this->metadata, $request);
179
180
        $this->isGrantedOr403($configuration, ResourceActions::SHOW);
181
        $resource = $this->findOr404($configuration);
182
183
        $this->eventDispatcher->dispatch(ResourceActions::SHOW, $configuration, $resource);
184
185
        $view = View::create($resource);
186
187
        if ($configuration->isHtmlRequest()) {
188
            $view
189
                ->setTemplate($configuration->getTemplate(ResourceActions::SHOW . '.html'))
190
                ->setTemplateVar($this->metadata->getName())
191
                ->setData([
192
                    'configuration' => $configuration,
193
                    'metadata' => $this->metadata,
194
                    'resource' => $resource,
195
                    $this->metadata->getName() => $resource,
196
                ])
197
            ;
198
        }
199
200
        return $this->viewHandler->handle($configuration, $view);
201
    }
202
203
    /**
204
     * @param Request $request
205
     *
206
     * @return Response
207
     */
208
    public function indexAction(Request $request)
209
    {
210
        $configuration = $this->requestConfigurationFactory->create($this->metadata, $request);
211
212
        $this->isGrantedOr403($configuration, ResourceActions::INDEX);
213
        $resources = $this->resourcesCollectionProvider->get($configuration, $this->repository);
214
215
        $view = View::create($resources);
216
217
        if ($configuration->isHtmlRequest()) {
218
            $view
219
                ->setTemplate($configuration->getTemplate(ResourceActions::INDEX . '.html'))
220
                ->setTemplateVar($this->metadata->getPluralName())
221
                ->setData([
222
                    'configuration' => $configuration,
223
                    'metadata' => $this->metadata,
224
                    'resources' => $resources,
225
                    $this->metadata->getPluralName() => $resources,
226
                ])
227
            ;
228
        }
229
230
        return $this->viewHandler->handle($configuration, $view);
231
    }
232
233
    /**
234
     * @param Request $request
235
     *
236
     * @return Response
237
     */
238
    public function createAction(Request $request)
239
    {
240
        $configuration = $this->requestConfigurationFactory->create($this->metadata, $request);
241
242
        $this->isGrantedOr403($configuration, ResourceActions::CREATE);
243
        $newResource = $this->newResourceFactory->create($configuration, $this->factory);
244
245
        $form = $this->resourceFormFactory->create($configuration, $newResource);
246
247
        if ($request->isMethod('POST') && $form->handleRequest($request)->isValid()) {
248
            $newResource = $form->getData();
249
250
            $event = $this->eventDispatcher->dispatchPreEvent(ResourceActions::CREATE, $configuration, $newResource);
251
252
            if ($event->isStopped() && !$configuration->isHtmlRequest()) {
253
                throw new HttpException($event->getErrorCode(), $event->getMessage());
254
            }
255
            if ($event->isStopped()) {
256
                $this->flashHelper->addFlashFromEvent($configuration, $event);
257
258
                return $this->redirectHandler->redirectToIndex($configuration, $newResource);
259
            }
260
261
            if ($configuration->hasStateMachine()) {
262
                $this->stateMachine->apply($configuration, $newResource);
263
            }
264
265
            $this->repository->add($newResource);
266
            $this->eventDispatcher->dispatchPostEvent(ResourceActions::CREATE, $configuration, $newResource);
267
268
            if (!$configuration->isHtmlRequest()) {
269
                return $this->viewHandler->handle($configuration, View::create($newResource, Response::HTTP_CREATED));
270
            }
271
272
            $this->flashHelper->addSuccessFlash($configuration, ResourceActions::CREATE, $newResource);
273
274
            return $this->redirectHandler->redirectToResource($configuration, $newResource);
275
        }
276
277
        if (!$configuration->isHtmlRequest()) {
278
            return $this->viewHandler->handle($configuration, View::create($form, Response::HTTP_BAD_REQUEST));
279
        }
280
281
        $this->eventDispatcher->dispatchInitializeEvent(ResourceActions::CREATE, $configuration, $newResource);
282
283
        $view = View::create()
284
            ->setData([
285
                'configuration' => $configuration,
286
                'metadata' => $this->metadata,
287
                'resource' => $newResource,
288
                $this->metadata->getName() => $newResource,
289
                'form' => $form->createView(),
290
            ])
291
            ->setTemplate($configuration->getTemplate(ResourceActions::CREATE . '.html'))
292
        ;
293
294
        return $this->viewHandler->handle($configuration, $view);
295
    }
296
297
    /**
298
     * @param Request $request
299
     *
300
     * @return Response
301
     */
302
    public function updateAction(Request $request)
303
    {
304
        $configuration = $this->requestConfigurationFactory->create($this->metadata, $request);
305
306
        $this->isGrantedOr403($configuration, ResourceActions::UPDATE);
307
        $resource = $this->findOr404($configuration);
308
309
        $form = $this->resourceFormFactory->create($configuration, $resource);
310
311
        if (in_array($request->getMethod(), ['POST', 'PUT', 'PATCH'], true) && $form->handleRequest($request)->isValid()) {
312
            $resource = $form->getData();
313
314
            /** @var ResourceControllerEvent $event */
315
            $event = $this->eventDispatcher->dispatchPreEvent(ResourceActions::UPDATE, $configuration, $resource);
316
317
            if ($event->isStopped() && !$configuration->isHtmlRequest()) {
318
                throw new HttpException($event->getErrorCode(), $event->getMessage());
319
            }
320
            if ($event->isStopped()) {
321
                $this->flashHelper->addFlashFromEvent($configuration, $event);
322
323
                if ($event->hasResponse()) {
324
                    return $event->getResponse();
325
                }
326
327
                return $this->redirectHandler->redirectToResource($configuration, $resource);
328
            }
329
330
            try {
331
                $this->resourceUpdateHandler->handle($resource, $configuration, $this->manager);
332
            } catch (UpdateHandlingException $exception) {
333
                if (!$configuration->isHtmlRequest()) {
334
                    return $this->viewHandler->handle(
335
                        $configuration,
336
                        View::create($form, $exception->getApiResponseCode())
337
                    );
338
                }
339
340
                $this->flashHelper->addErrorFlash($configuration, $exception->getFlash());
341
342
                return $this->redirectHandler->redirectToReferer($configuration);
343
            }
344
345
            $postEvent = $this->eventDispatcher->dispatchPostEvent(ResourceActions::UPDATE, $configuration, $resource);
346
347
            if (!$configuration->isHtmlRequest()) {
348
                return $this->viewHandler->handle($configuration, View::create(null, Response::HTTP_NO_CONTENT));
349
            }
350
351
            $this->flashHelper->addSuccessFlash($configuration, ResourceActions::UPDATE, $resource);
352
353
            if ($postEvent->hasResponse()) {
354
                return $postEvent->getResponse();
355
            }
356
357
            return $this->redirectHandler->redirectToResource($configuration, $resource);
358
        }
359
360
        if (!$configuration->isHtmlRequest()) {
361
            return $this->viewHandler->handle($configuration, View::create($form, Response::HTTP_BAD_REQUEST));
362
        }
363
364
        $this->eventDispatcher->dispatchInitializeEvent(ResourceActions::UPDATE, $configuration, $resource);
365
366
        $view = View::create()
367
            ->setData([
368
                'configuration' => $configuration,
369
                'metadata' => $this->metadata,
370
                'resource' => $resource,
371
                $this->metadata->getName() => $resource,
372
                'form' => $form->createView(),
373
            ])
374
            ->setTemplate($configuration->getTemplate(ResourceActions::UPDATE . '.html'))
375
        ;
376
377
        return $this->viewHandler->handle($configuration, $view);
378
    }
379
380
    /**
381
     * @param Request $request
382
     *
383
     * @return Response
384
     */
385
    public function deleteAction(Request $request)
386
    {
387
        $configuration = $this->requestConfigurationFactory->create($this->metadata, $request);
388
389
        $this->isGrantedOr403($configuration, ResourceActions::DELETE);
390
        $resource = $this->findOr404($configuration);
391
392
        if ($configuration->isCsrfProtectionEnabled() && !$this->isCsrfTokenValid($resource->getId(), $request->request->get('_csrf_token'))) {
393
            throw new HttpException(Response::HTTP_FORBIDDEN, 'Invalid csrf token.');
394
        }
395
396
        $event = $this->eventDispatcher->dispatchPreEvent(ResourceActions::DELETE, $configuration, $resource);
397
398
        if ($event->isStopped() && !$configuration->isHtmlRequest()) {
399
            throw new HttpException($event->getErrorCode(), $event->getMessage());
400
        }
401
        if ($event->isStopped()) {
402
            $this->flashHelper->addFlashFromEvent($configuration, $event);
403
404
            return $this->redirectHandler->redirectToIndex($configuration, $resource);
405
        }
406
407
        $this->repository->remove($resource);
408
        $this->eventDispatcher->dispatchPostEvent(ResourceActions::DELETE, $configuration, $resource);
409
410
        if (!$configuration->isHtmlRequest()) {
411
            return $this->viewHandler->handle($configuration, View::create(null, Response::HTTP_NO_CONTENT));
412
        }
413
414
        $this->flashHelper->addSuccessFlash($configuration, ResourceActions::DELETE, $resource);
415
416
        return $this->redirectHandler->redirectToIndex($configuration, $resource);
417
    }
418
419
    /**
420
     * @param Request $request
421
     *
422
     * @return RedirectResponse
423
     */
424
    public function applyStateMachineTransitionAction(Request $request)
425
    {
426
        $configuration = $this->requestConfigurationFactory->create($this->metadata, $request);
427
428
        $this->isGrantedOr403($configuration, ResourceActions::UPDATE);
429
        $resource = $this->findOr404($configuration);
430
431
        $event = $this->eventDispatcher->dispatchPreEvent(ResourceActions::UPDATE, $configuration, $resource);
432
433
        if ($event->isStopped() && !$configuration->isHtmlRequest()) {
434
            throw new HttpException($event->getErrorCode(), $event->getMessage());
435
        }
436
        if ($event->isStopped()) {
437
            $this->flashHelper->addFlashFromEvent($configuration, $event);
438
439
            return $this->redirectHandler->redirectToResource($configuration, $resource);
440
        }
441
442
        if (!$this->stateMachine->can($configuration, $resource)) {
443
            throw new BadRequestHttpException();
444
        }
445
446
        try {
447
            $this->resourceUpdateHandler->handle($resource, $configuration, $this->manager);
448
        } catch (UpdateHandlingException $exception) {
449
            if (!$configuration->isHtmlRequest()) {
450
                return $this->viewHandler->handle(
451
                    $configuration,
452
                    View::create($resource, $exception->getApiResponseCode())
453
                );
454
            }
455
456
            $this->flashHelper->addErrorFlash($configuration, $exception->getFlash());
457
458
            return $this->redirectHandler->redirectToReferer($configuration);
459
        }
460
461
        $this->eventDispatcher->dispatchPostEvent(ResourceActions::UPDATE, $configuration, $resource);
462
463
        if (!$configuration->isHtmlRequest()) {
464
            return $this->viewHandler->handle($configuration, View::create($resource, Response::HTTP_OK));
465
        }
466
467
        $this->flashHelper->addSuccessFlash($configuration, ResourceActions::UPDATE, $resource);
468
469
        return $this->redirectHandler->redirectToResource($configuration, $resource);
470
    }
471
472
    /**
473
     * @param RequestConfiguration $configuration
474
     * @param string $permission
475
     *
476
     * @throws AccessDeniedException
477
     */
478
    protected function isGrantedOr403(RequestConfiguration $configuration, $permission)
479
    {
480
        if (!$configuration->hasPermission()) {
481
            return;
482
        }
483
484
        $permission = $configuration->getPermission($permission);
485
486
        if (!$this->authorizationChecker->isGranted($configuration, $permission)) {
487
            throw new AccessDeniedException();
488
        }
489
    }
490
491
    /**
492
     * @param RequestConfiguration $configuration
493
     *
494
     * @return \Sylius\Component\Resource\Model\ResourceInterface
495
     *
496
     * @throws NotFoundHttpException
497
     */
498
    protected function findOr404(RequestConfiguration $configuration)
499
    {
500
        if (null === $resource = $this->singleResourceProvider->get($configuration, $this->repository)) {
501
            throw new NotFoundHttpException(sprintf('The "%s" has not been found', $this->metadata->getHumanizedName()));
502
        }
503
504
        return $resource;
505
    }
506
}
507