Completed
Push — cleanup/resource-controller ( 6b7ee8 )
by Kamil
30:03
created

ResourceController   D

Complexity

Total Complexity 43

Size/Duplication

Total Lines 468
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 24

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 43
c 1
b 0
f 0
lcom 1
cbo 24
dl 0
loc 468
rs 4.2493

12 Methods

Rating   Name   Duplication   Size   Complexity  
B __construct() 0 33 1
B showAction() 0 26 2
B indexAction() 0 24 2
C createAction() 0 52 8
B updateAction() 0 56 9
B deleteAction() 0 29 5
B applyStateMachineTransitionAction() 0 35 6
A enableAction() 0 4 1
A disableAction() 0 4 1
A toggle() 0 21 3
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
namespace Sylius\Bundle\ResourceBundle\Controller;
13
14
use Doctrine\Common\Persistence\ObjectManager;
15
use FOS\RestBundle\View\View;
16
use Sylius\Component\Resource\Factory\FactoryInterface;
17
use Sylius\Component\Resource\Metadata\MetadataInterface;
18
use Sylius\Component\Resource\Repository\RepositoryInterface;
19
use Sylius\Component\Resource\ResourceActions;
20
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
21
use Symfony\Component\HttpFoundation\RedirectResponse;
22
use Symfony\Component\HttpFoundation\Request;
23
use Symfony\Component\HttpFoundation\Response;
24
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
25
use Symfony\Component\HttpKernel\Exception\HttpException;
26
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
27
use Symfony\Component\PropertyAccess\PropertyAccess;
28
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
29
30
/**
31
 * @author Paweł Jędrzejewski <[email protected]>
32
 * @author Saša Stamenković <[email protected]>
33
 */
