Passed
Pull Request — feature/publishable (#43)
by Vincent
08:57 queued 02:27
created

PublishableEventListener::handlePUTRequest()   B

Complexity

Conditions 8
Paths 14

Size

Total Lines 61
Code Lines 23

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 72

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 23
c 1
b 0
f 0
dl 0
loc 61
ccs 0
cts 24
cp 0
rs 8.4444
cc 8
nc 14
nop 4
crap 72

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\Entity\Utility\PublishableTrait;
20
use Silverback\ApiComponentBundle\Publishable\ClassMetadataTrait;
21
use Silverback\ApiComponentBundle\Publishable\PublishableHelper;
22
use Symfony\Component\HttpFoundation\Request;
23
use Symfony\Component\HttpKernel\Event\RequestEvent;
24
use Symfony\Component\HttpKernel\Event\ResponseEvent;
25
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
26
27
/**
28
 * @author Vincent Chalamon <[email protected]>
29
 */
30
final class PublishableEventListener
31
{
32
    use ClassMetadataTrait;
33
34
    private PublishableHelper $publishableHelper;
35
    private ManagerRegistry $registry;
36
37
    public function __construct(PublishableHelper $publishableHelper, ManagerRegistry $registry)
38
    {
39
        $this->publishableHelper = $publishableHelper;
40
        // not unused, used by the trait
41
        $this->registry = $registry;
42
    }
43
44
    public function onKernelResponse(ResponseEvent $event): void
45
    {
46
        $request = $event->getRequest();
47
        /** @var PublishableTrait $data */
48
        $data = $request->attributes->get('data');
49
        if (!$this->publishableHelper->isPublishable($data)) {
50
            return;
51
        }
52
        $response = $event->getResponse();
53
        $response->setVary('Authorization');
54
55
        $configuration = $this->publishableHelper->getConfiguration($data);
56
        $classMetadata = $this->getClassMetadata($data);
57
58
        $draftResource = $data->getDraftResource() ?? $data;
59
60
        /** @var \DateTime|null $publishedAt */
61
        $publishedAt = $classMetadata->getFieldValue($draftResource, $configuration->fieldName);
62
        if (!$publishedAt || $publishedAt <= new \DateTime()) {
63
            return;
64
        }
65
66
        $response->setExpires($publishedAt);
67
    }
68
69
    public function onKernelRequest(RequestEvent $event): void
70
    {
71
        $request = $event->getRequest();
72
        $data = $request->attributes->get('data');
73
        if (empty($data) || !$this->publishableHelper->isPublishable($data)) {
74
            return;
75
        }
76
77
        $configuration = $this->publishableHelper->getConfiguration($data);
78
        $classMetadata = $this->getClassMetadata($data);
79
80
        switch ($request->getMethod()) {
81
            case Request::METHOD_POST:
82
                $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

82
                $this->handlePOSTRequest($classMetadata, /** @scrutinizer ignore-type */ $configuration, $data);
Loading history...
83
                break;
84
            case Request::METHOD_PATCH:
85
            case Request::METHOD_PUT:
86
                $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

86
                $this->handlePUTRequest($classMetadata, /** @scrutinizer ignore-type */ $configuration, $data, $request);
Loading history...
87
                break;
88
        }
89
    }
90
91
    private function handlePOSTRequest(ClassMetadataInfo $classMetadata, Publishable $configuration, object $data): void
92
    {
93
        // It's not possible for a user to define a resource as draft from another
94
        $classMetadata->setFieldValue($data, $configuration->associationName, null);
95
96
        // User doesn't have draft access: force publication date
97
        if (!$this->publishableHelper->isGranted()) {
98
            $classMetadata->setFieldValue($data, $configuration->fieldName, new \DateTimeImmutable());
99
        }
100
    }
101
102
    private function handlePUTRequest(ClassMetadataInfo $classMetadata, Publishable $configuration, object $data, Request $request): void
103
    {
104
        $changeSet = $this->getEntityManager($data)->getUnitOfWork()->getEntityChangeSet($data);
105
106
        // It's not possible to change the publishedResource property
107
        if (isset($changeSet[$configuration->associationName])) {
108
            $classMetadata->setFieldValue($data, $configuration->associationName, $changeSet[$configuration->associationName][0]);
109
        }
110
111
        // User doesn't have draft access: cannot change the publication date
112
        if (!$this->publishableHelper->isGranted()) {
113
            if (isset($changeSet[$configuration->fieldName])) {
114
                $classMetadata->setFieldValue($data, $configuration->fieldName, $changeSet[$configuration->fieldName][0]);
115
            }
116
117
            // Nothing to do here anymore for user without draft access
118
            return;
119
        }
120
121
        // User requested for original object
122
        if (true === $request->query->getBoolean('published', false)) {
123
            // User cannot change the publication date of the original resource
124
            if ($changeSet[$configuration->fieldName]) {
125
                throw new BadRequestHttpException('You cannot change the publication date of a published resource.');
126
            }
127
128
            // User wants to update the original object: nothing to do here anymore
129
            return;
130
        }
131
132
        // Resource is a draft of another resource: nothing to do here anymore
133
        if (null !== $classMetadata->getFieldValue($data, $configuration->associationName)) {
134
            return;
135
        }
136
137
        // Any field has been modified: create or update draft
138
        $draft = $this->getEntityManager($data)->getRepository($this->getObjectClass($data))->findOneBy([
139
            $configuration->associationName => $data,
140
        ]);
141
        if (!$draft) {
142
            // Identifier(s) should be reset from AbstractComponent::__clone method
143
            $draft = clone $data;
144
145
            // Add draft object to UnitOfWork
146
            $this->getEntityManager($draft)->persist($draft);
147
148
            // Empty publishedDate on draft
149
            $classMetadata->setFieldValue($draft, $configuration->fieldName, null);
150
151
            // Set publishedResource on draft
152
            $classMetadata->setFieldValue($draft, $configuration->associationName, $data);
153
154
            // Set draftResource on data
155
            $classMetadata->setFieldValue($data, $configuration->reverseAssociationName, $draft);
156
        }
157
158
        // Replace data by its draft
159
        $request->attributes->set('data', $draft);
160
161
        // Rollback modifications on original resource
162
        $this->getEntityManager($data)->refresh($data);
163
    }
164
}
165