Passed
Pull Request — feature/publishable (#43)
by Daniel
06:23
created

PublishableEventListener::onPostRespond()   A

Complexity

Conditions 5
Paths 3

Size

Total Lines 26
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 30

Importance

Changes 0
Metric Value
eloc 15
c 0
b 0
f 0
dl 0
loc 26
ccs 0
cts 15
cp 0
rs 9.4555
cc 5
nc 3
nop 1
crap 30
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\Persistence\ManagerRegistry;
17
use Silverback\ApiComponentBundle\Entity\Utility\PublishableTrait;
18
use Silverback\ApiComponentBundle\Publishable\ClassMetadataTrait;
19
use Silverback\ApiComponentBundle\Publishable\PublishableHelper;
20
use Symfony\Component\HttpFoundation\Request;
21
use Symfony\Component\HttpKernel\Event\RequestEvent;
22
use Symfony\Component\HttpKernel\Event\ResponseEvent;
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;
34
35
    public function __construct(PublishableHelper $publishableHelper, ManagerRegistry $registry)
36
    {
37
        $this->publishableHelper = $publishableHelper;
38
        // not unused, used by the trait
39
        $this->registry = $registry;
40
    }
41
42
    public function onPreWrite(RequestEvent $event): void
43
    {
44
        $request = $event->getRequest();
45
        $data = $request->attributes->get('data');
46
        if (
47
            empty($data) ||
48
            !$this->publishableHelper->isPublishable($data) ||
49
            !($request->isMethod(Request::METHOD_PUT) || $request->isMethod(Request::METHOD_PATCH))
50
        ) {
51
            return;
52
        }
53
54
        $configuration = $this->publishableHelper->getConfiguration($data);
55
        $classMetadata = $this->getClassMetadata($data);
56
57
        $publishedResource = $classMetadata->getFieldValue($data, $configuration->associationName);
58
        if ($publishedResource && $this->publishableHelper->isPublished($data)) {
59
            $entityManager = $this->getEntityManager($data);
60
            $entityManager->remove($publishedResource);
61
            $entityManager->flush();
62
63
            $meta = $entityManager->getClassMetadata(\get_class($data));
64
            $identifier = $meta->getSingleIdentifierFieldName();
0 ignored issues
show
Bug introduced by
The method getSingleIdentifierFieldName() does not exist on Doctrine\Persistence\Mapping\ClassMetadata. It seems like you code against a sub-type of Doctrine\Persistence\Mapping\ClassMetadata such as Doctrine\ORM\Mapping\ClassMetadataInfo. ( Ignorable by Annotation )

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

64
            /** @scrutinizer ignore-call */ 
65
            $identifier = $meta->getSingleIdentifierFieldName();
Loading history...
65
            $publishedIdentifier = $classMetadata->getFieldValue($publishedResource, $identifier);
66
            $classMetadata->setFieldValue($data, $identifier, $publishedIdentifier);
67
            $classMetadata->setFieldValue($data, $configuration->associationName, null);
68
        }
69
    }
70
71
    public function onPostDeserialize(RequestEvent $event): void
72
    {
73
        $request = $event->getRequest();
74
        $data = $request->attributes->get('data');
75
        if (
76
            empty($data) ||
77
            !$this->publishableHelper->isPublishable($data) ||
78
            !($request->isMethod(Request::METHOD_PUT) || $request->isMethod(Request::METHOD_PATCH))
79
        ) {
80
            return;
81
        }
82
83
        $configuration = $this->publishableHelper->getConfiguration($data);
84
85
        // User cannot change the publication date of the original resource
86
        if (
87
            true === $request->query->getBoolean('published', false) &&
88
            $this->getValue($request->attributes->get('previous_data'), $configuration->fieldName) !== $this->getValue($data, $configuration->fieldName)
89
        ) {
90
            throw new BadRequestHttpException('You cannot change the publication date of a published resource.');
91
        }
92
    }
93
94
    public function onPostRespond(ResponseEvent $event): void
95
    {
96
        $request = $event->getRequest();
97
        /** @var PublishableTrait $data */
98
        $data = $request->attributes->get('data');
99
        if (
100
            empty($data) ||
101
            !$this->publishableHelper->isPublishable($data)
102
        ) {
103
            return;
104
        }
105
        $response = $event->getResponse();
106
        $response->setVary('Authorization');
107
108
        $configuration = $this->publishableHelper->getConfiguration($data);
109
        $classMetadata = $this->getClassMetadata($data);
110
111
        $draftResource = $classMetadata->getFieldValue($data, $configuration->reverseAssociationName) ?? $data;
112
113
        /** @var \DateTime|null $publishedAt */
114
        $publishedAt = $classMetadata->getFieldValue($draftResource, $configuration->fieldName);
115
        if (!$publishedAt || $publishedAt <= new \DateTime()) {
116
            return;
117
        }
118
119
        $response->setExpires($publishedAt);
120
    }
121
122
    private function getValue(object $object, string $property)
123
    {
124
        return $this->getClassMetadata($object)->getFieldValue($object, $property);
125
    }
126
}
127