Test Failed
Pull Request — main (#152)
by Daniel
06:32 queued 02:15
created

DoctrineResourceFlushTrait   A

Complexity

Total Complexity 30

Size/Duplication

Total Lines 144
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 66
c 1
b 0
f 0
dl 0
loc 144
rs 10
wmc 30

11 Methods

Rating   Name   Duplication   Size   Complexity  
A postFlush() 0 5 1
A __construct() 0 8 1
A addResourcesToPurge() 0 3 1
A getAssociationMappings() 0 3 1
A collectUpdatedResource() 0 8 4
A purgeResources() 0 3 1
A gatherRelationResourceClasses() 0 12 5
A gatherIrisForCollectionResources() 0 22 5
A preUpdate() 0 19 4
A onFlush() 0 15 4
A gatherResourcesForPositionsWithPageDataProperties() 0 13 3
1
<?php
2
3
/*
4
 * This file is part of the Silverback API Components 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\ApiComponentsBundle\EventListener\Doctrine;
15
16
use ApiPlatform\Api\IriConverterInterface;
17
use Doctrine\Common\Util\ClassUtils;
18
use Doctrine\ORM\EntityManagerInterface;
19
use Doctrine\ORM\EntityRepository;
20
use Doctrine\ORM\Event\OnFlushEventArgs;
21
use Doctrine\ORM\Event\PreUpdateEventArgs;
22
use Doctrine\ORM\PersistentCollection;
23
use Doctrine\Persistence\ManagerRegistry;
24
use Doctrine\Persistence\ObjectRepository;
25
use Silverback\ApiComponentsBundle\Entity\Component\Collection;
26
use Silverback\ApiComponentsBundle\Entity\Core\ComponentPosition;
27
use Silverback\ApiComponentsBundle\Entity\Core\PageDataInterface;
28
use Silverback\ApiComponentsBundle\HttpCache\ResourceChangedPropagatorInterface;
29
use Symfony\Component\PropertyAccess\PropertyAccess;
30
use Symfony\Component\PropertyAccess\PropertyAccessor;
31
32
trait DoctrineResourceFlushTrait
33
{
34
    private array $pageDataPropertiesChanged = [];
35
    private PropertyAccessor $propertyAccessor;
36
    private ObjectRepository|EntityRepository $collectionRepository;
37
    private ObjectRepository|EntityRepository $positionRepository;
38
39
    public function __construct(
40
        private readonly IriConverterInterface $iriConverter,
41
        ManagerRegistry $entityManager,
42
        private readonly ResourceChangedPropagatorInterface $resourceChangedPropagator,
43
    ) {
44
        $this->propertyAccessor = PropertyAccess::createPropertyAccessor();
45
        $this->collectionRepository = $entityManager->getRepository(Collection::class);
46
        $this->positionRepository = $entityManager->getRepository(ComponentPosition::class);
47
    }
48
49
    public function preUpdate(PreUpdateEventArgs $eventArgs): void
50
    {
51
        $object = $eventArgs->getObject();
52
        $this->collectUpdatedResource($object);
53
54
        $changeSet = $eventArgs->getEntityChangeSet();
55
        $associationMappings = $this->getAssociationMappings($eventArgs->getEntityManager(), $eventArgs->getObject());
0 ignored issues
show
Deprecated Code introduced by
The function Doctrine\ORM\Event\Lifec...rgs::getEntityManager() has been deprecated: 2.13. Use {@see getObjectManager} instead. ( Ignorable by Annotation )

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

55
        $associationMappings = $this->getAssociationMappings(/** @scrutinizer ignore-deprecated */ $eventArgs->getEntityManager(), $eventArgs->getObject());

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
56
57
        if ($object instanceof PageDataInterface) {
58
            $this->pageDataPropertiesChanged = array_keys($changeSet);
59
        }
60
61
        foreach ($changeSet as $field => $value) {
62
            if (!isset($associationMappings[$field])) {
63
                continue;
64
            }
65
66
            $this->collectUpdatedResource($value[0]);
67
            $this->collectUpdatedResource($value[1]);
68
        }
69
    }
70
71
    public function onFlush(OnFlushEventArgs $eventArgs): void
