Completed
Push — master ( a0071b...e33605 )
by Michael
12s
created

Collection/AbstractCollectionPersister.php (2 issues)

1
<?php
2
3
declare(strict_types=1);
4
5
namespace Doctrine\ORM\Cache\Persister\Collection;
6
7
use Doctrine\Common\Collections\Collection;
8
use Doctrine\Common\Collections\Criteria;
9
use Doctrine\ORM\Cache\CollectionCacheKey;
10
use Doctrine\ORM\Cache\EntityCacheKey;
11
use Doctrine\ORM\Cache\Region;
12
use Doctrine\ORM\EntityManagerInterface;
13
use Doctrine\ORM\Mapping\AssociationMetadata;
14
use Doctrine\ORM\Mapping\ToManyAssociationMetadata;
15
use Doctrine\ORM\PersistentCollection;
16
use Doctrine\ORM\Persisters\Collection\CollectionPersister;
17
use Doctrine\ORM\Utility\StaticClassNameConverter;
18
19
abstract class AbstractCollectionPersister implements CachedCollectionPersister
20
{
21
    /**
22
     * @var \Doctrine\ORM\UnitOfWork
23
     */
24
    protected $uow;
25
26
    /**
27
     * @var \Doctrine\ORM\Mapping\ClassMetadataFactory
28
     */
29
    protected $metadataFactory;
30
31
    /**
32
     * @var \Doctrine\ORM\Persisters\Collection\CollectionPersister
33
     */
34
    protected $persister;
35
36
    /**
37
     * @var \Doctrine\ORM\Mapping\ClassMetadata
38
     */
39
    protected $sourceEntity;
40
41
    /**
42
     * @var \Doctrine\ORM\Mapping\ClassMetadata
43
     */
44
    protected $targetEntity;
45
46
    /**
47
     * @var \Doctrine\ORM\Mapping\AssociationMetadata
48
     */
49
    protected $association;
50
51
    /**
52
     * @var mixed[][][]
53
     */
54
    protected $queuedCache = [];
55
56
    /**
57
     * @var \Doctrine\ORM\Cache\Region
58
     */
59
    protected $region;
60
61
    /**
62
     * @var string
63
     */
64
    protected $regionName;
65
66
    /**
67
     * @var \Doctrine\ORM\Cache\CollectionHydrator
68
     */
69
    protected $hydrator;
70
71
    /**
72
     * @var \Doctrine\ORM\Cache\Logging\CacheLogger
73
     */
74
    protected $cacheLogger;
75
76
    /**
77
     * @param CollectionPersister    $persister   The collection persister that will be cached.
78
     * @param Region                 $region      The collection region.
79
     * @param EntityManagerInterface $em          The entity manager.
80
     * @param AssociationMetadata    $association The association mapping.
81
     */
82 117
    public function __construct(
83
        CollectionPersister $persister,
84
        Region $region,
85
        EntityManagerInterface $em,
86
        AssociationMetadata $association
87
    ) {
88 117
        $configuration = $em->getConfiguration();
89 117
        $cacheConfig   = $configuration->getSecondLevelCacheConfiguration();
90 117
        $cacheFactory  = $cacheConfig->getCacheFactory();
91
92 117
        $this->region          = $region;
93 117
        $this->persister       = $persister;
94 117
        $this->association     = $association;
95 117
        $this->regionName      = $region->getName();
96 117
        $this->uow             = $em->getUnitOfWork();
97 117
        $this->metadataFactory = $em->getMetadataFactory();
98 117
        $this->cacheLogger     = $cacheConfig->getCacheLogger();
99 117
        $this->hydrator        = $cacheFactory->buildCollectionHydrator($em, $association);
100 117
        $this->sourceEntity    = $em->getClassMetadata($association->getSourceEntity());
0 ignored issues
show
Documentation Bug introduced by
It seems like $em->getClassMetadata($a...ion->getSourceEntity()) of type Doctrine\Common\Persistence\Mapping\ClassMetadata is incompatible with the declared type Doctrine\ORM\Mapping\ClassMetadata of property $sourceEntity.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
101 117
        $this->targetEntity    = $em->getClassMetadata($association->getTargetEntity());
0 ignored issues
show
Documentation Bug introduced by
It seems like $em->getClassMetadata($a...ion->getTargetEntity()) of type Doctrine\Common\Persistence\Mapping\ClassMetadata is incompatible with the declared type Doctrine\ORM\Mapping\ClassMetadata of property $targetEntity.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
102 117
    }
103
104
    /**
105
     * {@inheritdoc}
106
     */
107 63
    public function getCacheRegion()
108
    {
109 63
        return $this->region;
110
    }
111
112
    /**
113
     * {@inheritdoc}
114
     */
115
    public function getSourceEntityMetadata()
116
    {
117
        return $this->sourceEntity;
118
    }
119
120
    /**
121
     * {@inheritdoc}
122
     */
123
    public function getTargetEntityMetadata()
124
    {
125
        return $this->targetEntity;
126
    }
127
128
    /**
129
     *
130
     * @return \Doctrine\ORM\PersistentCollection|null
131
     */
132 18
    public function loadCollectionCache(PersistentCollection $collection, CollectionCacheKey $key)
133
    {
134 18
        $cache = $this->region->get($key);
135
136 18
        if ($cache === null) {
137 14
            return null;
138
        }
139
140 15
        $cache = $this->hydrator->loadCacheEntry($this->sourceEntity, $key, $cache, $collection);
141
142 15
        if ($cache === null) {
143 1
            return null;
144
        }
145
146 15
        return $cache;
147
    }
148
149
    /**
150
     * {@inheritdoc}
151
     */
152 45
    public function storeCollectionCache(CollectionCacheKey $key, $elements)
153
    {
154
        /* @var $targetPersister CachedEntityPersister */
155 45
        $association     = $this->sourceEntity->getProperty($key->association);
156 45
        $targetPersister = $this->uow->getEntityPersister($this->targetEntity->getRootClassName());
157 45
        $targetRegion    = $targetPersister->getCacheRegion();
158 45
        $targetHydrator  = $targetPersister->getEntityHydrator();
159
160
        // Only preserve ordering if association configured it
161 45
        if (! ($association instanceof ToManyAssociationMetadata && $association->getIndexedBy())) {
162
            // Elements may be an array or a Collection
163 45
            $elements = \array_values($elements instanceof Collection ? $elements->getValues() : $elements);
164
        }
165
166 45
        $entry = $this->hydrator->buildCacheEntry($this->targetEntity, $key, $elements);
167
168 45
        foreach ($entry->identifiers as $index => $entityKey) {
169 45
            if ($targetRegion->contains($entityKey)) {
170 45
                continue;
171
            }
172
173 11
            $class     = $this->targetEntity;
174 11
            $className = StaticClassNameConverter::getClass($elements[$index]);
175
176 11
            if ($className !== $this->targetEntity->getClassName()) {
177 2
                $class = $this->metadataFactory->getMetadataFor($className);
178
            }
179
180 11
            $entity      = $elements[$index];
181 11
            $entityEntry = $targetHydrator->buildCacheEntry($class, $entityKey, $entity);
182
183 11
            $targetRegion->put($entityKey, $entityEntry);
184
        }
185
186 45
        $cached = $this->region->put($key, $entry);
187
188 45
        if ($this->cacheLogger && $cached) {
189 45
            $this->cacheLogger->collectionCachePut($this->regionName, $key);
190
        }
191 45
    }
192
193
    /**
194
     * {@inheritdoc}
195
     */
196 3
    public function contains(PersistentCollection $collection, $element)
197
    {
198 3
        return $this->persister->contains($collection, $element);
199
    }
200
201
    /**
202
     * {@inheritdoc}
203
     */
204 3
    public function containsKey(PersistentCollection $collection, $key)
205
    {
206 3
        return $this->persister->containsKey($collection, $key);
207
    }
208
209
    /**
210
     * {@inheritdoc}
211
     */
212 4
    public function count(PersistentCollection $collection)
213
    {
214 4
        $fieldName = $this->association->getName();
215 4
        $ownerId   = $this->uow->getEntityIdentifier($collection->getOwner());
216 4
        $key       = new CollectionCacheKey($this->sourceEntity->getRootClassName(), $fieldName, $ownerId);
217 4
        $entry     = $this->region->get($key);
218
219 4
        if ($entry !== null) {
220 1
            return count($entry->identifiers);
221
        }
222
223 4
        return $this->persister->count($collection);
224
    }
225
226
    /**
227
     * {@inheritdoc}
228
     */
229 3
    public function get(PersistentCollection $collection, $index)
230
    {
231 3
        return $this->persister->get($collection, $index);
232
    }
233
234
    /**
235
     * {@inheritdoc}
236
     */
237 3
    public function removeElement(PersistentCollection $collection, $element)
238
    {
239 3
        $persisterResult = $this->persister->removeElement($collection, $element);
240
241 3
        if ($persisterResult) {
242
            $this->evictCollectionCache($collection);
243
            $this->evictElementCache($this->sourceEntity->getRootClassName(), $collection->getOwner());
244
            $this->evictElementCache($this->targetEntity->getRootClassName(), $element);
245
        }
246
247 3
        return $persisterResult;
248
    }
249
250
    /**
251
     * {@inheritdoc}
252
     */
253 3
    public function slice(PersistentCollection $collection, $offset, $length = null)
254
    {
255 3
        return $this->persister->slice($collection, $offset, $length);
256
    }
257
258
    /**
259
     * {@inheritDoc}
260
     */
261
    public function loadCriteria(PersistentCollection $collection, Criteria $criteria)
262
    {
263
        return $this->persister->loadCriteria($collection, $criteria);
264
    }
265
266
    /**
267
     * Clears cache entries related to the current collection
268
     */
269
    protected function evictCollectionCache(PersistentCollection $collection)
270
    {
271
        $key = new CollectionCacheKey(
272
            $this->sourceEntity->getRootClassName(),
273
            $this->association->getName(),
274
            $this->uow->getEntityIdentifier($collection->getOwner())
275
        );
276
277
        $this->region->evict($key);
278
279
        if ($this->cacheLogger) {
280
            $this->cacheLogger->collectionCachePut($this->regionName, $key);
281
        }
282
    }
283
284
    /**
285
     * @param string $targetEntity
286
     * @param object $element
287
     */
288
    protected function evictElementCache($targetEntity, $element)
289
    {
290
        /* @var $targetPersister CachedEntityPersister */
291
        $targetPersister = $this->uow->getEntityPersister($targetEntity);
292
        $targetRegion    = $targetPersister->getCacheRegion();
293
        $key             = new EntityCacheKey($targetEntity, $this->uow->getEntityIdentifier($element));
294
295
        $targetRegion->evict($key);
296
297
        if ($this->cacheLogger) {
298
            $this->cacheLogger->entityCachePut($targetRegion->getName(), $key);
299
        }
300
    }
301
}
302