summaryrefslogtreecommitdiff
path: root/vendor/doctrine/orm/src/Cache/Persister/Entity
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/doctrine/orm/src/Cache/Persister/Entity')
-rw-r--r--vendor/doctrine/orm/src/Cache/Persister/Entity/AbstractEntityPersister.php557
-rw-r--r--vendor/doctrine/orm/src/Cache/Persister/Entity/CachedEntityPersister.php20
-rw-r--r--vendor/doctrine/orm/src/Cache/Persister/Entity/NonStrictReadWriteCachedEntityPersister.php85
-rw-r--r--vendor/doctrine/orm/src/Cache/Persister/Entity/ReadOnlyCachedEntityPersister.php19
-rw-r--r--vendor/doctrine/orm/src/Cache/Persister/Entity/ReadWriteCachedEntityPersister.php105
5 files changed, 786 insertions, 0 deletions
diff --git a/vendor/doctrine/orm/src/Cache/Persister/Entity/AbstractEntityPersister.php b/vendor/doctrine/orm/src/Cache/Persister/Entity/AbstractEntityPersister.php
new file mode 100644
index 0000000..9f371d8
--- /dev/null
+++ b/vendor/doctrine/orm/src/Cache/Persister/Entity/AbstractEntityPersister.php
@@ -0,0 +1,557 @@
1<?php
2
3declare(strict_types=1);
4
5namespace Doctrine\ORM\Cache\Persister\Entity;
6
7use Doctrine\Common\Collections\Criteria;
8use Doctrine\Common\Collections\Order;
9use Doctrine\DBAL\LockMode;
10use Doctrine\ORM\Cache;
11use Doctrine\ORM\Cache\CollectionCacheKey;
12use Doctrine\ORM\Cache\EntityCacheKey;
13use Doctrine\ORM\Cache\EntityHydrator;
14use Doctrine\ORM\Cache\Logging\CacheLogger;
15use Doctrine\ORM\Cache\Persister\CachedPersister;
16use Doctrine\ORM\Cache\QueryCacheKey;
17use Doctrine\ORM\Cache\Region;
18use Doctrine\ORM\Cache\TimestampCacheKey;
19use Doctrine\ORM\Cache\TimestampRegion;
20use Doctrine\ORM\EntityManagerInterface;
21use Doctrine\ORM\Mapping\AssociationMapping;
22use Doctrine\ORM\Mapping\ClassMetadata;
23use Doctrine\ORM\Mapping\ClassMetadataFactory;
24use Doctrine\ORM\PersistentCollection;
25use Doctrine\ORM\Persisters\Entity\EntityPersister;
26use Doctrine\ORM\Proxy\DefaultProxyClassNameResolver;
27use Doctrine\ORM\Query\ResultSetMapping;
28use Doctrine\ORM\UnitOfWork;
29
30use function array_merge;
31use function assert;
32use function serialize;
33use function sha1;
34
35abstract class AbstractEntityPersister implements CachedEntityPersister
36{
37 protected UnitOfWork $uow;
38 protected ClassMetadataFactory $metadataFactory;
39
40 /** @var mixed[] */
41 protected array $queuedCache = [];
42
43 protected TimestampRegion $timestampRegion;
44 protected TimestampCacheKey $timestampKey;
45 protected EntityHydrator $hydrator;
46 protected Cache $cache;
47 protected CacheLogger|null $cacheLogger = null;
48 protected string $regionName;
49
50 /**
51 * Associations configured as FETCH_EAGER, as well as all inverse one-to-one associations.
52 *
53 * @var array<string>|null
54 */
55 protected array|null $joinedAssociations = null;
56
57 public function __construct(
58 protected EntityPersister $persister,
59 protected Region $region,
60 EntityManagerInterface $em,
61 protected ClassMetadata $class,
62 ) {
63 $configuration = $em->getConfiguration();
64 $cacheConfig = $configuration->getSecondLevelCacheConfiguration();
65 $cacheFactory = $cacheConfig->getCacheFactory();
66
67 $this->cache = $em->getCache();
68 $this->regionName = $region->getName();
69 $this->uow = $em->getUnitOfWork();
70 $this->metadataFactory = $em->getMetadataFactory();
71 $this->cacheLogger = $cacheConfig->getCacheLogger();
72 $this->timestampRegion = $cacheFactory->getTimestampRegion();
73 $this->hydrator = $cacheFactory->buildEntityHydrator($em, $class);
74 $this->timestampKey = new TimestampCacheKey($this->class->rootEntityName);
75 }
76
77 public function addInsert(object $entity): void
78 {
79 $this->persister->addInsert($entity);
80 }
81
82 /**
83 * {@inheritDoc}
84 */
85 public function getInserts(): array
86 {
87 return $this->persister->getInserts();
88 }
89
90 public function getSelectSQL(
91 array|Criteria $criteria,
92 AssociationMapping|null $assoc = null,
93 LockMode|int|null $lockMode = null,
94 int|null $limit = null,
95 int|null $offset = null,
96 array|null $orderBy = null,
97 ): string {
98 return $this->persister->getSelectSQL($criteria, $assoc, $lockMode, $limit, $offset, $orderBy);
99 }
100
101 public function getCountSQL(array|Criteria $criteria = []): string
102 {
103 return $this->persister->getCountSQL($criteria);
104 }
105
106 public function getInsertSQL(): string
107 {
108 return $this->persister->getInsertSQL();
109 }
110
111 public function getResultSetMapping(): ResultSetMapping
112 {
113 return $this->persister->getResultSetMapping();
114 }
115
116 public function getSelectConditionStatementSQL(
117 string $field,
118 mixed $value,
119 AssociationMapping|null $assoc = null,
120 string|null $comparison = null,
121 ): string {
122 return $this->persister->getSelectConditionStatementSQL($field, $value, $assoc, $comparison);
123 }
124
125 public function exists(object $entity, Criteria|null $extraConditions = null): bool
126 {
127 if ($extraConditions === null) {
128 $key = new EntityCacheKey($this->class->rootEntityName, $this->class->getIdentifierValues($entity));
129
130 if ($this->region->contains($key)) {
131 return true;
132 }
133 }
134
135 return $this->persister->exists($entity, $extraConditions);
136 }
137
138 public function getCacheRegion(): Region
139 {
140 return $this->region;
141 }
142
143 public function getEntityHydrator(): EntityHydrator
144 {
145 return $this->hydrator;
146 }
147
148 public function storeEntityCache(object $entity, EntityCacheKey $key): bool
149 {
150 $class = $this->class;
151 $className = DefaultProxyClassNameResolver::getClass($entity);
152
153 if ($className !== $this->class->name) {
154 $class = $this->metadataFactory->getMetadataFor($className);
155 }
156
157 $entry = $this->hydrator->buildCacheEntry($class, $key, $entity);
158 $cached = $this->region->put($key, $entry);
159
160 if ($cached) {
161 $this->cacheLogger?->entityCachePut($this->regionName, $key);
162 }
163
164 return $cached;
165 }
166
167 private function storeJoinedAssociations(object $entity): void
168 {
169 if ($this->joinedAssociations === null) {
170 $associations = [];
171
172 foreach ($this->class->associationMappings as $name => $assoc) {
173 if (
174 isset($assoc->cache) &&
175 ($assoc->isToOne()) &&
176 ($assoc->fetch === ClassMetadata::FETCH_EAGER || ! $assoc->isOwningSide())
177 ) {
178 $associations[] = $name;
179 }
180 }
181
182 $this->joinedAssociations = $associations;
183 }
184
185 foreach ($this->joinedAssociations as $name) {
186 $assoc = $this->class->associationMappings[$name];
187 $assocEntity = $this->class->getFieldValue($entity, $name);
188
189 if ($assocEntity === null) {
190 continue;
191 }
192
193 $assocId = $this->uow->getEntityIdentifier($assocEntity);
194 $assocMetadata = $this->metadataFactory->getMetadataFor($assoc->targetEntity);
195 $assocKey = new EntityCacheKey($assocMetadata->rootEntityName, $assocId);
196 $assocPersister = $this->uow->getEntityPersister($assoc->targetEntity);
197
198 $assocPersister->storeEntityCache($assocEntity, $assocKey);
199 }
200 }
201
202 /**
203 * Generates a string of currently query
204 *
205 * @param string[]|Criteria $criteria
206 * @param array<string, Order>|null $orderBy
207 */
208 protected function getHash(
209 string $query,
210 array|Criteria $criteria,
211 array|null $orderBy = null,
212 int|null $limit = null,
213 int|null $offset = null,
214 ): string {
215 [$params] = $criteria instanceof Criteria
216 ? $this->persister->expandCriteriaParameters($criteria)
217 : $this->persister->expandParameters($criteria);
218
219 return sha1($query . serialize($params) . serialize($orderBy) . $limit . $offset);
220 }
221
222 /**
223 * {@inheritDoc}
224 */
225 public function expandParameters(array $criteria): array
226 {
227 return $this->persister->expandParameters($criteria);
228 }
229
230 /**
231 * {@inheritDoc}
232 */
233 public function expandCriteriaParameters(Criteria $criteria): array
234 {
235 return $this->persister->expandCriteriaParameters($criteria);
236 }
237
238 public function getClassMetadata(): ClassMetadata
239 {
240 return $this->persister->getClassMetadata();
241 }
242
243 /**
244 * {@inheritDoc}
245 */
246 public function getManyToManyCollection(
247 AssociationMapping $assoc,
248 object $sourceEntity,
249 int|null $offset = null,
250 int|null $limit = null,
251 ): array {
252 return $this->persister->getManyToManyCollection($assoc, $sourceEntity, $offset, $limit);
253 }
254
255 /**
256 * {@inheritDoc}
257 */
258 public function getOneToManyCollection(
259 AssociationMapping $assoc,
260 object $sourceEntity,
261 int|null $offset = null,
262 int|null $limit = null,
263 ): array {
264 return $this->persister->getOneToManyCollection($assoc, $sourceEntity, $offset, $limit);
265 }
266
267 public function getOwningTable(string $fieldName): string
268 {
269 return $this->persister->getOwningTable($fieldName);
270 }
271
272 public function executeInserts(): void
273 {
274 // The commit order/foreign key relationships may make it necessary that multiple calls to executeInsert()
275 // are performed, so collect all the new entities.
276 $newInserts = $this->persister->getInserts();
277
278 if ($newInserts) {
279 $this->queuedCache['insert'] = array_merge($this->queuedCache['insert'] ?? [], $newInserts);
280 }
281
282 $this->persister->executeInserts();
283 }
284
285 /**
286 * {@inheritDoc}
287 */
288 public function load(
289 array $criteria,
290 object|null $entity = null,
291 AssociationMapping|null $assoc = null,
292 array $hints = [],
293 LockMode|int|null $lockMode = null,
294 int|null $limit = null,
295 array|null $orderBy = null,
296 ): object|null {
297 if ($entity !== null || $assoc !== null || $hints !== [] || $lockMode !== null) {
298 return $this->persister->load($criteria, $entity, $assoc, $hints, $lockMode, $limit, $orderBy);
299 }
300
301 //handle only EntityRepository#findOneBy
302 $query = $this->persister->getSelectSQL($criteria, null, null, $limit, null, $orderBy);
303 $hash = $this->getHash($query, $criteria);
304 $rsm = $this->getResultSetMapping();
305 $queryKey = new QueryCacheKey($hash, 0, Cache::MODE_NORMAL, $this->timestampKey);
306 $queryCache = $this->cache->getQueryCache($this->regionName);
307 $result = $queryCache->get($queryKey, $rsm);
308
309 if ($result !== null) {
310 $this->cacheLogger?->queryCacheHit($this->regionName, $queryKey);
311
312 return $result[0];
313 }
314
315 $result = $this->persister->load($criteria, $entity, $assoc, $hints, $lockMode, $limit, $orderBy);
316
317 if ($result === null) {
318 return null;
319 }
320
321 $cached = $queryCache->put($queryKey, $rsm, [$result]);
322
323 $this->cacheLogger?->queryCacheMiss($this->regionName, $queryKey);
324
325 if ($cached) {
326 $this->cacheLogger?->queryCachePut($this->regionName, $queryKey);
327 }
328
329 return $result;
330 }
331
332 /**
333 * {@inheritDoc}
334 */
335 public function loadAll(
336 array $criteria = [],
337 array|null $orderBy = null,
338 int|null $limit = null,
339 int|null $offset = null,
340 ): array {
341 $query = $this->persister->getSelectSQL($criteria, null, null, $limit, $offset, $orderBy);
342 $hash = $this->getHash($query, $criteria);
343 $rsm = $this->getResultSetMapping();
344 $queryKey = new QueryCacheKey($hash, 0, Cache::MODE_NORMAL, $this->timestampKey);
345 $queryCache = $this->cache->getQueryCache($this->regionName);
346 $result = $queryCache->get($queryKey, $rsm);
347
348 if ($result !== null) {
349 $this->cacheLogger?->queryCacheHit($this->regionName, $queryKey);
350
351 return $result;
352 }
353
354 $result = $this->persister->loadAll($criteria, $orderBy, $limit, $offset);
355 $cached = $queryCache->put($queryKey, $rsm, $result);
356
357 if ($result) {
358 $this->cacheLogger?->queryCacheMiss($this->regionName, $queryKey);
359 }
360
361 if ($cached) {
362 $this->cacheLogger?->queryCachePut($this->regionName, $queryKey);
363 }
364
365 return $result;
366 }
367
368 /**
369 * {@inheritDoc}
370 */
371 public function loadById(array $identifier, object|null $entity = null): object|null
372 {
373 $cacheKey = new EntityCacheKey($this->class->rootEntityName, $identifier);
374 $cacheEntry = $this->region->get($cacheKey);
375 $class = $this->class;
376
377 if ($cacheEntry !== null) {
378 if ($cacheEntry->class !== $this->class->name) {
379 $class = $this->metadataFactory->getMetadataFor($cacheEntry->class);
380 }
381
382 $cachedEntity = $this->hydrator->loadCacheEntry($class, $cacheKey, $cacheEntry, $entity);
383
384 if ($cachedEntity !== null) {
385 $this->cacheLogger?->entityCacheHit($this->regionName, $cacheKey);
386
387 return $cachedEntity;
388 }
389 }
390
391 $entity = $this->persister->loadById($identifier, $entity);
392
393 if ($entity === null) {
394 return null;
395 }
396
397 $class = $this->class;
398 $className = DefaultProxyClassNameResolver::getClass($entity);
399
400 if ($className !== $this->class->name) {
401 $class = $this->metadataFactory->getMetadataFor($className);
402 }
403
404 $cacheEntry = $this->hydrator->buildCacheEntry($class, $cacheKey, $entity);
405 $cached = $this->region->put($cacheKey, $cacheEntry);
406
407 if ($cached && ($this->joinedAssociations === null || $this->joinedAssociations)) {
408 $this->storeJoinedAssociations($entity);
409 }
410
411 if ($cached) {
412 $this->cacheLogger?->entityCachePut($this->regionName, $cacheKey);
413 }
414
415 $this->cacheLogger?->entityCacheMiss($this->regionName, $cacheKey);
416
417 return $entity;
418 }
419
420 public function count(array|Criteria $criteria = []): int
421 {
422 return $this->persister->count($criteria);
423 }
424
425 /**
426 * {@inheritDoc}
427 */
428 public function loadCriteria(Criteria $criteria): array
429 {
430 $orderBy = $criteria->orderings();
431 $limit = $criteria->getMaxResults();
432 $offset = $criteria->getFirstResult();
433 $query = $this->persister->getSelectSQL($criteria);
434 $hash = $this->getHash($query, $criteria, $orderBy, $limit, $offset);
435 $rsm = $this->getResultSetMapping();
436 $queryKey = new QueryCacheKey($hash, 0, Cache::MODE_NORMAL, $this->timestampKey);
437 $queryCache = $this->cache->getQueryCache($this->regionName);
438 $cacheResult = $queryCache->get($queryKey, $rsm);
439
440 if ($cacheResult !== null) {
441 $this->cacheLogger?->queryCacheHit($this->regionName, $queryKey);
442
443 return $cacheResult;
444 }
445
446 $result = $this->persister->loadCriteria($criteria);
447 $cached = $queryCache->put($queryKey, $rsm, $result);
448
449 if ($result) {
450 $this->cacheLogger?->queryCacheMiss($this->regionName, $queryKey);
451 }
452
453 if ($cached) {
454 $this->cacheLogger?->queryCachePut($this->regionName, $queryKey);
455 }
456
457 return $result;
458 }
459
460 /**
461 * {@inheritDoc}
462 */
463 public function loadManyToManyCollection(
464 AssociationMapping $assoc,
465 object $sourceEntity,
466 PersistentCollection $collection,
467 ): array {
468 $persister = $this->uow->getCollectionPersister($assoc);
469 $hasCache = ($persister instanceof CachedPersister);
470
471 if (! $hasCache) {
472 return $this->persister->loadManyToManyCollection($assoc, $sourceEntity, $collection);
473 }
474
475 $ownerId = $this->uow->getEntityIdentifier($collection->getOwner());
476 $key = $this->buildCollectionCacheKey($assoc, $ownerId);
477 $list = $persister->loadCollectionCache($collection, $key);
478
479 if ($list !== null) {
480 $this->cacheLogger?->collectionCacheHit($persister->getCacheRegion()->getName(), $key);
481
482 return $list;
483 }
484
485 $list = $this->persister->loadManyToManyCollection($assoc, $sourceEntity, $collection);
486
487 $persister->storeCollectionCache($key, $list);
488
489 $this->cacheLogger?->collectionCacheMiss($persister->getCacheRegion()->getName(), $key);
490
491 return $list;
492 }
493
494 public function loadOneToManyCollection(
495 AssociationMapping $assoc,
496 object $sourceEntity,
497 PersistentCollection $collection,
498 ): mixed {
499 $persister = $this->uow->getCollectionPersister($assoc);
500 $hasCache = ($persister instanceof CachedPersister);
501
502 if (! $hasCache) {
503 return $this->persister->loadOneToManyCollection($assoc, $sourceEntity, $collection);
504 }
505
506 $ownerId = $this->uow->getEntityIdentifier($collection->getOwner());
507 $key = $this->buildCollectionCacheKey($assoc, $ownerId);
508 $list = $persister->loadCollectionCache($collection, $key);
509
510 if ($list !== null) {
511 $this->cacheLogger?->collectionCacheHit($persister->getCacheRegion()->getName(), $key);
512
513 return $list;
514 }
515
516 $list = $this->persister->loadOneToManyCollection($assoc, $sourceEntity, $collection);
517
518 $persister->storeCollectionCache($key, $list);
519
520 $this->cacheLogger?->collectionCacheMiss($persister->getCacheRegion()->getName(), $key);
521
522 return $list;
523 }
524
525 /**
526 * {@inheritDoc}
527 */
528 public function loadOneToOneEntity(AssociationMapping $assoc, object $sourceEntity, array $identifier = []): object|null
529 {
530 return $this->persister->loadOneToOneEntity($assoc, $sourceEntity, $identifier);
531 }
532
533 /**
534 * {@inheritDoc}
535 */
536 public function lock(array $criteria, LockMode|int $lockMode): void
537 {
538 $this->persister->lock($criteria, $lockMode);
539 }
540
541 /**
542 * {@inheritDoc}
543 */
544 public function refresh(array $id, object $entity, LockMode|int|null $lockMode = null): void
545 {
546 $this->persister->refresh($id, $entity, $lockMode);
547 }
548
549 /** @param array<string, mixed> $ownerId */
550 protected function buildCollectionCacheKey(AssociationMapping $association, array $ownerId): CollectionCacheKey
551 {
552 $metadata = $this->metadataFactory->getMetadataFor($association->sourceEntity);
553 assert($metadata instanceof ClassMetadata);
554
555 return new CollectionCacheKey($metadata->rootEntityName, $association->fieldName, $ownerId);
556 }
557}
diff --git a/vendor/doctrine/orm/src/Cache/Persister/Entity/CachedEntityPersister.php b/vendor/doctrine/orm/src/Cache/Persister/Entity/CachedEntityPersister.php
new file mode 100644
index 0000000..5fba56f
--- /dev/null
+++ b/vendor/doctrine/orm/src/Cache/Persister/Entity/CachedEntityPersister.php
@@ -0,0 +1,20 @@
1<?php
2
3declare(strict_types=1);
4
5namespace Doctrine\ORM\Cache\Persister\Entity;
6
7use Doctrine\ORM\Cache\EntityCacheKey;
8use Doctrine\ORM\Cache\EntityHydrator;
9use Doctrine\ORM\Cache\Persister\CachedPersister;
10use Doctrine\ORM\Persisters\Entity\EntityPersister;
11
12/**
13 * Interface for second level cache entity persisters.
14 */
15interface CachedEntityPersister extends CachedPersister, EntityPersister
16{
17 public function getEntityHydrator(): EntityHydrator;
18
19 public function storeEntityCache(object $entity, EntityCacheKey $key): bool;
20}
diff --git a/vendor/doctrine/orm/src/Cache/Persister/Entity/NonStrictReadWriteCachedEntityPersister.php b/vendor/doctrine/orm/src/Cache/Persister/Entity/NonStrictReadWriteCachedEntityPersister.php
new file mode 100644
index 0000000..43c76ab
--- /dev/null
+++ b/vendor/doctrine/orm/src/Cache/Persister/Entity/NonStrictReadWriteCachedEntityPersister.php
@@ -0,0 +1,85 @@
1<?php
2
3declare(strict_types=1);
4
5namespace Doctrine\ORM\Cache\Persister\Entity;
6
7use Doctrine\ORM\Cache\EntityCacheKey;
8
9/**
10 * Specific non-strict read/write cached entity persister
11 */
12class NonStrictReadWriteCachedEntityPersister extends AbstractEntityPersister
13{
14 public function afterTransactionComplete(): void
15 {
16 $isChanged = false;
17
18 if (isset($this->queuedCache['insert'])) {
19 foreach ($this->queuedCache['insert'] as $entity) {
20 $isChanged = $this->updateCache($entity, $isChanged);
21 }
22 }
23
24 if (isset($this->queuedCache['update'])) {
25 foreach ($this->queuedCache['update'] as $entity) {
26 $isChanged = $this->updateCache($entity, $isChanged);
27 }
28 }
29
30 if (isset($this->queuedCache['delete'])) {
31 foreach ($this->queuedCache['delete'] as $key) {
32 $this->region->evict($key);
33
34 $isChanged = true;
35 }
36 }
37
38 if ($isChanged) {
39 $this->timestampRegion->update($this->timestampKey);
40 }
41
42 $this->queuedCache = [];
43 }
44
45 public function afterTransactionRolledBack(): void
46 {
47 $this->queuedCache = [];
48 }
49
50 public function delete(object $entity): bool
51 {
52 $key = new EntityCacheKey($this->class->rootEntityName, $this->uow->getEntityIdentifier($entity));
53 $deleted = $this->persister->delete($entity);
54
55 if ($deleted) {
56 $this->region->evict($key);
57 }
58
59 $this->queuedCache['delete'][] = $key;
60
61 return $deleted;
62 }
63
64 public function update(object $entity): void
65 {
66 $this->persister->update($entity);
67
68 $this->queuedCache['update'][] = $entity;
69 }
70
71 private function updateCache(object $entity, bool $isChanged): bool
72 {
73 $class = $this->metadataFactory->getMetadataFor($entity::class);
74 $key = new EntityCacheKey($class->rootEntityName, $this->uow->getEntityIdentifier($entity));
75 $entry = $this->hydrator->buildCacheEntry($class, $key, $entity);
76 $cached = $this->region->put($key, $entry);
77 $isChanged = $isChanged || $cached;
78
79 if ($cached) {
80 $this->cacheLogger?->entityCachePut($this->regionName, $key);
81 }
82
83 return $isChanged;
84 }
85}
diff --git a/vendor/doctrine/orm/src/Cache/Persister/Entity/ReadOnlyCachedEntityPersister.php b/vendor/doctrine/orm/src/Cache/Persister/Entity/ReadOnlyCachedEntityPersister.php
new file mode 100644
index 0000000..4cd1784
--- /dev/null
+++ b/vendor/doctrine/orm/src/Cache/Persister/Entity/ReadOnlyCachedEntityPersister.php
@@ -0,0 +1,19 @@
1<?php
2
3declare(strict_types=1);
4
5namespace Doctrine\ORM\Cache\Persister\Entity;
6
7use Doctrine\ORM\Cache\Exception\CannotUpdateReadOnlyEntity;
8use Doctrine\ORM\Proxy\DefaultProxyClassNameResolver;
9
10/**
11 * Specific read-only region entity persister
12 */
13class ReadOnlyCachedEntityPersister extends NonStrictReadWriteCachedEntityPersister
14{
15 public function update(object $entity): void
16 {
17 throw CannotUpdateReadOnlyEntity::fromEntity(DefaultProxyClassNameResolver::getClass($entity));
18 }
19}
diff --git a/vendor/doctrine/orm/src/Cache/Persister/Entity/ReadWriteCachedEntityPersister.php b/vendor/doctrine/orm/src/Cache/Persister/Entity/ReadWriteCachedEntityPersister.php
new file mode 100644
index 0000000..a1ea0dc
--- /dev/null
+++ b/vendor/doctrine/orm/src/Cache/Persister/Entity/ReadWriteCachedEntityPersister.php
@@ -0,0 +1,105 @@
1<?php
2
3declare(strict_types=1);
4
5namespace Doctrine\ORM\Cache\Persister\Entity;
6
7use Doctrine\ORM\Cache\ConcurrentRegion;
8use Doctrine\ORM\Cache\EntityCacheKey;
9use Doctrine\ORM\EntityManagerInterface;
10use Doctrine\ORM\Mapping\ClassMetadata;
11use Doctrine\ORM\Persisters\Entity\EntityPersister;
12
13/**
14 * Specific read-write entity persister
15 */
16class ReadWriteCachedEntityPersister extends AbstractEntityPersister
17{
18 public function __construct(EntityPersister $persister, ConcurrentRegion $region, EntityManagerInterface $em, ClassMetadata $class)
19 {
20 parent::__construct($persister, $region, $em, $class);
21 }
22
23 public function afterTransactionComplete(): void
24 {
25 $isChanged = true;
26
27 if (isset($this->queuedCache['update'])) {
28 foreach ($this->queuedCache['update'] as $item) {
29 $this->region->evict($item['key']);
30
31 $isChanged = true;
32 }
33 }
34
35 if (isset($this->queuedCache['delete'])) {
36 foreach ($this->queuedCache['delete'] as $item) {
37 $this->region->evict($item['key']);
38
39 $isChanged = true;
40 }
41 }
42
43 if ($isChanged) {
44 $this->timestampRegion->update($this->timestampKey);
45 }
46
47 $this->queuedCache = [];
48 }
49
50 public function afterTransactionRolledBack(): void
51 {
52 if (isset($this->queuedCache['update'])) {
53 foreach ($this->queuedCache['update'] as $item) {
54 $this->region->evict($item['key']);
55 }
56 }
57
58 if (isset($this->queuedCache['delete'])) {
59 foreach ($this->queuedCache['delete'] as $item) {
60 $this->region->evict($item['key']);
61 }
62 }
63
64 $this->queuedCache = [];
65 }
66
67 public function delete(object $entity): bool
68 {
69 $key = new EntityCacheKey($this->class->rootEntityName, $this->uow->getEntityIdentifier($entity));
70 $lock = $this->region->lock($key);
71 $deleted = $this->persister->delete($entity);
72
73 if ($deleted) {
74 $this->region->evict($key);
75 }
76
77 if ($lock === null) {
78 return $deleted;
79 }
80
81 $this->queuedCache['delete'][] = [
82 'lock' => $lock,
83 'key' => $key,
84 ];
85
86 return $deleted;
87 }
88
89 public function update(object $entity): void
90 {
91 $key = new EntityCacheKey($this->class->rootEntityName, $this->uow->getEntityIdentifier($entity));
92 $lock = $this->region->lock($key);
93
94 $this->persister->update($entity);
95
96 if ($lock === null) {
97 return;
98 }
99
100 $this->queuedCache['update'][] = [
101 'lock' => $lock,
102 'key' => $key,
103 ];
104 }
105}