From bf6655a534a6775d30cafa67bd801276bda1d98d Mon Sep 17 00:00:00 2001 From: polo Date: Tue, 13 Aug 2024 23:45:21 +0200 Subject: =?UTF-8?q?VERSION=200.2=20doctrine=20ORM=20et=20entit=C3=A9s?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../orm/src/Cache/Persister/CachedPersister.php | 25 + .../Collection/AbstractCollectionPersister.php | 168 +++++++ .../Collection/CachedCollectionPersister.php | 36 ++ ...NonStrictReadWriteCachedCollectionPersister.php | 74 +++ .../ReadOnlyCachedCollectionPersister.php | 24 + .../ReadWriteCachedCollectionPersister.php | 103 ++++ .../Persister/Entity/AbstractEntityPersister.php | 557 +++++++++++++++++++++ .../Persister/Entity/CachedEntityPersister.php | 20 + .../NonStrictReadWriteCachedEntityPersister.php | 85 ++++ .../Entity/ReadOnlyCachedEntityPersister.php | 19 + .../Entity/ReadWriteCachedEntityPersister.php | 105 ++++ 11 files changed, 1216 insertions(+) create mode 100644 vendor/doctrine/orm/src/Cache/Persister/CachedPersister.php create mode 100644 vendor/doctrine/orm/src/Cache/Persister/Collection/AbstractCollectionPersister.php create mode 100644 vendor/doctrine/orm/src/Cache/Persister/Collection/CachedCollectionPersister.php create mode 100644 vendor/doctrine/orm/src/Cache/Persister/Collection/NonStrictReadWriteCachedCollectionPersister.php create mode 100644 vendor/doctrine/orm/src/Cache/Persister/Collection/ReadOnlyCachedCollectionPersister.php create mode 100644 vendor/doctrine/orm/src/Cache/Persister/Collection/ReadWriteCachedCollectionPersister.php create mode 100644 vendor/doctrine/orm/src/Cache/Persister/Entity/AbstractEntityPersister.php create mode 100644 vendor/doctrine/orm/src/Cache/Persister/Entity/CachedEntityPersister.php create mode 100644 vendor/doctrine/orm/src/Cache/Persister/Entity/NonStrictReadWriteCachedEntityPersister.php create mode 100644 vendor/doctrine/orm/src/Cache/Persister/Entity/ReadOnlyCachedEntityPersister.php create mode 100644 vendor/doctrine/orm/src/Cache/Persister/Entity/ReadWriteCachedEntityPersister.php (limited to 'vendor/doctrine/orm/src/Cache/Persister') diff --git a/vendor/doctrine/orm/src/Cache/Persister/CachedPersister.php b/vendor/doctrine/orm/src/Cache/Persister/CachedPersister.php new file mode 100644 index 0000000..223692c --- /dev/null +++ b/vendor/doctrine/orm/src/Cache/Persister/CachedPersister.php @@ -0,0 +1,25 @@ +getConfiguration(); + $cacheConfig = $configuration->getSecondLevelCacheConfiguration(); + $cacheFactory = $cacheConfig->getCacheFactory(); + + $this->regionName = $region->getName(); + $this->uow = $em->getUnitOfWork(); + $this->metadataFactory = $em->getMetadataFactory(); + $this->cacheLogger = $cacheConfig->getCacheLogger(); + $this->hydrator = $cacheFactory->buildCollectionHydrator($em, $association); + $this->sourceEntity = $em->getClassMetadata($association->sourceEntity); + $this->targetEntity = $em->getClassMetadata($association->targetEntity); + } + + public function getCacheRegion(): Region + { + return $this->region; + } + + public function getSourceEntityMetadata(): ClassMetadata + { + return $this->sourceEntity; + } + + public function getTargetEntityMetadata(): ClassMetadata + { + return $this->targetEntity; + } + + public function loadCollectionCache(PersistentCollection $collection, CollectionCacheKey $key): array|null + { + $cache = $this->region->get($key); + + if ($cache === null) { + return null; + } + + return $this->hydrator->loadCacheEntry($this->sourceEntity, $key, $cache, $collection); + } + + public function storeCollectionCache(CollectionCacheKey $key, Collection|array $elements): void + { + $associationMapping = $this->sourceEntity->associationMappings[$key->association]; + $targetPersister = $this->uow->getEntityPersister($this->targetEntity->rootEntityName); + assert($targetPersister instanceof CachedEntityPersister); + $targetRegion = $targetPersister->getCacheRegion(); + $targetHydrator = $targetPersister->getEntityHydrator(); + + // Only preserve ordering if association configured it + if (! $associationMapping->isIndexed()) { + // Elements may be an array or a Collection + $elements = array_values($elements instanceof Collection ? $elements->getValues() : $elements); + } + + $entry = $this->hydrator->buildCacheEntry($this->targetEntity, $key, $elements); + + foreach ($entry->identifiers as $index => $entityKey) { + if ($targetRegion->contains($entityKey)) { + continue; + } + + $class = $this->targetEntity; + $className = DefaultProxyClassNameResolver::getClass($elements[$index]); + + if ($className !== $this->targetEntity->name) { + $class = $this->metadataFactory->getMetadataFor($className); + } + + $entity = $elements[$index]; + $entityEntry = $targetHydrator->buildCacheEntry($class, $entityKey, $entity); + + $targetRegion->put($entityKey, $entityEntry); + } + + if ($this->region->put($key, $entry)) { + $this->cacheLogger?->collectionCachePut($this->regionName, $key); + } + } + + public function contains(PersistentCollection $collection, object $element): bool + { + return $this->persister->contains($collection, $element); + } + + public function containsKey(PersistentCollection $collection, mixed $key): bool + { + return $this->persister->containsKey($collection, $key); + } + + public function count(PersistentCollection $collection): int + { + $ownerId = $this->uow->getEntityIdentifier($collection->getOwner()); + $key = new CollectionCacheKey($this->sourceEntity->rootEntityName, $this->association->fieldName, $ownerId); + $entry = $this->region->get($key); + + if ($entry !== null) { + return count($entry->identifiers); + } + + return $this->persister->count($collection); + } + + public function get(PersistentCollection $collection, mixed $index): mixed + { + return $this->persister->get($collection, $index); + } + + /** + * {@inheritDoc} + */ + public function slice(PersistentCollection $collection, int $offset, int|null $length = null): array + { + return $this->persister->slice($collection, $offset, $length); + } + + /** + * {@inheritDoc} + */ + public function loadCriteria(PersistentCollection $collection, Criteria $criteria): array + { + return $this->persister->loadCriteria($collection, $criteria); + } +} diff --git a/vendor/doctrine/orm/src/Cache/Persister/Collection/CachedCollectionPersister.php b/vendor/doctrine/orm/src/Cache/Persister/Collection/CachedCollectionPersister.php new file mode 100644 index 0000000..6b10c80 --- /dev/null +++ b/vendor/doctrine/orm/src/Cache/Persister/Collection/CachedCollectionPersister.php @@ -0,0 +1,36 @@ +queuedCache['update'])) { + foreach ($this->queuedCache['update'] as $item) { + $this->storeCollectionCache($item['key'], $item['list']); + } + } + + if (isset($this->queuedCache['delete'])) { + foreach ($this->queuedCache['delete'] as $key) { + $this->region->evict($key); + } + } + + $this->queuedCache = []; + } + + public function afterTransactionRolledBack(): void + { + $this->queuedCache = []; + } + + public function delete(PersistentCollection $collection): void + { + $ownerId = $this->uow->getEntityIdentifier($collection->getOwner()); + $key = new CollectionCacheKey($this->sourceEntity->rootEntityName, $this->association->fieldName, $ownerId); + + $this->persister->delete($collection); + + $this->queuedCache['delete'][spl_object_id($collection)] = $key; + } + + public function update(PersistentCollection $collection): void + { + $isInitialized = $collection->isInitialized(); + $isDirty = $collection->isDirty(); + + if (! $isInitialized && ! $isDirty) { + return; + } + + $ownerId = $this->uow->getEntityIdentifier($collection->getOwner()); + $key = new CollectionCacheKey($this->sourceEntity->rootEntityName, $this->association->fieldName, $ownerId); + + // Invalidate non initialized collections OR ordered collection + if ($isDirty && ! $isInitialized || $this->association->isOrdered()) { + $this->persister->update($collection); + + $this->queuedCache['delete'][spl_object_id($collection)] = $key; + + return; + } + + $this->persister->update($collection); + + $this->queuedCache['update'][spl_object_id($collection)] = [ + 'key' => $key, + 'list' => $collection, + ]; + } +} diff --git a/vendor/doctrine/orm/src/Cache/Persister/Collection/ReadOnlyCachedCollectionPersister.php b/vendor/doctrine/orm/src/Cache/Persister/Collection/ReadOnlyCachedCollectionPersister.php new file mode 100644 index 0000000..96e0a4b --- /dev/null +++ b/vendor/doctrine/orm/src/Cache/Persister/Collection/ReadOnlyCachedCollectionPersister.php @@ -0,0 +1,24 @@ +isDirty() && $collection->getSnapshot()) { + throw CannotUpdateReadOnlyCollection::fromEntityAndField( + DefaultProxyClassNameResolver::getClass($collection->getOwner()), + $this->association->fieldName, + ); + } + + parent::update($collection); + } +} diff --git a/vendor/doctrine/orm/src/Cache/Persister/Collection/ReadWriteCachedCollectionPersister.php b/vendor/doctrine/orm/src/Cache/Persister/Collection/ReadWriteCachedCollectionPersister.php new file mode 100644 index 0000000..347a065 --- /dev/null +++ b/vendor/doctrine/orm/src/Cache/Persister/Collection/ReadWriteCachedCollectionPersister.php @@ -0,0 +1,103 @@ +queuedCache['update'])) { + foreach ($this->queuedCache['update'] as $item) { + $this->region->evict($item['key']); + } + } + + if (isset($this->queuedCache['delete'])) { + foreach ($this->queuedCache['delete'] as $item) { + $this->region->evict($item['key']); + } + } + + $this->queuedCache = []; + } + + public function afterTransactionRolledBack(): void + { + if (isset($this->queuedCache['update'])) { + foreach ($this->queuedCache['update'] as $item) { + $this->region->evict($item['key']); + } + } + + if (isset($this->queuedCache['delete'])) { + foreach ($this->queuedCache['delete'] as $item) { + $this->region->evict($item['key']); + } + } + + $this->queuedCache = []; + } + + public function delete(PersistentCollection $collection): void + { + $ownerId = $this->uow->getEntityIdentifier($collection->getOwner()); + $key = new CollectionCacheKey($this->sourceEntity->rootEntityName, $this->association->fieldName, $ownerId); + $lock = $this->region->lock($key); + + $this->persister->delete($collection); + + if ($lock === null) { + return; + } + + $this->queuedCache['delete'][spl_object_id($collection)] = [ + 'key' => $key, + 'lock' => $lock, + ]; + } + + public function update(PersistentCollection $collection): void + { + $isInitialized = $collection->isInitialized(); + $isDirty = $collection->isDirty(); + + if (! $isInitialized && ! $isDirty) { + return; + } + + $this->persister->update($collection); + + $ownerId = $this->uow->getEntityIdentifier($collection->getOwner()); + $key = new CollectionCacheKey($this->sourceEntity->rootEntityName, $this->association->fieldName, $ownerId); + $lock = $this->region->lock($key); + + if ($lock === null) { + return; + } + + $this->queuedCache['update'][spl_object_id($collection)] = [ + 'key' => $key, + 'lock' => $lock, + ]; + } +} 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 @@ +|null + */ + protected array|null $joinedAssociations = null; + + public function __construct( + protected EntityPersister $persister, + protected Region $region, + EntityManagerInterface $em, + protected ClassMetadata $class, + ) { + $configuration = $em->getConfiguration(); + $cacheConfig = $configuration->getSecondLevelCacheConfiguration(); + $cacheFactory = $cacheConfig->getCacheFactory(); + + $this->cache = $em->getCache(); + $this->regionName = $region->getName(); + $this->uow = $em->getUnitOfWork(); + $this->metadataFactory = $em->getMetadataFactory(); + $this->cacheLogger = $cacheConfig->getCacheLogger(); + $this->timestampRegion = $cacheFactory->getTimestampRegion(); + $this->hydrator = $cacheFactory->buildEntityHydrator($em, $class); + $this->timestampKey = new TimestampCacheKey($this->class->rootEntityName); + } + + public function addInsert(object $entity): void + { + $this->persister->addInsert($entity); + } + + /** + * {@inheritDoc} + */ + public function getInserts(): array + { + return $this->persister->getInserts(); + } + + public function getSelectSQL( + array|Criteria $criteria, + AssociationMapping|null $assoc = null, + LockMode|int|null $lockMode = null, + int|null $limit = null, + int|null $offset = null, + array|null $orderBy = null, + ): string { + return $this->persister->getSelectSQL($criteria, $assoc, $lockMode, $limit, $offset, $orderBy); + } + + public function getCountSQL(array|Criteria $criteria = []): string + { + return $this->persister->getCountSQL($criteria); + } + + public function getInsertSQL(): string + { + return $this->persister->getInsertSQL(); + } + + public function getResultSetMapping(): ResultSetMapping + { + return $this->persister->getResultSetMapping(); + } + + public function getSelectConditionStatementSQL( + string $field, + mixed $value, + AssociationMapping|null $assoc = null, + string|null $comparison = null, + ): string { + return $this->persister->getSelectConditionStatementSQL($field, $value, $assoc, $comparison); + } + + public function exists(object $entity, Criteria|null $extraConditions = null): bool + { + if ($extraConditions === null) { + $key = new EntityCacheKey($this->class->rootEntityName, $this->class->getIdentifierValues($entity)); + + if ($this->region->contains($key)) { + return true; + } + } + + return $this->persister->exists($entity, $extraConditions); + } + + public function getCacheRegion(): Region + { + return $this->region; + } + + public function getEntityHydrator(): EntityHydrator + { + return $this->hydrator; + } + + public function storeEntityCache(object $entity, EntityCacheKey $key): bool + { + $class = $this->class; + $className = DefaultProxyClassNameResolver::getClass($entity); + + if ($className !== $this->class->name) { + $class = $this->metadataFactory->getMetadataFor($className); + } + + $entry = $this->hydrator->buildCacheEntry($class, $key, $entity); + $cached = $this->region->put($key, $entry); + + if ($cached) { + $this->cacheLogger?->entityCachePut($this->regionName, $key); + } + + return $cached; + } + + private function storeJoinedAssociations(object $entity): void + { + if ($this->joinedAssociations === null) { + $associations = []; + + foreach ($this->class->associationMappings as $name => $assoc) { + if ( + isset($assoc->cache) && + ($assoc->isToOne()) && + ($assoc->fetch === ClassMetadata::FETCH_EAGER || ! $assoc->isOwningSide()) + ) { + $associations[] = $name; + } + } + + $this->joinedAssociations = $associations; + } + + foreach ($this->joinedAssociations as $name) { + $assoc = $this->class->associationMappings[$name]; + $assocEntity = $this->class->getFieldValue($entity, $name); + + if ($assocEntity === null) { + continue; + } + + $assocId = $this->uow->getEntityIdentifier($assocEntity); + $assocMetadata = $this->metadataFactory->getMetadataFor($assoc->targetEntity); + $assocKey = new EntityCacheKey($assocMetadata->rootEntityName, $assocId); + $assocPersister = $this->uow->getEntityPersister($assoc->targetEntity); + + $assocPersister->storeEntityCache($assocEntity, $assocKey); + } + } + + /** + * Generates a string of currently query + * + * @param string[]|Criteria $criteria + * @param array|null $orderBy + */ + protected function getHash( + string $query, + array|Criteria $criteria, + array|null $orderBy = null, + int|null $limit = null, + int|null $offset = null, + ): string { + [$params] = $criteria instanceof Criteria + ? $this->persister->expandCriteriaParameters($criteria) + : $this->persister->expandParameters($criteria); + + return sha1($query . serialize($params) . serialize($orderBy) . $limit . $offset); + } + + /** + * {@inheritDoc} + */ + public function expandParameters(array $criteria): array + { + return $this->persister->expandParameters($criteria); + } + + /** + * {@inheritDoc} + */ + public function expandCriteriaParameters(Criteria $criteria): array + { + return $this->persister->expandCriteriaParameters($criteria); + } + + public function getClassMetadata(): ClassMetadata + { + return $this->persister->getClassMetadata(); + } + + /** + * {@inheritDoc} + */ + public function getManyToManyCollection( + AssociationMapping $assoc, + object $sourceEntity, + int|null $offset = null, + int|null $limit = null, + ): array { + return $this->persister->getManyToManyCollection($assoc, $sourceEntity, $offset, $limit); + } + + /** + * {@inheritDoc} + */ + public function getOneToManyCollection( + AssociationMapping $assoc, + object $sourceEntity, + int|null $offset = null, + int|null $limit = null, + ): array { + return $this->persister->getOneToManyCollection($assoc, $sourceEntity, $offset, $limit); + } + + public function getOwningTable(string $fieldName): string + { + return $this->persister->getOwningTable($fieldName); + } + + public function executeInserts(): void + { + // The commit order/foreign key relationships may make it necessary that multiple calls to executeInsert() + // are performed, so collect all the new entities. + $newInserts = $this->persister->getInserts(); + + if ($newInserts) { + $this->queuedCache['insert'] = array_merge($this->queuedCache['insert'] ?? [], $newInserts); + } + + $this->persister->executeInserts(); + } + + /** + * {@inheritDoc} + */ + public function load( + array $criteria, + object|null $entity = null, + AssociationMapping|null $assoc = null, + array $hints = [], + LockMode|int|null $lockMode = null, + int|null $limit = null, + array|null $orderBy = null, + ): object|null { + if ($entity !== null || $assoc !== null || $hints !== [] || $lockMode !== null) { + return $this->persister->load($criteria, $entity, $assoc, $hints, $lockMode, $limit, $orderBy); + } + + //handle only EntityRepository#findOneBy + $query = $this->persister->getSelectSQL($criteria, null, null, $limit, null, $orderBy); + $hash = $this->getHash($query, $criteria); + $rsm = $this->getResultSetMapping(); + $queryKey = new QueryCacheKey($hash, 0, Cache::MODE_NORMAL, $this->timestampKey); + $queryCache = $this->cache->getQueryCache($this->regionName); + $result = $queryCache->get($queryKey, $rsm); + + if ($result !== null) { + $this->cacheLogger?->queryCacheHit($this->regionName, $queryKey); + + return $result[0]; + } + + $result = $this->persister->load($criteria, $entity, $assoc, $hints, $lockMode, $limit, $orderBy); + + if ($result === null) { + return null; + } + + $cached = $queryCache->put($queryKey, $rsm, [$result]); + + $this->cacheLogger?->queryCacheMiss($this->regionName, $queryKey); + + if ($cached) { + $this->cacheLogger?->queryCachePut($this->regionName, $queryKey); + } + + return $result; + } + + /** + * {@inheritDoc} + */ + public function loadAll( + array $criteria = [], + array|null $orderBy = null, + int|null $limit = null, + int|null $offset = null, + ): array { + $query = $this->persister->getSelectSQL($criteria, null, null, $limit, $offset, $orderBy); + $hash = $this->getHash($query, $criteria); + $rsm = $this->getResultSetMapping(); + $queryKey = new QueryCacheKey($hash, 0, Cache::MODE_NORMAL, $this->timestampKey); + $queryCache = $this->cache->getQueryCache($this->regionName); + $result = $queryCache->get($queryKey, $rsm); + + if ($result !== null) { + $this->cacheLogger?->queryCacheHit($this->regionName, $queryKey); + + return $result; + } + + $result = $this->persister->loadAll($criteria, $orderBy, $limit, $offset); + $cached = $queryCache->put($queryKey, $rsm, $result); + + if ($result) { + $this->cacheLogger?->queryCacheMiss($this->regionName, $queryKey); + } + + if ($cached) { + $this->cacheLogger?->queryCachePut($this->regionName, $queryKey); + } + + return $result; + } + + /** + * {@inheritDoc} + */ + public function loadById(array $identifier, object|null $entity = null): object|null + { + $cacheKey = new EntityCacheKey($this->class->rootEntityName, $identifier); + $cacheEntry = $this->region->get($cacheKey); + $class = $this->class; + + if ($cacheEntry !== null) { + if ($cacheEntry->class !== $this->class->name) { + $class = $this->metadataFactory->getMetadataFor($cacheEntry->class); + } + + $cachedEntity = $this->hydrator->loadCacheEntry($class, $cacheKey, $cacheEntry, $entity); + + if ($cachedEntity !== null) { + $this->cacheLogger?->entityCacheHit($this->regionName, $cacheKey); + + return $cachedEntity; + } + } + + $entity = $this->persister->loadById($identifier, $entity); + + if ($entity === null) { + return null; + } + + $class = $this->class; + $className = DefaultProxyClassNameResolver::getClass($entity); + + if ($className !== $this->class->name) { + $class = $this->metadataFactory->getMetadataFor($className); + } + + $cacheEntry = $this->hydrator->buildCacheEntry($class, $cacheKey, $entity); + $cached = $this->region->put($cacheKey, $cacheEntry); + + if ($cached && ($this->joinedAssociations === null || $this->joinedAssociations)) { + $this->storeJoinedAssociations($entity); + } + + if ($cached) { + $this->cacheLogger?->entityCachePut($this->regionName, $cacheKey); + } + + $this->cacheLogger?->entityCacheMiss($this->regionName, $cacheKey); + + return $entity; + } + + public function count(array|Criteria $criteria = []): int + { + return $this->persister->count($criteria); + } + + /** + * {@inheritDoc} + */ + public function loadCriteria(Criteria $criteria): array + { + $orderBy = $criteria->orderings(); + $limit = $criteria->getMaxResults(); + $offset = $criteria->getFirstResult(); + $query = $this->persister->getSelectSQL($criteria); + $hash = $this->getHash($query, $criteria, $orderBy, $limit, $offset); + $rsm = $this->getResultSetMapping(); + $queryKey = new QueryCacheKey($hash, 0, Cache::MODE_NORMAL, $this->timestampKey); + $queryCache = $this->cache->getQueryCache($this->regionName); + $cacheResult = $queryCache->get($queryKey, $rsm); + + if ($cacheResult !== null) { + $this->cacheLogger?->queryCacheHit($this->regionName, $queryKey); + + return $cacheResult; + } + + $result = $this->persister->loadCriteria($criteria); + $cached = $queryCache->put($queryKey, $rsm, $result); + + if ($result) { + $this->cacheLogger?->queryCacheMiss($this->regionName, $queryKey); + } + + if ($cached) { + $this->cacheLogger?->queryCachePut($this->regionName, $queryKey); + } + + return $result; + } + + /** + * {@inheritDoc} + */ + public function loadManyToManyCollection( + AssociationMapping $assoc, + object $sourceEntity, + PersistentCollection $collection, + ): array { + $persister = $this->uow->getCollectionPersister($assoc); + $hasCache = ($persister instanceof CachedPersister); + + if (! $hasCache) { + return $this->persister->loadManyToManyCollection($assoc, $sourceEntity, $collection); + } + + $ownerId = $this->uow->getEntityIdentifier($collection->getOwner()); + $key = $this->buildCollectionCacheKey($assoc, $ownerId); + $list = $persister->loadCollectionCache($collection, $key); + + if ($list !== null) { + $this->cacheLogger?->collectionCacheHit($persister->getCacheRegion()->getName(), $key); + + return $list; + } + + $list = $this->persister->loadManyToManyCollection($assoc, $sourceEntity, $collection); + + $persister->storeCollectionCache($key, $list); + + $this->cacheLogger?->collectionCacheMiss($persister->getCacheRegion()->getName(), $key); + + return $list; + } + + public function loadOneToManyCollection( + AssociationMapping $assoc, + object $sourceEntity, + PersistentCollection $collection, + ): mixed { + $persister = $this->uow->getCollectionPersister($assoc); + $hasCache = ($persister instanceof CachedPersister); + + if (! $hasCache) { + return $this->persister->loadOneToManyCollection($assoc, $sourceEntity, $collection); + } + + $ownerId = $this->uow->getEntityIdentifier($collection->getOwner()); + $key = $this->buildCollectionCacheKey($assoc, $ownerId); + $list = $persister->loadCollectionCache($collection, $key); + + if ($list !== null) { + $this->cacheLogger?->collectionCacheHit($persister->getCacheRegion()->getName(), $key); + + return $list; + } + + $list = $this->persister->loadOneToManyCollection($assoc, $sourceEntity, $collection); + + $persister->storeCollectionCache($key, $list); + + $this->cacheLogger?->collectionCacheMiss($persister->getCacheRegion()->getName(), $key); + + return $list; + } + + /** + * {@inheritDoc} + */ + public function loadOneToOneEntity(AssociationMapping $assoc, object $sourceEntity, array $identifier = []): object|null + { + return $this->persister->loadOneToOneEntity($assoc, $sourceEntity, $identifier); + } + + /** + * {@inheritDoc} + */ + public function lock(array $criteria, LockMode|int $lockMode): void + { + $this->persister->lock($criteria, $lockMode); + } + + /** + * {@inheritDoc} + */ + public function refresh(array $id, object $entity, LockMode|int|null $lockMode = null): void + { + $this->persister->refresh($id, $entity, $lockMode); + } + + /** @param array $ownerId */ + protected function buildCollectionCacheKey(AssociationMapping $association, array $ownerId): CollectionCacheKey + { + $metadata = $this->metadataFactory->getMetadataFor($association->sourceEntity); + assert($metadata instanceof ClassMetadata); + + return new CollectionCacheKey($metadata->rootEntityName, $association->fieldName, $ownerId); + } +} 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 @@ +queuedCache['insert'])) { + foreach ($this->queuedCache['insert'] as $entity) { + $isChanged = $this->updateCache($entity, $isChanged); + } + } + + if (isset($this->queuedCache['update'])) { + foreach ($this->queuedCache['update'] as $entity) { + $isChanged = $this->updateCache($entity, $isChanged); + } + } + + if (isset($this->queuedCache['delete'])) { + foreach ($this->queuedCache['delete'] as $key) { + $this->region->evict($key); + + $isChanged = true; + } + } + + if ($isChanged) { + $this->timestampRegion->update($this->timestampKey); + } + + $this->queuedCache = []; + } + + public function afterTransactionRolledBack(): void + { + $this->queuedCache = []; + } + + public function delete(object $entity): bool + { + $key = new EntityCacheKey($this->class->rootEntityName, $this->uow->getEntityIdentifier($entity)); + $deleted = $this->persister->delete($entity); + + if ($deleted) { + $this->region->evict($key); + } + + $this->queuedCache['delete'][] = $key; + + return $deleted; + } + + public function update(object $entity): void + { + $this->persister->update($entity); + + $this->queuedCache['update'][] = $entity; + } + + private function updateCache(object $entity, bool $isChanged): bool + { + $class = $this->metadataFactory->getMetadataFor($entity::class); + $key = new EntityCacheKey($class->rootEntityName, $this->uow->getEntityIdentifier($entity)); + $entry = $this->hydrator->buildCacheEntry($class, $key, $entity); + $cached = $this->region->put($key, $entry); + $isChanged = $isChanged || $cached; + + if ($cached) { + $this->cacheLogger?->entityCachePut($this->regionName, $key); + } + + return $isChanged; + } +} 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 @@ +queuedCache['update'])) { + foreach ($this->queuedCache['update'] as $item) { + $this->region->evict($item['key']); + + $isChanged = true; + } + } + + if (isset($this->queuedCache['delete'])) { + foreach ($this->queuedCache['delete'] as $item) { + $this->region->evict($item['key']); + + $isChanged = true; + } + } + + if ($isChanged) { + $this->timestampRegion->update($this->timestampKey); + } + + $this->queuedCache = []; + } + + public function afterTransactionRolledBack(): void + { + if (isset($this->queuedCache['update'])) { + foreach ($this->queuedCache['update'] as $item) { + $this->region->evict($item['key']); + } + } + + if (isset($this->queuedCache['delete'])) { + foreach ($this->queuedCache['delete'] as $item) { + $this->region->evict($item['key']); + } + } + + $this->queuedCache = []; + } + + public function delete(object $entity): bool + { + $key = new EntityCacheKey($this->class->rootEntityName, $this->uow->getEntityIdentifier($entity)); + $lock = $this->region->lock($key); + $deleted = $this->persister->delete($entity); + + if ($deleted) { + $this->region->evict($key); + } + + if ($lock === null) { + return $deleted; + } + + $this->queuedCache['delete'][] = [ + 'lock' => $lock, + 'key' => $key, + ]; + + return $deleted; + } + + public function update(object $entity): void + { + $key = new EntityCacheKey($this->class->rootEntityName, $this->uow->getEntityIdentifier($entity)); + $lock = $this->region->lock($key); + + $this->persister->update($entity); + + if ($lock === null) { + return; + } + + $this->queuedCache['update'][] = [ + 'lock' => $lock, + 'key' => $key, + ]; + } +} -- cgit v1.2.3