Completed
Push — 1.0 ( 3a78b4...c03df0 )
by Kamil
45:57 queued 15:08
created

ResourceController   D

Complexity

Total Complexity 58

Size/Duplication

Total Lines 528
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 21

Importance

Changes 0
Metric Value
wmc 58
lcom 1
cbo 21
dl 0
loc 528
rs 4.5599
c 0
b 0
f 0

9 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 37 1
A showAction() 0 26 2
A indexAction() 0 26 2
C createAction() 0 66 11
C updateAction() 0 79 13
C deleteAction() 0 55 11
C applyStateMachineTransitionAction() 0 61 13
A isGrantedOr403() 0 12 3
A findOr404() 0 8 2

How to fix   Complexity   

Complex Class

Complex classes like ResourceController often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use ResourceController, and based on these observations, apply Extract Interface, too.

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
declare(strict_types=1);
13
14
namespace Sylius\Bundle\ResourceBundle\Controller;
15
16
use Doctrine\Common\Persistence\ObjectManager;
17
use FOS\RestBundle\View\View;
18
use Sylius\Bundle\ResourceBundle\Event\ResourceControllerEvent;
19
use Sylius\Component\Resource\Exception\DeleteHandlingException;
20
use Sylius\Component\Resource\Exception\UpdateHandlingException;
21
use Sylius\Component\Resource\Factory\FactoryInterface;
22
use Sylius\Component\Resource\Metadata\MetadataInterface;
23
use Sylius\Component\Resource\Model\ResourceInterface;
24
use Sylius\Component\Resource\Repository\RepositoryInterface;
25
use Sylius\Component\Resource\ResourceActions;
26
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
27
use Symfony\Component\HttpFoundation\Request;
28
use Symfony\Component\HttpFoundation\Response;
29
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
30
use Symfony\Component\HttpKernel\Exception\HttpException;
31
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
32
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
33
34
class ResourceController extends Controller
35
{
36
    /**
37
     * @var MetadataInterface
38
     */
39
    protected $metadata;
40
41
    /**
42
     * @var RequestConfigurationFactoryInterface
43
     */
44
    protected $requestConfigurationFactory;
45
46
    /**
47
     * @var ViewHandlerInterface
48
     */
49
    protected $viewHandler;
50
51
    /**
52
     * @var RepositoryInterface
53
     */
54
    protected $repository;
55
56
    /**
57
     * @var FactoryInterface
58
     */
59
    protected $factory;
60
61
    /**
62
     * @var NewResourceFactoryInterface
63
     */
64
    protected $newResourceFactory;
65
66
    /**
67
     * @var ObjectManager
68
     */
69
    protected $manager;
70
71
    /**
72
     * @var SingleResourceProviderInterface
73
     */
74
    protected $singleResourceProvider;
75
76
    /**
77
     * @var ResourcesCollectionProviderInterface
78
     */
79
    protected $resourcesCollectionProvider;
80
81
    /**
82
     * @var ResourceFormFactoryInterface
83
     */
84
    protected $resourceFormFactory;
85
86
    /**
87
     * @var RedirectHandlerInterface
88
     */
89
    protected $redirectHandler;
90
91
    /**
92
     * @var FlashHelperInterface
93
     */
94
    protected $flashHelper;
95
96
    /**
97
     * @var AuthorizationCheckerInterface
98
     */
99
    protected $authorizationChecker;
100
101
    /**
102
     * @var EventDispatcherInterface
103
     */
104
    protected $eventDispatcher;
105
106
    /**
107
     * @var StateMachineInterface
108
     */
109
    protected $stateMachine;
110
111
    /**
112
     * @var ResourceUpdateHandlerInterface
113
     */
114
    protected $resourceUpdateHandler;
115
116
    /**
117
     * @var ResourceDeleteHandlerInterface
118
     */
119
    protected $resourceDeleteHandler;
120
121
    /**
122
     * @param MetadataInterface $metadata
123
     * @param RequestConfigurationFactoryInterface $requestConfigurationFactory
124
     * @param ViewHandlerInterface $viewHandler
125
     * @param RepositoryInterface $repository
126
     * @param FactoryInterface $factory
127
     * @param NewResourceFactoryInterface $newResourceFactory
128
     * @param ObjectManager $manager
129
     * @param SingleResourceProviderInterface $singleResourceProvider
130
     * @param ResourcesCollectionProviderInterface $resourcesFinder
131
     * @param ResourceFormFactoryInterface $resourceFormFactory
132
     * @param RedirectHandlerInterface $redirectHandler
133
     * @param FlashHelperInterface $flashHelper
134
     * @param AuthorizationCheckerInterface $authorizationChecker
135
     * @param EventDispatcherInterface $eventDispatcher
136
     * @param StateMachineInterface $stateMachine
137
     * @param ResourceUpdateHandlerInterface $resourceUpdateHandler
138
     * @param ResourceDeleteHandlerInterface $resourceDeleteHandler
139
     */
140
    public function __construct(
141
        MetadataInterface $metadata,
142
        RequestConfigurationFactoryInterface $requestConfigurationFactory,
143
        ViewHandlerInterface $viewHandler,
144
        RepositoryInterface $repository,
145
        FactoryInterface $factory,
146
        NewResourceFactoryInterface $newResourceFactory,
147
        ObjectManager $manager,
148
        SingleResourceProviderInterface $singleResourceProvider,
149
        ResourcesCollectionProviderInterface $resourcesFinder,
150
        ResourceFormFactoryInterface $resourceFormFactory,
151
        RedirectHandlerInterface $redirectHandler,
152
        FlashHelperInterface $flashHelper,
153
        AuthorizationCheckerInterface $authorizationChecker,
154
        EventDispatcherInterface $eventDispatcher,
155
        StateMachineInterface $stateMachine,
156
        ResourceUpdateHandlerInterface $resourceUpdateHandler,
157
        ResourceDeleteHandlerInterface $resourceDeleteHandler
158
    ) {
159
        $this->metadata = $metadata;
160
        $this->requestConfigurationFactory = $requestConfigurationFactory;
161
        $this->viewHandler = $viewHandler;
162
        $this->repository = $repository;
163
        $this->factory = $factory;
164
        $this->newResourceFactory = $newResourceFactory;
165
        $this->manager = $manager;
166
        $this->singleResourceProvider = $singleResourceProvider;
167
        $this->resourcesCollectionProvider = $resourcesFinder;
168
        $this->resourceFormFactory = $resourceFormFactory;
169
        $this->redirectHandler = $redirectHandler;
170
        $this->flashHelper = $flashHelper;
171
        $this->authorizationChecker = $authorizationChecker;
172
        $this->eventDispatcher = $eventDispatcher;
173
        $this->stateMachine = $stateMachine;
174
        $this->resourceUpdateHandler = $resourceUpdateHandler;
175
        $this->resourceDeleteHandler = $resourceDeleteHandler;
176
    }
177
178
    /**
179
     * @param Request $request
180
     *
181
     * @return Response
182
     */
183
    public function showAction(Request $request): Response
184
    {
185
        $configuration = $this->requestConfigurationFactory->create($this->metadata, $request);
186
187
        $this->isGrantedOr403($configuration, ResourceActions::SHOW);
188
        $resource = $this->findOr404($configuration);
189
190
        $this->eventDispatcher->dispatch(ResourceActions::SHOW, $configuration, $resource);
191
192
        $view = View::create($resource);
193
194
        if ($configuration->isHtmlRequest()) {
195
            $view
196
                ->setTemplate($configuration->getTemplate(ResourceActions::SHOW . '.html'))
197
                ->setTemplateVar($this->metadata->getName())
198
                ->setData([
199
                    'configuration' => $configuration,
200
                    'metadata' => $this->metadata,
201
                    'resource' => $resource,
202
                    $this->metadata->getName() => $resource,
203
                ])
204
            ;
205
        }
206
207
        return $this->viewHandler->handle($configuration, $view);
208
    }
209
210
    /**
211
     * @param Request $request
212
     *
213
     * @return Response
214
     */
215
    public function indexAction(Request $request): Response
216
    {
217
        $configuration = $this->requestConfigurationFactory->create($this->metadata, $request);
218
219
        $this->isGrantedOr403($configuration, ResourceActions::INDEX);
220
        $resources = $this->resourcesCollectionProvider->get($configuration, $this->repository);
221
222
        $this->eventDispatcher->dispatchMultiple(ResourceActions::INDEX, $configuration, $resources);
223
224
        $view = View::create($resources);
225
226
        if ($configuration->isHtmlRequest()) {
227
            $view
228
                ->setTemplate($configuration->getTemplate(ResourceActions::INDEX . '.html'))
229
                ->setTemplateVar($this->metadata->getPluralName())
230
                ->setData([
231
                    'configuration' => $configuration,
232
                    'metadata' => $this->metadata,
233
                    'resources' => $resources,
234
                    $this->metadata->getPluralName() => $resources,
235
                ])
236
            ;
237
        }
238
239
        return $this->viewHandler->handle($configuration, $view);
240
    }
241
242
    /**
243
     * @param Request $request
244
     *
245
     * @return Response
246
     */
247
    public function createAction(Request $request): Response
248
    {
249
        $configuration = $this->requestConfigurationFactory->create($this->metadata, $request);
250
251
        $this->isGrantedOr403($configuration, ResourceActions::CREATE);
252
        $newResource = $this->newResourceFactory->create($configuration, $this->factory);
253
254
        $form = $this->resourceFormFactory->create($configuration, $newResource);
255
256
        if ($request->isMethod('POST') && $form->handleRequest($request)->isValid()) {
257
            $newResource = $form->getData();
258
259
            $event = $this->eventDispatcher->dispatchPreEvent(ResourceActions::CREATE, $configuration, $newResource);
260
261
            if ($event->isStopped() && !$configuration->isHtmlRequest()) {
262
                throw new HttpException($event->getErrorCode(), $event->getMessage());
263
            }
264
            if ($event->isStopped()) {
265
                $this->flashHelper->addFlashFromEvent($configuration, $event);
266
267
                if ($event->hasResponse()) {
268
                    return $event->getResponse();
269
                }
270
271
                return $this->redirectHandler->redirectToIndex($configuration, $newResource);
272
            }
273
274
            if ($configuration->hasStateMachine()) {
275
                $this->stateMachine->apply($configuration, $newResource);
276
            }
277
278
            $this->repository->add($newResource);
279
            $postEvent = $this->eventDispatcher->dispatchPostEvent(ResourceActions::CREATE, $configuration, $newResource);
280
281
            if (!$configuration->isHtmlRequest()) {
282
                return $this->viewHandler->handle($configuration, View::create($newResource, Response::HTTP_CREATED));
283
            }
284
285
            $this->flashHelper->addSuccessFlash($configuration, ResourceActions::CREATE, $newResource);
286
287
            if ($postEvent->hasResponse()) {
288
                return $postEvent->getResponse();
289
            }
290
291
            return $this->redirectHandler->redirectToResource($configuration, $newResource);
292
        }
293
294
        if (!$configuration->isHtmlRequest()) {
295
            return $this->viewHandler->handle($configuration, View::create($form, Response::HTTP_BAD_REQUEST));
296
        }
297
298
        $this->eventDispatcher->dispatchInitializeEvent(ResourceActions::CREATE, $configuration, $newResource);
299
300
        $view = View::create()
301
            ->setData([
302
                'configuration' => $configuration,
303
                'metadata' => $this->metadata,
304
                'resource' => $newResource,
305
                $this->metadata->getName() => $newResource,
306
                'form' => $form->createView(),
307
            ])
308
            ->setTemplate($configuration->getTemplate(ResourceActions::CREATE . '.html'))
309
        ;
310
311
        return $this->viewHandler->handle($configuration, $view);
312
    }
313
314
    /**
315
     * @param Request $request
316
     *
317
     * @return Response
318
     */
319
    public function updateAction(Request $request): Response
320
    {
321
        $configuration = $this->requestConfigurationFactory->create($this->metadata, $request);
322
323
        $this->isGrantedOr403($configuration, ResourceActions::UPDATE);
324
        $resource = $this->findOr404($configuration);
325
326
        $form = $this->resourceFormFactory->create($configuration, $resource);
327
328
        if (in_array($request->getMethod(), ['POST', 'PUT', 'PATCH'], true) && $form->handleRequest($request)->isValid()) {
329
            $resource = $form->getData();
330
331
            /** @var ResourceControllerEvent $event */
332
            $event = $this->eventDispatcher->dispatchPreEvent(ResourceActions::UPDATE, $configuration, $resource);
333
334
            if ($event->isStopped() && !$configuration->isHtmlRequest()) {
335
                throw new HttpException($event->getErrorCode(), $event->getMessage());
336
            }
337
            if ($event->isStopped()) {
338
                $this->flashHelper->addFlashFromEvent($configuration, $event);
339
340
                if ($event->hasResponse()) {
341
                    return $event->getResponse();
342
                }
343
344
                return $this->redirectHandler->redirectToResource($configuration, $resource);
345
            }
346
347
            try {
348
                $this->resourceUpdateHandler->handle($resource, $configuration, $this->manager);
349
            } catch (UpdateHandlingException $exception) {
350
                if (!$configuration->isHtmlRequest()) {
351
                    return $this->viewHandler->handle(
352
                        $configuration,
353
                        View::create($form, $exception->getApiResponseCode())
354
                    );
355
                }
356
357
                $this->flashHelper->addErrorFlash($configuration, $exception->getFlash());
358
359
                return $this->redirectHandler->redirectToReferer($configuration);
360
            }
361
362
            $postEvent = $this->eventDispatcher->dispatchPostEvent(ResourceActions::UPDATE, $configuration, $resource);
363
364
            if (!$configuration->isHtmlRequest()) {
365
                $view = $configuration->getParameters()->get('return_content', false) ? View::create($resource, Response::HTTP_OK) : View::create(null, Response::HTTP_NO_CONTENT);
366
367
                return $this->viewHandler->handle($configuration, $view);
368
            }
369
370
            $this->flashHelper->addSuccessFlash($configuration, ResourceActions::UPDATE, $resource);
371
372
            if ($postEvent->hasResponse()) {
373
                return $postEvent->getResponse();
374
            }
375
376
            return $this->redirectHandler->redirectToResource($configuration, $resource);
377
        }
378
379
        if (!$configuration->isHtmlRequest()) {
380
            return $this->viewHandler->handle($configuration, View::create($form, Response::HTTP_BAD_REQUEST));
381
        }
382
383
        $this->eventDispatcher->dispatchInitializeEvent(ResourceActions::UPDATE, $configuration, $resource);
384
385
        $view = View::create()
386
            ->setData([
387
                'configuration' => $configuration,
388
                'metadata' => $this->metadata,
389
                'resource' => $resource,
390
                $this->metadata->getName() => $resource,
391
                'form' => $form->createView(),
392
            ])
393
            ->setTemplate($configuration->getTemplate(ResourceActions::UPDATE . '.html'))
394
        ;
395
396
        return $this->viewHandler->handle($configuration, $view);
397
    }
398
399
    /**
400
     * @param Request $request
401
     *
402
     * @return Response
403
     */
404
    public function deleteAction(Request $request): Response
405
    {
406
        $configuration = $this->requestConfigurationFactory->create($this->metadata, $request);
407
408
        $this->isGrantedOr403($configuration, ResourceActions::DELETE);
409
        $resource = $this->findOr404($configuration);
410
411
        if ($configuration->isCsrfProtectionEnabled() && !$this->isCsrfTokenValid($resource->getId(), $request->request->get('_csrf_token'))) {
412
            throw new HttpException(Response::HTTP_FORBIDDEN, 'Invalid csrf token.');
413
        }
414
415
        $event = $this->eventDispatcher->dispatchPreEvent(ResourceActions::DELETE, $configuration, $resource);
416
417
        if ($event->isStopped() && !$configuration->isHtmlRequest()) {
418
            throw new HttpException($event->getErrorCode(), $event->getMessage());
419
        }
420
        if ($event->isStopped()) {
421
            $this->flashHelper->addFlashFromEvent($configuration, $event);
422
423
            if ($event->hasResponse()) {
424
                return $event->getResponse();
425
            }
426
427
            return $this->redirectHandler->redirectToIndex($configuration, $resource);
428
        }
429
430
        try {
431
            $this->resourceDeleteHandler->handle($resource, $this->repository);
432
        } catch (DeleteHandlingException $exception) {
433
            if (!$configuration->isHtmlRequest()) {
434
                return $this->viewHandler->handle(
435
                    $configuration,
436
                    View::create(null, $exception->getApiResponseCode())
437
                );
438
            }
439
440
            $this->flashHelper->addErrorFlash($configuration, $exception->getFlash());
441
442
            return $this->redirectHandler->redirectToReferer($configuration);
443
        }
444
445
        $postEvent = $this->eventDispatcher->dispatchPostEvent(ResourceActions::DELETE, $configuration, $resource);
446
447
        if (!$configuration->isHtmlRequest()) {
448
            return $this->viewHandler->handle($configuration, View::create(null, Response::HTTP_NO_CONTENT));
449
        }
450
451
        $this->flashHelper->addSuccessFlash($configuration, ResourceActions::DELETE, $resource);
452
453
        if ($postEvent->hasResponse()) {
454
            return $postEvent->getResponse();
455
        }
456
457
        return $this->redirectHandler->redirectToIndex($configuration, $resource);
458
    }
459
460
    /**
461
     * @param Request $request
462
     *
463
     * @return Response
464
     */
465
    public function applyStateMachineTransitionAction(Request $request): Response
466
    {
467
        $configuration = $this->requestConfigurationFactory->create($this->metadata, $request);
468
469
        $this->isGrantedOr403($configuration, ResourceActions::UPDATE);
470
        $resource = $this->findOr404($configuration);
471
472
        if ($configuration->isCsrfProtectionEnabled() && !$this->isCsrfTokenValid($resource->getId(), $request->request->get('_csrf_token'))) {
473
            throw new HttpException(Response::HTTP_FORBIDDEN, 'Invalid CSRF token.');
474
        }
475
476
        $event = $this->eventDispatcher->dispatchPreEvent(ResourceActions::UPDATE, $configuration, $resource);
477
478
        if ($event->isStopped() && !$configuration->isHtmlRequest()) {
479
            throw new HttpException($event->getErrorCode(), $event->getMessage());
480
        }
481
        if ($event->isStopped()) {
482
            $this->flashHelper->addFlashFromEvent($configuration, $event);
483
484
            if ($event->hasResponse()) {
485
                return $event->getResponse();
486
            }
487
488
            return $this->redirectHandler->redirectToResource($configuration, $resource);
489
        }
490
491
        if (!$this->stateMachine->can($configuration, $resource)) {
492
            throw new BadRequestHttpException();
493
        }
494
495
        try {
496
            $this->resourceUpdateHandler->handle($resource, $configuration, $this->manager);
497
        } catch (UpdateHandlingException $exception) {
498
            if (!$configuration->isHtmlRequest()) {
499
                return $this->viewHandler->handle(
500
                    $configuration,
501
                    View::create($resource, $exception->getApiResponseCode())
502
                );
503
            }
504
505
            $this->flashHelper->addErrorFlash($configuration, $exception->getFlash());
506
507
            return $this->redirectHandler->redirectToReferer($configuration);
508
        }
509
510
        $postEvent = $this->eventDispatcher->dispatchPostEvent(ResourceActions::UPDATE, $configuration, $resource);
511
512
        if (!$configuration->isHtmlRequest()) {
513
            $view = $configuration->getParameters()->get('return_content', true) ? View::create($resource, Response::HTTP_OK) : View::create(null, Response::HTTP_NO_CONTENT);
514
515
            return $this->viewHandler->handle($configuration, $view);
516
        }
517
518
        $this->flashHelper->addSuccessFlash($configuration, ResourceActions::UPDATE, $resource);
519
520
        if ($postEvent->hasResponse()) {
521
            return $postEvent->getResponse();
522
        }
523
524
        return $this->redirectHandler->redirectToResource($configuration, $resource);
525
    }
526
527
    /**
528
     * @param RequestConfiguration $configuration
529
     * @param string $permission
530
     *
531
     * @throws AccessDeniedException
532
     */
533
    protected function isGrantedOr403(RequestConfiguration $configuration, string $permission): void
534
    {
535
        if (!$configuration->hasPermission()) {
536
            return;
537
        }
538
539
        $permission = $configuration->getPermission($permission);
540
541
        if (!$this->authorizationChecker->isGranted($configuration, $permission)) {
542
            throw new AccessDeniedException();
543
        }
544
    }
545
546
    /**
547
     * @param RequestConfiguration $configuration
548
     *
549
     * @return ResourceInterface
550
     *
551
     * @throws NotFoundHttpException
552
     */
553
    protected function findOr404(RequestConfiguration $configuration): ResourceInterface
554
    {
555
        if (null === $resource = $this->singleResourceProvider->get($configuration, $this->repository)) {
556
            throw new NotFoundHttpException(sprintf('The "%s" has not been found', $this->metadata->getHumanizedName()));
557
        }
558
559
        return $resource;
560
    }
561
}
562