72
    {
73
        $em = $eventArgs->getObjectManager();
74
        $uow = $em->getUnitOfWork();
0 ignored issues
show
Bug introduced by
The method getUnitOfWork() does not exist on Doctrine\Persistence\ObjectManager. It seems like you code against a sub-type of said class. However, the method does not exist in Doctrine\Persistence\ObjectManagerDecorator. Are you sure you never get one of those? ( Ignorable by Annotation )

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

74
        /** @scrutinizer ignore-call */ 
75
        $uow = $em->getUnitOfWork();
Loading history...
75
76
        foreach ($uow->getScheduledEntityInsertions() as $entity) {
77
            $this->collectUpdatedResource($entity, $em, true);
78
        }
79
80
        foreach ($uow->getScheduledEntityUpdates() as $entity) {
81
            $this->collectUpdatedResource($entity, $em, true);
82
        }
83
84
        foreach ($uow->getScheduledEntityDeletions() as $entity) {
85
            $this->collectUpdatedResource($entity, $em, true);
86
        }
87
    }
88
89
    public function postFlush(): void
90
    {
91
        $this->addResourcesToPurge($this->gatherResourcesForPositionsWithPageDataProperties());
92
        $this->addResourcesToPurge($this->gatherIrisForCollectionResources());
93
        $this->purgeResources();
94
    }
95
96
    private function gatherRelationResourceClasses(EntityManagerInterface $em, $entity): void
97
    {
98
        $associationMappings = $this->getAssociationMappings($em, $entity);
99
        foreach (array_keys($associationMappings) as $property) {
100
            if ($this->propertyAccessor->isReadable($entity, $property)) {
101
                $value = $this->propertyAccessor->getValue($entity, $property);
102
                if ($value instanceof PersistentCollection) {
103
                    foreach ($value as $item) {
104
                        $this->collectUpdatedResource($item);
105
                    }
106
                } else {
107
                    $this->collectUpdatedResource($value);
108
                }
109
            }
110
        }
111
    }
112
113
    private function gatherResourcesForPositionsWithPageDataProperties(): array
114
    {
115
        $positionResources = [];
116
        foreach ($this->pageDataPropertiesChanged as $pageDataProperty) {
117
            $positions = $this->positionRepository->findBy([
118
                'pageDataProperty' => $pageDataProperty,
119
            ]);
120
            foreach ($positions as $position) {
121
                $positionResources[] = $position;
122
            }
123
        }
124
125
        return $positionResources;
126
    }
127
128
    private function gatherIrisForCollectionResources(): array
129
    {
130
        if (empty($this->resourceIris)) {
131
            return [];
132
        }
133
134
        $collectionResources = [];
135
        foreach ($this->resourceIris as $resourceIri) {
136
            $collections = $this->collectionRepository->findBy([
137
                'resourceIri' => $resourceIri,
138
            ]);
139
            foreach ($collections as $collection) {
140
                $collectionResources[] = $collection;
141
            }
142
        }
143
144
        $this->resourceIris = [];
0 ignored issues
show
Bug Best Practice introduced by
The property resourceIris does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
145
        if (empty($collectionResources)) {
146
            return [];
147
        }
148
149
        return $collectionResources;
150
    }
151
152
    private function getAssociationMappings(EntityManagerInterface $em, $entity): array
153
    {
154
        return $em->getClassMetadata(ClassUtils::getClass($entity))->getAssociationMappings();
155
    }
156
157
    private function collectUpdatedResource($resource, ?EntityManagerInterface $em = null, bool $gatherRelated = false): void
158
    {
159
        if (!$resource) {
160
            return;
161
        }
162
        $this->resourceChangedPropagator?->collectItem($resource);
163
        if ($gatherRelated && $em) {
164
            $this->gatherRelationResourceClasses($em, $resource);
165
        }
166
    }
167
168
    private function addResourcesToPurge(array $resources): void
169
    {
170
        $this->resourceChangedPropagator->collectItems($resources);
171
    }
172
173
    private function purgeResources(): void
174
    {
175
        $this->resourceChangedPropagator->propagate();
176
    }
177
}
178