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\CollectionHydrator; |
||||||
11 | use Doctrine\ORM\Cache\EntityCacheKey; |
||||||
12 | use Doctrine\ORM\Cache\Logging\CacheLogger; |
||||||
13 | use Doctrine\ORM\Cache\Persister\Entity\CachedEntityPersister; |
||||||
14 | use Doctrine\ORM\Cache\Region; |
||||||
15 | use Doctrine\ORM\EntityManagerInterface; |
||||||
16 | use Doctrine\ORM\Mapping\AssociationMetadata; |
||||||
17 | use Doctrine\ORM\Mapping\ClassMetadata; |
||||||
18 | use Doctrine\ORM\Mapping\ClassMetadataFactory; |
||||||
19 | use Doctrine\ORM\Mapping\ToManyAssociationMetadata; |
||||||
20 | use Doctrine\ORM\PersistentCollection; |
||||||
21 | use Doctrine\ORM\Persisters\Collection\CollectionPersister; |
||||||
22 | use Doctrine\ORM\UnitOfWork; |
||||||
23 | use Doctrine\ORM\Utility\StaticClassNameConverter; |
||||||
24 | use function array_values; |
||||||
25 | use function count; |
||||||
26 | |||||||
27 | abstract class AbstractCollectionPersister implements CachedCollectionPersister |
||||||
28 | { |
||||||
29 | /** @var UnitOfWork */ |
||||||
30 | protected $uow; |
||||||
31 | |||||||
32 | /** @var ClassMetadataFactory */ |
||||||
33 | protected $metadataFactory; |
||||||
34 | |||||||
35 | /** @var CollectionPersister */ |
||||||
36 | protected $persister; |
||||||
37 | |||||||
38 | /** @var ClassMetadata */ |
||||||
39 | protected $sourceEntity; |
||||||
40 | |||||||
41 | /** @var ClassMetadata */ |
||||||
42 | protected $targetEntity; |
||||||
43 | |||||||
44 | /** @var AssociationMetadata */ |
||||||
45 | protected $association; |
||||||
46 | |||||||
47 | /** @var mixed[][] */ |
||||||
48 | protected $queuedCache = []; |
||||||
49 | |||||||
50 | /** @var Region */ |
||||||
51 | protected $region; |
||||||
52 | |||||||
53 | /** @var string */ |
||||||
54 | protected $regionName; |
||||||
55 | |||||||
56 | /** @var CollectionHydrator */ |
||||||
57 | protected $hydrator; |
||||||
58 | |||||||
59 | /** @var CacheLogger */ |
||||||
60 | protected $cacheLogger; |
||||||
61 | |||||||
62 | /** |
||||||
63 | * @param CollectionPersister $persister The collection persister that will be cached. |
||||||
64 | * @param Region $region The collection region. |
||||||
65 | * @param EntityManagerInterface $em The entity manager. |
||||||
66 | * @param AssociationMetadata $association The association mapping. |
||||||
67 | */ |
||||||
68 | 117 | public function __construct( |
|||||
69 | CollectionPersister $persister, |
||||||
70 | Region $region, |
||||||
71 | EntityManagerInterface $em, |
||||||
72 | AssociationMetadata $association |
||||||
73 | ) { |
||||||
74 | 117 | $configuration = $em->getConfiguration(); |
|||||
75 | 117 | $cacheConfig = $configuration->getSecondLevelCacheConfiguration(); |
|||||
76 | 117 | $cacheFactory = $cacheConfig->getCacheFactory(); |
|||||
77 | |||||||
78 | 117 | $this->region = $region; |
|||||
79 | 117 | $this->persister = $persister; |
|||||
80 | 117 | $this->association = $association; |
|||||
81 | 117 | $this->regionName = $region->getName(); |
|||||
82 | 117 | $this->uow = $em->getUnitOfWork(); |
|||||
83 | 117 | $this->metadataFactory = $em->getMetadataFactory(); |
|||||
84 | 117 | $this->cacheLogger = $cacheConfig->getCacheLogger(); |
|||||
85 | 117 | $this->hydrator = $cacheFactory->buildCollectionHydrator($em, $association); |
|||||
86 | 117 | $this->sourceEntity = $em->getClassMetadata($association->getSourceEntity()); |
|||||
0 ignored issues
–
show
|
|||||||
87 | 117 | $this->targetEntity = $em->getClassMetadata($association->getTargetEntity()); |
|||||
0 ignored issues
–
show
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.. ![]() |
|||||||
88 | 117 | } |
|||||
89 | |||||||
90 | /** |
||||||
91 | * {@inheritdoc} |
||||||
92 | */ |
||||||
93 | 63 | public function getCacheRegion() |
|||||
94 | { |
||||||
95 | 63 | return $this->region; |
|||||
96 | } |
||||||
97 | |||||||
98 | /** |
||||||
99 | * {@inheritdoc} |
||||||
100 | */ |
||||||
101 | public function getSourceEntityMetadata() |
||||||
102 | { |
||||||
103 | return $this->sourceEntity; |
||||||
104 | } |
||||||
105 | |||||||
106 | /** |
||||||
107 | * {@inheritdoc} |
||||||
108 | */ |
||||||
109 | public function getTargetEntityMetadata() |
||||||
110 | { |
||||||
111 | return $this->targetEntity; |
||||||
112 | } |
||||||
113 | |||||||
114 | /** |
||||||
115 | * @return PersistentCollection|null |
||||||
116 | */ |
||||||
117 | 18 | public function loadCollectionCache(PersistentCollection $collection, CollectionCacheKey $key) |
|||||
118 | { |
||||||
119 | 18 | $cache = $this->region->get($key); |
|||||
120 | |||||||
121 | 18 | if ($cache === null) { |
|||||
122 | 14 | return null; |
|||||
123 | } |
||||||
124 | |||||||
125 | 15 | return $this->hydrator->loadCacheEntry($this->sourceEntity, $key, $cache, $collection); |
|||||
0 ignored issues
–
show
|
|||||||
126 | } |
||||||
127 | |||||||
128 | /** |
||||||
129 | * {@inheritdoc} |
||||||
130 | */ |
||||||
131 | 45 | public function storeCollectionCache(CollectionCacheKey $key, $elements) |
|||||
132 | { |
||||||
133 | /** @var CachedEntityPersister $targetPersister */ |
||||||
134 | 45 | $association = $this->sourceEntity->getProperty($key->association); |
|||||
135 | 45 | $targetPersister = $this->uow->getEntityPersister($this->targetEntity->getRootClassName()); |
|||||
136 | 45 | $targetRegion = $targetPersister->getCacheRegion(); |
|||||
0 ignored issues
–
show
The method
getCacheRegion() does not exist on Doctrine\ORM\Persisters\Entity\EntityPersister . It seems like you code against a sub-type of Doctrine\ORM\Persisters\Entity\EntityPersister such as Doctrine\ORM\Cache\Persi...y\CachedEntityPersister .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
137 | 45 | $targetHydrator = $targetPersister->getEntityHydrator(); |
|||||
0 ignored issues
–
show
The method
getEntityHydrator() does not exist on Doctrine\ORM\Persisters\Entity\EntityPersister . It seems like you code against a sub-type of Doctrine\ORM\Persisters\Entity\EntityPersister such as Doctrine\ORM\Cache\Persi...y\CachedEntityPersister .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
138 | |||||||
139 | // Only preserve ordering if association configured it |
||||||
140 | 45 | if (! ($association instanceof ToManyAssociationMetadata && $association->getIndexedBy())) { |
|||||
141 | // Elements may be an array or a Collection |
||||||
142 | 45 | $elements = array_values($elements instanceof Collection ? $elements->getValues() : $elements); |
|||||
143 | } |
||||||
144 | |||||||
145 | 45 | $entry = $this->hydrator->buildCacheEntry($this->targetEntity, $key, $elements); |
|||||
146 | |||||||
147 | 45 | foreach ($entry->identifiers as $index => $entityKey) { |
|||||
148 | 45 | if ($targetRegion->contains($entityKey)) { |
|||||
149 | 45 | continue; |
|||||
150 | } |
||||||
151 | |||||||
152 | 11 | $class = $this->targetEntity; |
|||||
153 | 11 | $className = StaticClassNameConverter::getClass($elements[$index]); |
|||||
154 | |||||||
155 | 11 | if ($className !== $this->targetEntity->getClassName()) { |
|||||
156 | 2 | $class = $this->metadataFactory->getMetadataFor($className); |
|||||
157 | } |
||||||
158 | |||||||
159 | 11 | $entity = $elements[$index]; |
|||||
160 | 11 | $entityEntry = $targetHydrator->buildCacheEntry($class, $entityKey, $entity); |
|||||
161 | |||||||
162 | 11 | $targetRegion->put($entityKey, $entityEntry); |
|||||
163 | } |
||||||
164 | |||||||
165 | 45 | $cached = $this->region->put($key, $entry); |
|||||
166 | |||||||
167 | 45 | if ($this->cacheLogger && $cached) { |
|||||
168 | 45 | $this->cacheLogger->collectionCachePut($this->regionName, $key); |
|||||
169 | } |
||||||
170 | 45 | } |
|||||
171 | |||||||
172 | /** |
||||||
173 | * {@inheritdoc} |
||||||
174 | */ |
||||||
175 | 3 | public function contains(PersistentCollection $collection, $element) |
|||||
176 | { |
||||||
177 | 3 | return $this->persister->contains($collection, $element); |
|||||
178 | } |
||||||
179 | |||||||
180 | /** |
||||||
181 | * {@inheritdoc} |
||||||
182 | */ |
||||||
183 | 3 | public function containsKey(PersistentCollection $collection, $key) |
|||||
184 | { |
||||||
185 | 3 | return $this->persister->containsKey($collection, $key); |
|||||
186 | } |
||||||
187 | |||||||
188 | /** |
||||||
189 | * {@inheritdoc} |
||||||
190 | */ |
||||||
191 | 4 | public function count(PersistentCollection $collection) |
|||||
192 | { |
||||||
193 | 4 | $fieldName = $this->association->getName(); |
|||||
194 | 4 | $ownerId = $this->uow->getEntityIdentifier($collection->getOwner()); |
|||||
195 | 4 | $key = new CollectionCacheKey($this->sourceEntity->getRootClassName(), $fieldName, $ownerId); |
|||||
196 | 4 | $entry = $this->region->get($key); |
|||||
197 | |||||||
198 | 4 | if ($entry !== null) { |
|||||
199 | 1 | return count($entry->identifiers); |
|||||
0 ignored issues
–
show
|
|||||||
200 | } |
||||||
201 | |||||||
202 | 4 | return $this->persister->count($collection); |
|||||
203 | } |
||||||
204 | |||||||
205 | /** |
||||||
206 | * {@inheritdoc} |
||||||
207 | */ |
||||||
208 | 3 | public function get(PersistentCollection $collection, $index) |
|||||
209 | { |
||||||
210 | 3 | return $this->persister->get($collection, $index); |
|||||
211 | } |
||||||
212 | |||||||
213 | /** |
||||||
214 | * {@inheritdoc} |
||||||
215 | */ |
||||||
216 | 3 | public function removeElement(PersistentCollection $collection, $element) |
|||||
217 | { |
||||||
218 | 3 | $persisterResult = $this->persister->removeElement($collection, $element); |
|||||
219 | |||||||
220 | 3 | if ($persisterResult) { |
|||||
221 | $this->evictCollectionCache($collection); |
||||||
222 | $this->evictElementCache($this->sourceEntity->getRootClassName(), $collection->getOwner()); |
||||||
223 | $this->evictElementCache($this->targetEntity->getRootClassName(), $element); |
||||||
224 | } |
||||||
225 | |||||||
226 | 3 | return $persisterResult; |
|||||
227 | } |
||||||
228 | |||||||
229 | /** |
||||||
230 | * {@inheritdoc} |
||||||
231 | */ |
||||||
232 | 3 | public function slice(PersistentCollection $collection, $offset, $length = null) |
|||||
233 | { |
||||||
234 | 3 | return $this->persister->slice($collection, $offset, $length); |
|||||
235 | } |
||||||
236 | |||||||
237 | /** |
||||||
238 | * {@inheritDoc} |
||||||
239 | */ |
||||||
240 | public function loadCriteria(PersistentCollection $collection, Criteria $criteria) |
||||||
241 | { |
||||||
242 | return $this->persister->loadCriteria($collection, $criteria); |
||||||
243 | } |
||||||
244 | |||||||
245 | /** |
||||||
246 | * Clears cache entries related to the current collection |
||||||
247 | */ |
||||||
248 | protected function evictCollectionCache(PersistentCollection $collection) |
||||||
249 | { |
||||||
250 | $key = new CollectionCacheKey( |
||||||
251 | $this->sourceEntity->getRootClassName(), |
||||||
252 | $this->association->getName(), |
||||||
253 | $this->uow->getEntityIdentifier($collection->getOwner()) |
||||||
254 | ); |
||||||
255 | |||||||
256 | $this->region->evict($key); |
||||||
257 | |||||||
258 | if ($this->cacheLogger) { |
||||||
259 | $this->cacheLogger->collectionCachePut($this->regionName, $key); |
||||||
260 | } |
||||||
261 | } |
||||||
262 | |||||||
263 | /** |
||||||
264 | * @param string $targetEntity |
||||||
265 | * @param object $element |
||||||
266 | */ |
||||||
267 | protected function evictElementCache($targetEntity, $element) |
||||||
268 | { |
||||||
269 | /** @var CachedEntityPersister $targetPersister */ |
||||||
270 | $targetPersister = $this->uow->getEntityPersister($targetEntity); |
||||||
271 | $targetRegion = $targetPersister->getCacheRegion(); |
||||||
272 | $key = new EntityCacheKey($targetEntity, $this->uow->getEntityIdentifier($element)); |
||||||
273 | |||||||
274 | $targetRegion->evict($key); |
||||||
275 | |||||||
276 | if ($this->cacheLogger) { |
||||||
277 | $this->cacheLogger->entityCachePut($targetRegion->getName(), $key); |
||||||
278 | } |
||||||
279 | } |
||||||
280 | } |
||||||
281 |
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..