Test Setup Failed
Pull Request — feature/publishable (#31)
by Vincent
25:43 queued 05:53
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;
34
35
    public function __construct(PublishableHelper $publishableHelper, ManagerRegistry $registry)
36
    {
37
        $this->publishableHelper = $publishableHelper;
38
        $this->registry = $registry;
39
    }
40
41
    public function __invoke(ViewEvent $event): void
42
    {
43
        $request = $event->getRequest();
44
        $data = $request->attributes->get('data');
45
        if (!$this->publishableHelper->isPublishable($data)) {
46
            return;
47
        }
48
49
        $configuration = $this->publishableHelper->getConfiguration($data);
50
        $classMetadata = $this->getClassMetadata($data);
51
52
        if ($request->isMethod(Request::METHOD_POST)) {
53
            $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

53
            $this->handlePOSTRequest($classMetadata, /** @scrutinizer ignore-type */ $configuration, $data);
Loading history...
54
        }
55
56
        if ($request->isMethod(Request::METHOD_PUT) || $request->isMethod(Request::METHOD_PATCH)) {
57
            $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

57
            $this->handlePUTRequest($classMetadata, /** @scrutinizer ignore-type */ $configuration, $data, $request);
Loading history...
58
        }
59
    }
60
61
    private function handlePOSTRequest(ClassMetadataInfo $classMetadata, Publishable $configuration, object $data): void
62
    {
63
        // It's not possible for a user to define a resource as draft from another
64
        $classMetadata->setFieldValue($data, $configuration->associationName, null);
65
66
        // User doesn't have draft access: force publication date
67
        if (!$this->publishableHelper->isGranted()) {
68
            $classMetadata->setFieldValue($data, $configuration->fieldName, new \DateTimeImmutable());
69
        }
70
    }
71
72
    private function handlePUTRequest(ClassMetadataInfo $classMetadata, Publishable $configuration, object $data, Request $request): void
73
    {
74
        $changeSet = $this->getEntityManager($data)->getUnitOfWork()->getEntityChangeSet($data);
75
76
        // It's not possible to change the publishedResource property
77
        if (isset($changeSet[$configuration->associationName])) {
78
            $classMetadata->setFieldValue($data, $configuration->associationName, $changeSet[$configuration->associationName][0]);
79
        }
80
81
        // User doesn't have draft access: cannot change the publication date
82
        if (!$this->publishableHelper->isGranted()) {
83
            if (isset($changeSet[$configuration->fieldName])) {
84
                $classMetadata->setFieldValue($data, $configuration->fieldName, $changeSet[$configuration->fieldName][0]);
85
            }
86
87
            // Nothing to do here anymore for user without draft access
88
            return;
89
        }
90
91
        // User requested for original object
92
        if (true === $request->query->getBoolean('published', false)) {
93
            // User cannot change the publication date of the original resource
94
            if ($changeSet[$configuration->fieldName]) {
95
                throw new BadRequestHttpException('You cannot change the publication date of a published resource.');
96
            }
97
98
            // User wants to update the original object: nothing to do here anymore
99
            return;
100
        }
101
102
        // Resource is a draft of another resource: nothing to do here anymore
103
        if (null !== $classMetadata->getFieldValue($data, $configuration->associationName)) {
104
            return;
105
        }
106
107
        // Any field has been modified: create or update draft
108
        $draft = $this->getEntityManager($data)->getRepository($this->getObjectClass($data))->findOneBy([
109
            $configuration->associationName => $data,
110
        ]);
111
        if (!$draft) {
112
            $draft = clone $data;
113
            // Reset draft identifier(s)
114
            $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

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