Test Failed
Pull Request — feature/publishable (#31)
by Vincent
06:22
created

PublishableEventListener::handlePUTRequest()   B

Complexity

Conditions 8
Paths 14

Size

Total Lines 52
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 21
c 1
b 0
f 0
dl 0
loc 52
rs 8.4444
cc 8
nc 14
nop 4

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/*
4
 * This file is part of the Silverback API Component Bundle Project
5
 *
6
 * (c) Daniel West <[email protected]>
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 Silverback\ApiComponentBundle\EventListener\Api;
15
16
use Doctrine\ORM\Mapping\ClassMetadataInfo;
17
use Doctrine\Persistence\ManagerRegistry;
18
use Silverback\ApiComponentBundle\Annotation\Publishable;
19
use Silverback\ApiComponentBundle\Publishable\ClassMetadataTrait;
20
use Silverback\ApiComponentBundle\Publishable\PublishableHelper;
21
use Symfony\Component\HttpFoundation\Request;
22
use Symfony\Component\HttpKernel\Event\ViewEvent;
23
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
24
25
/**
26
 * @author Vincent Chalamon <[email protected]>
27
 */
28
final class PublishableEventListener
29
{
30
    use ClassMetadataTrait;
31
32
    private PublishableHelper $publishableHelper;
33
    private ManagerRegistry $registry;
0 ignored issues
show
introduced by
The private property $registry is not used, and could be removed.
Loading history...
34
35
    public function __invoke(ViewEvent $event): void
36
    {
37
        $request = $event->getRequest();
38
        $data = $request->attributes->get('data');
39
        if (!$this->publishableHelper->isPublishable($data)) {
40
            return;
41
        }
42
43
        $configuration = $this->publishableHelper->getConfiguration($data);
44
        $classMetadata = $this->getClassMetadata($data);
45
46
        if ($request->isMethod(Request::METHOD_POST)) {
47
            $this->handlePOSTRequest($classMetadata, $configuration, $data);
0 ignored issues
show
Bug introduced by
It seems like $configuration can also be of type null; however, parameter $configuration of Silverback\ApiComponentB...er::handlePOSTRequest() does only seem to accept Silverback\ApiComponentB...\Annotation\Publishable, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

47
            $this->handlePOSTRequest($classMetadata, /** @scrutinizer ignore-type */ $configuration, $data);
Loading history...
48
        }
49
50
        if ($request->isMethod(Request::METHOD_PUT) || $request->isMethod(Request::METHOD_PATCH)) {
51
            $this->handlePUTRequest($classMetadata, $configuration, $data, $request);
0 ignored issues
show
Bug introduced by
It seems like $configuration can also be of type null; however, parameter $configuration of Silverback\ApiComponentB...ner::handlePUTRequest() does only seem to accept Silverback\ApiComponentB...\Annotation\Publishable, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

51
            $this->handlePUTRequest($classMetadata, /** @scrutinizer ignore-type */ $configuration, $data, $request);
Loading history...
52
        }
53
    }
54
55
    private function handlePOSTRequest(ClassMetadataInfo $classMetadata, Publishable $configuration, object $data): void
56
    {
57
        // It's not possible for a user to define a resource as draft from another
58
        $classMetadata->setFieldValue($data, $configuration->associationName, null);
59
60
        // User doesn't have draft access: force publication date
61
        if (!$this->publishableHelper->isGranted()) {
62
            $classMetadata->setFieldValue($data, $configuration->fieldName, new \DateTimeImmutable());
63
        }
64
    }
65
66
    private function handlePUTRequest(ClassMetadataInfo $classMetadata, Publishable $configuration, object $data, Request $request): void
67
    {
68
        $changeSet = $this->getEntityManager($data)->getUnitOfWork()->getEntityChangeSet($data);
69
70
        // It's not possible to change the publishedResource property
71
        if (isset($changeSet[$configuration->associationName])) {
72
            $classMetadata->setFieldValue($data, $configuration->associationName, $changeSet[$configuration->associationName][0]);
73
        }
74
75
        // User doesn't have draft access: cannot change the publication date
76
        if (!$this->publishableHelper->isGranted()) {
77
            if (isset($changeSet[$configuration->fieldName])) {
78
                $classMetadata->setFieldValue($data, $configuration->fieldName, $changeSet[$configuration->fieldName][0]);
79
            }
80
81
            // Nothing to do here anymore for user without draft access
82
            return;
83
        }
84
85
        // User requested for original object
86
        if (true === $request->query->getBoolean('published', false)) {
87
            // User cannot change the publication date of the original resource
88
            if ($changeSet[$configuration->fieldName]) {
89
                throw new BadRequestHttpException('You cannot change the publication date of a published resource.');
90
            }
91
92
            // User wants to update the original object: nothing to do here anymore
93
            return;
94
        }
95
96
        // Resource is a draft of another resource: nothing to do here anymore
97
        if (null !== $classMetadata->getFieldValue($data, $configuration->associationName)) {
98
            return;
99
        }
100
101
        // Any field has been modified: create or update draft
102
        $draft = $this->getEntityManager($data)->getRepository($this->getObjectClass($data))->findOneBy([
103
            $configuration->associationName => $data,
104
        ]);
105
        if (!$draft) {
106
            $draft = clone $data;
107
            // Reset draft identifier(s)
108
            $classMetadata->setIdentifierValues($draft, array_combine($classMetadata->getIdentifierFieldNames(), array_fill(0, \count($classMetadata->getIdentifierFieldNames()), null)));
0 ignored issues
show
Bug introduced by
It seems like array_combine($classMeta...erFieldNames()), null)) can also be of type false; however, parameter $id of Doctrine\ORM\Mapping\Cla...::setIdentifierValues() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

108
            $classMetadata->setIdentifierValues($draft, /** @scrutinizer ignore-type */ array_combine($classMetadata->getIdentifierFieldNames(), array_fill(0, \count($classMetadata->getIdentifierFieldNames()), null)));
Loading history...
109
110
            $this->getEntityManager($draft)->persist($draft);
111
        }
112
113
        // Replace data by its draft
114
        $request->attributes->set('data', $draft);
115
116
        // Rollback modifications on original resource
117
        $this->getEntityManager($data)->refresh($data);
118
    }
119
}
120