*/ private array $queryCaches = []; private QueryCache|null $defaultQueryCache = null; public function __construct( private readonly EntityManagerInterface $em, ) { $this->uow = $em->getUnitOfWork(); $this->cacheFactory = $em->getConfiguration() ->getSecondLevelCacheConfiguration() ->getCacheFactory(); } public function getEntityCacheRegion(string $className): Region|null { $metadata = $this->em->getClassMetadata($className); $persister = $this->uow->getEntityPersister($metadata->rootEntityName); if (! ($persister instanceof CachedPersister)) { return null; } return $persister->getCacheRegion(); } public function getCollectionCacheRegion(string $className, string $association): Region|null { $metadata = $this->em->getClassMetadata($className); $persister = $this->uow->getCollectionPersister($metadata->getAssociationMapping($association)); if (! ($persister instanceof CachedPersister)) { return null; } return $persister->getCacheRegion(); } public function containsEntity(string $className, mixed $identifier): bool { $metadata = $this->em->getClassMetadata($className); $persister = $this->uow->getEntityPersister($metadata->rootEntityName); if (! ($persister instanceof CachedPersister)) { return false; } return $persister->getCacheRegion()->contains($this->buildEntityCacheKey($metadata, $identifier)); } public function evictEntity(string $className, mixed $identifier): void { $metadata = $this->em->getClassMetadata($className); $persister = $this->uow->getEntityPersister($metadata->rootEntityName); if (! ($persister instanceof CachedPersister)) { return; } $persister->getCacheRegion()->evict($this->buildEntityCacheKey($metadata, $identifier)); } public function evictEntityRegion(string $className): void { $metadata = $this->em->getClassMetadata($className); $persister = $this->uow->getEntityPersister($metadata->rootEntityName); if (! ($persister instanceof CachedPersister)) { return; } $persister->getCacheRegion()->evictAll(); } public function evictEntityRegions(): void { $metadatas = $this->em->getMetadataFactory()->getAllMetadata(); foreach ($metadatas as $metadata) { $persister = $this->uow->getEntityPersister($metadata->rootEntityName); if (! ($persister instanceof CachedPersister)) { continue; } $persister->getCacheRegion()->evictAll(); } } public function containsCollection(string $className, string $association, mixed $ownerIdentifier): bool { $metadata = $this->em->getClassMetadata($className); $persister = $this->uow->getCollectionPersister($metadata->getAssociationMapping($association)); if (! ($persister instanceof CachedPersister)) { return false; } return $persister->getCacheRegion()->contains($this->buildCollectionCacheKey($metadata, $association, $ownerIdentifier)); } public function evictCollection(string $className, string $association, mixed $ownerIdentifier): void { $metadata = $this->em->getClassMetadata($className); $persister = $this->uow->getCollectionPersister($metadata->getAssociationMapping($association)); if (! ($persister instanceof CachedPersister)) { return; } $persister->getCacheRegion()->evict($this->buildCollectionCacheKey($metadata, $association, $ownerIdentifier)); } public function evictCollectionRegion(string $className, string $association): void { $metadata = $this->em->getClassMetadata($className); $persister = $this->uow->getCollectionPersister($metadata->getAssociationMapping($association)); if (! ($persister instanceof CachedPersister)) { return; } $persister->getCacheRegion()->evictAll(); } public function evictCollectionRegions(): void { $metadatas = $this->em->getMetadataFactory()->getAllMetadata(); foreach ($metadatas as $metadata) { foreach ($metadata->associationMappings as $association) { if (! $association->isToMany()) { continue; } $persister = $this->uow->getCollectionPersister($association); if (! ($persister instanceof CachedPersister)) { continue; } $persister->getCacheRegion()->evictAll(); } } } public function containsQuery(string $regionName): bool { return isset($this->queryCaches[$regionName]); } public function evictQueryRegion(string|null $regionName = null): void { if ($regionName === null && $this->defaultQueryCache !== null) { $this->defaultQueryCache->clear(); return; } if (isset($this->queryCaches[$regionName])) { $this->queryCaches[$regionName]->clear(); } } public function evictQueryRegions(): void { $this->getQueryCache()->clear(); foreach ($this->queryCaches as $queryCache) { $queryCache->clear(); } } public function getQueryCache(string|null $regionName = null): QueryCache { if ($regionName === null) { return $this->defaultQueryCache ??= $this->cacheFactory->buildQueryCache($this->em); } return $this->queryCaches[$regionName] ??= $this->cacheFactory->buildQueryCache($this->em, $regionName); } private function buildEntityCacheKey(ClassMetadata $metadata, mixed $identifier): EntityCacheKey { if (! is_array($identifier)) { $identifier = $this->toIdentifierArray($metadata, $identifier); } return new EntityCacheKey($metadata->rootEntityName, $identifier); } private function buildCollectionCacheKey( ClassMetadata $metadata, string $association, mixed $ownerIdentifier, ): CollectionCacheKey { if (! is_array($ownerIdentifier)) { $ownerIdentifier = $this->toIdentifierArray($metadata, $ownerIdentifier); } return new CollectionCacheKey($metadata->rootEntityName, $association, $ownerIdentifier); } /** @return array */ private function toIdentifierArray(ClassMetadata $metadata, mixed $identifier): array { if (is_object($identifier)) { $class = DefaultProxyClassNameResolver::getClass($identifier); if ($this->em->getMetadataFactory()->hasMetadataFor($class)) { $identifier = $this->uow->getSingleIdentifierValue($identifier) ?? throw ORMInvalidArgumentException::invalidIdentifierBindingEntity($class); } } return [$metadata->identifier[0] => $identifier]; } }