34
class ResourceController extends Controller
35
{
36
    /**
37
     * @var MetadataInterface
38
     */
39
    protected $metadata;
40
41
    /**
42
     * @var RequestConfigurationFactoryInterface
43
     */
44
    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...
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;
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...
75
76
    /**
77
     * @var ResourcesCollectionProviderInterface
78
     */
79
    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...
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
     * @param MetadataInterface $metadata
113
     * @param RequestConfigurationFactoryInterface $requestConfigurationFactory
114
     * @param ViewHandlerInterface $viewHandler
115
     * @param RepositoryInterface $repository
116
     * @param FactoryInterface $factory
117
     * @param NewResourceFactoryInterface $newResourceFactory
118
     * @param ObjectManager $manager
119
     * @param SingleResourceProviderInterface $singleResourceProvider
120
     * @param ResourcesCollectionProviderInterface $resourcesFinder
121
     * @param ResourceFormFactoryInterface $resourceFormFactory
122
     * @param RedirectHandlerInterface $redirectHandler
123
     * @param FlashHelperInterface $flashHelper
124
     * @param AuthorizationCheckerInterface $authorizationChecker
125
     * @param EventDispatcherInterface $eventDispatcher
126
     * @param StateMachineInterface $stateMachine
127
     */
128
    public function __construct(
129
        MetadataInterface $metadata,
130
        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...
131
        ViewHandlerInterface $viewHandler,
132
        RepositoryInterface $repository,
133
        FactoryInterface $factory,
134
        NewResourceFactoryInterface $newResourceFactory,
135
        ObjectManager $manager,
136
        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...
137
        ResourcesCollectionProviderInterface $resourcesFinder,
138
        ResourceFormFactoryInterface $resourceFormFactory,
139
        RedirectHandlerInterface $redirectHandler,
140
        FlashHelperInterface $flashHelper,
141
        AuthorizationCheckerInterface $authorizationChecker,
142
        EventDispatcherInterface $eventDispatcher,
143
        StateMachineInterface $stateMachine
144
    ) {
145
        $this->metadata = $metadata;
146
        $this->requestConfigurationFactory = $requestConfigurationFactory;
147
        $this->viewHandler = $viewHandler;
148
        $this->repository = $repository;
149
        $this->factory = $factory;
150
        $this->newResourceFactory = $newResourceFactory;
151
        $this->manager = $manager;
152
        $this->singleResourceProvider = $singleResourceProvider;
153
        $this->resourcesCollectionProvider = $resourcesFinder;
154
        $this->resourceFormFactory = $resourceFormFactory;
155
        $this->redirectHandler = $redirectHandler;
156
        $this->flashHelper = $flashHelper;
157
        $this->authorizationChecker = $authorizationChecker;
158
        $this->eventDispatcher = $eventDispatcher;
159
        $this->stateMachine = $stateMachine;
160
    }
161
162
    /**
163
     * @param Request $request
164
     *
165
     * @return Response
166
     */
167
    public function showAction(Request $request)
168
    {
169
        $configuration = $this->requestConfigurationFactory->create($this->metadata, $request);
170
171
        $this->isGrantedOr403($configuration, ResourceActions::SHOW);
172
        $resource = $this->findOr404($configuration);
173
174
        $this->eventDispatcher->dispatch(ResourceActions::SHOW, $configuration, $resource);
175
176
        $view = View::create($resource);
177
178
        if ($configuration->isHtmlRequest()) {
179
            $view
180
                ->setTemplate($configuration->getTemplate(ResourceActions::SHOW . '.html'))
181
                ->setTemplateVar($this->metadata->getName())
182
                ->setData([
183
                    'configuration' => $configuration,
184
                    'metadata' => $this->metadata,
185
                    'resource' => $resource,
186
                    $this->metadata->getName() => $resource,
187
                ])
188
            ;
189
        }
190
191
        return $this->viewHandler->handle($configuration, $view);
192
    }
193
194
    /**
195
     * @param Request $request
196
     *
197
     * @return \Symfony\Component\HttpFoundation\Response
198
     */
199
    public function indexAction(Request $request)
200
    {
201
        $configuration = $this->requestConfigurationFactory->create($this->metadata, $request);
202
203
        $this->isGrantedOr403($configuration, ResourceActions::INDEX);
204
        $resources = $this->resourcesCollectionProvider->get($configuration, $this->repository);
205
206
        $view = View::create($resources);
207
208
        if ($configuration->isHtmlRequest()) {
209
            $view
210
                ->setTemplate($configuration->getTemplate(ResourceActions::INDEX . '.html'))
211
                ->setTemplateVar($this->metadata->getPluralName())
212
                ->setData([
213
                    'configuration' => $configuration,
214
                    'metadata' => $this->metadata,
215
                    'resources' => $resources,
216
                    $this->metadata->getPluralName() => $resources,
217
                ])
218
            ;
219
        }
220
221
        return $this->viewHandler->handle($configuration, $view);
222
    }
223
224
    /**
225
     * @param Request $request
226
     *
227
     * @return Response
228
     */
229
    public function createAction(Request $request)
230
    {
231
        $configuration = $this->requestConfigurationFactory->create($this->metadata, $request);
232
233
        $this->isGrantedOr403($configuration, ResourceActions::CREATE);
234
        $newResource = $this->newResourceFactory->create($configuration, $this->factory);
235
236
        $form = $this->resourceFormFactory->create($configuration, $newResource);
237
238
        if ($request->isMethod('POST') && $form->submit($request)->isValid()) {
239
            $newResource = $form->getData();
240
241
            $event = $this->eventDispatcher->dispatchPreEvent(ResourceActions::CREATE, $configuration, $newResource);
242
243
            if ($event->isStopped() && !$configuration->isHtmlRequest()) {
244
                throw new HttpException($event->getErrorCode(), $event->getMessage());
245
            }
246
            if ($event->isStopped()) {
247
                $this->flashHelper->addFlashFromEvent($configuration, $event);
248
249
                return $this->redirectHandler->redirectToIndex($configuration, $newResource);
250
            }
251
252
            $this->repository->add($newResource);
253
            $this->eventDispatcher->dispatchPostEvent(ResourceActions::CREATE, $configuration, $newResource);
254
255
            if (!$configuration->isHtmlRequest()) {
256
                return $this->viewHandler->handle($configuration, View::create($newResource, Response::HTTP_CREATED));
257
            }
258
259
            $this->flashHelper->addSuccessFlash($configuration, ResourceActions::CREATE, $newResource);
260
261
            return $this->redirectHandler->redirectToResource($configuration, $newResource);
262
        }
263
264
        if (!$configuration->isHtmlRequest()) {
265
            return $this->viewHandler->handle($configuration, View::create($form, Response::HTTP_BAD_REQUEST));
266
        }
267
268
        $view = View::create()
269
            ->setData([
270
                'configuration' => $configuration,
271
                'metadata' => $this->metadata,
272
                'resource' => $newResource,
273
                $this->metadata->getName() => $newResource,
274
                'form' => $form->createView(),
275
            ])
276
            ->setTemplate($configuration->getTemplate(ResourceActions::CREATE . '.html'))
277
        ;
278
279
        return $this->viewHandler->handle($configuration, $view);
280
    }
281
282
    /**
283
     * @param Request $request
284
     *
285
     * @return Response
286
     */
287
    public function updateAction(Request $request)
288
    {
289
        $configuration = $this->requestConfigurationFactory->create($this->metadata, $request);
290
291
        $this->isGrantedOr403($configuration, ResourceActions::UPDATE);
292
        $resource = $this->findOr404($configuration);
293
294
        $form = $this->resourceFormFactory->create($configuration, $resource);
295
296
        if (in_array($request->getMethod(), ['POST', 'PUT', 'PATCH']) && $form->submit($request, !$request->isMethod('PATCH'))->isValid()) {
297
            $resource = $form->getData();
298
299
            $event = $this->eventDispatcher->dispatchPreEvent(ResourceActions::UPDATE, $configuration, $resource);
300
301
            if ($event->isStopped() && !$configuration->isHtmlRequest()) {
302
                throw new HttpException($event->getErrorCode(), $event->getMessage());
303
            }
304
            if ($event->isStopped()) {
305
                $this->flashHelper->addFlashFromEvent($configuration, $event);
306
307
                return $this->redirectHandler->redirectToResource($configuration, $resource);
308
            }
309
310
            if ($configuration->hasStateMachine()) {
311
                $this->stateMachine->apply($configuration, $resource);
312
            }
313
314
            $this->manager->flush();
315
            $this->eventDispatcher->dispatchPostEvent(ResourceActions::UPDATE, $configuration, $resource);
316
317
            if (!$configuration->isHtmlRequest()) {
318
                return $this->viewHandler->handle($configuration, View::create(null, Response::HTTP_NO_CONTENT));
319
            }
320
321
            $this->flashHelper->addSuccessFlash($configuration, ResourceActions::UPDATE, $resource);
322
323
            return $this->redirectHandler->redirectToResource($configuration, $resource);
324
        }
325
326
        if (!$configuration->isHtmlRequest()) {
327
            return $this->viewHandler->handle($configuration, View::create($form, Response::HTTP_BAD_REQUEST));
328
        }
329
330
        $view = View::create()
331
            ->setData([
332
                'configuration' => $configuration,
333
                'metadata' => $this->metadata,
334
                'resource' => $resource,
335
                $this->metadata->getName() => $resource,
336
                'form' => $form->createView(),
337
            ])
338
            ->setTemplate($configuration->getTemplate(ResourceActions::UPDATE . '.html'))
339
        ;
340
341
        return $this->viewHandler->handle($configuration, $view);
342
    }
343
344
    /**
345
     * @param Request $request
346
     *
347
     * @return Response
348
     */
349
    public function deleteAction(Request $request)
350
    {
351
        $configuration = $this->requestConfigurationFactory->create($this->metadata, $request);
352
353
        $this->isGrantedOr403($configuration, ResourceActions::DELETE);
354
        $resource = $this->findOr404($configuration);
355
356
        $event = $this->eventDispatcher->dispatchPreEvent(ResourceActions::DELETE, $configuration, $resource);
357
358
        if ($event->isStopped() && !$configuration->isHtmlRequest()) {
359
            throw new HttpException($event->getErrorCode(), $event->getMessage());
360
        }
361
        if ($event->isStopped()) {
362
            $this->flashHelper->addFlashFromEvent($configuration, $event);
363
364
            return $this->redirectHandler->redirectToIndex($configuration, $resource);
365
        }
366
367
        $this->repository->remove($resource);
368
        $this->eventDispatcher->dispatchPostEvent(ResourceActions::DELETE, $configuration, $resource);
369
370
        if (!$configuration->isHtmlRequest()) {
371
            return $this->viewHandler->handle($configuration, View::create(null, Response::HTTP_NO_CONTENT));
372
        }
373
374
        $this->flashHelper->addSuccessFlash($configuration, ResourceActions::DELETE, $resource);
375
376
        return $this->redirectHandler->redirectToIndex($configuration, $resource);
377
    }
378
379
    /**
380
     * @param Request $request
381
     *
382
     * @return RedirectResponse
383
     */
384
    public function applyStateMachineTransitionAction(Request $request)
385
    {
386
        $configuration = $this->requestConfigurationFactory->create($this->metadata, $request);
387
388
        $this->isGrantedOr403($configuration, ResourceActions::UPDATE);
389
        $resource = $this->findOr404($configuration);
390
391
        $event = $this->eventDispatcher->dispatchPreEvent(ResourceActions::UPDATE, $configuration, $resource);
392
393
        if ($event->isStopped() && !$configuration->isHtmlRequest()) {
394
            throw new HttpException($event->getErrorCode(), $event->getMessage());
395
        }
396
        if ($event->isStopped()) {
397
            $this->flashHelper->addFlashFromEvent($configuration, $event);
398
399
            return $this->redirectHandler->redirectToResource($configuration, $resource);
400
        }
401
402
        if (!$this->stateMachine->can($configuration, $resource)) {
403
            throw new BadRequestHttpException();
404
        }
405
406
        $this->stateMachine->apply($configuration, $resource);
407
        $this->manager->flush();
408
409
        $this->eventDispatcher->dispatchPostEvent(ResourceActions::UPDATE, $configuration, $resource);
410
411
        if (!$configuration->isHtmlRequest()) {
412
            return $this->viewHandler->handle($configuration, View::create($resource, Response::HTTP_OK));
413
        }
414
415
        $this->flashHelper->addSuccessFlash($configuration, ResourceActions::UPDATE, $resource);
416
417
        return $this->redirectHandler->redirectToResource($configuration, $resource);
418
    }
419
420
    /**
421
     * @param Request $request
422
     *
423
     * @return RedirectResponse
424
     */
425
    public function enableAction(Request $request)
426
    {
427
        return $this->toggle($request, true);
428
    }
429
    /**
430
     * @param Request $request
431
     *
432
     * @return RedirectResponse
433
     */
434
    public function disableAction(Request $request)
435
    {
436
        return $this->toggle($request, false);
437
    }
438
439
    /**
440
     * @param Request $request
441
     * @param $enabled
442
     *
443
     * @return RedirectResponse
444
     */
445
    protected function toggle(Request $request, $enabled)
446
    {
447
        $configuration = $this->requestConfigurationFactory->create($this->metadata, $request);
448
449
        $this->isGrantedOr403($configuration, ResourceActions::UPDATE);
450
451
        $resource = $this->findOr404($configuration);
452
        $resource->setEnabled($enabled);
453
454
        $this->eventDispatcher->dispatchPreEvent(ResourceActions::UPDATE, $configuration, $resource);
455
        $this->manager->flush();
456
        $this->eventDispatcher->dispatchPostEvent(ResourceActions::UPDATE, $configuration, $resource);
457
458
        if (!$configuration->isHtmlRequest()) {
459
            return $this->viewHandler->handle($configuration, View::create(null, Response::HTTP_NO_CONTENT));
460
        }
461
462
        $this->flashHelper->addSuccessFlash($configuration, $enabled ? 'enable' : 'disable', $resource);
463
464
        return $this->redirectHandler->redirectToIndex($configuration, $resource);
465
    }
466
467
    /**
468
     * @param RequestConfiguration $configuration
469
     * @param string $permission
470
     *
471
     * @throws AccessDeniedException
472
     */
473
    protected function isGrantedOr403(RequestConfiguration $configuration, $permission)
474
    {
475
        if (!$configuration->hasPermission()) {
476
            return;
477
        }
478
479
        $permission = $configuration->getPermission($permission);
480
481
        if (!$this->authorizationChecker->isGranted($configuration, $permission)) {
482
            throw new AccessDeniedException();
483
        }
484
    }
485
486
    /**
487
     * @param RequestConfiguration $configuration
488
     *
489
     * @return \Sylius\Component\Resource\Model\ResourceInterface
490
     *
491
     * @throws NotFoundHttpException
492
     */
493
    protected function findOr404(RequestConfiguration $configuration)
494
    {
495
        if (null === $resource = $this->singleResourceProvider->get($configuration, $this->repository)) {
496
            throw new NotFoundHttpException();
497
        }
498
499
        return $resource;
500
    }
501
}
502