From 5d0fbc47d047cf3dce2e2f8a8c8b6379427a0323 Mon Sep 17 00:00:00 2001 From: "Alexander M. Turek" Date: Sun, 2 Jan 2022 17:17:13 +0100 Subject: [PATCH] PSR-6 second level cache --- UPGRADE.md | 16 ++ docs/en/reference/second-level-cache.rst | 2 +- .../ORM/Cache/DefaultCacheFactory.php | 77 +++++----- .../Cache/Region/DefaultMultiGetRegion.php | 57 +------ .../ORM/Cache/Region/DefaultRegion.php | 145 +++++++++++++----- .../ClearCache/CollectionRegionCommand.php | 14 +- .../ClearCache/EntityRegionCommand.php | 14 +- .../Command/ClearCache/QueryRegionCommand.php | 16 +- phpstan-baseline.neon | 5 - phpstan-dbal2.neon | 3 + phpstan.neon | 3 + psalm-baseline.xml | 29 +--- psalm.xml | 11 ++ .../Tests/ORM/Cache/AbstractRegionTest.php | 15 +- .../ORM/Cache/DefaultCacheFactoryTest.php | 96 ++---------- .../ORM/Cache/DefaultRegionLegacyTest.php | 22 +++ .../Tests/ORM/Cache/DefaultRegionTest.php | 130 +++++----------- .../Tests/ORM/Cache/FileLockRegionTest.php | 2 +- .../Tests/ORM/Cache/MultiGetRegionTest.php | 8 +- .../AbstractCollectionPersisterTest.php | 2 +- .../Entity/AbstractEntityPersisterTest.php | 2 +- .../SecondLevelCacheConcurrentTest.php | 9 +- .../ORM/Functional/Ticket/DDC7969Test.php | 7 +- .../Doctrine/Tests/OrmFunctionalTestCase.php | 6 +- tests/Doctrine/Tests/OrmTestCase.php | 21 ++- 25 files changed, 304 insertions(+), 408 deletions(-) create mode 100644 tests/Doctrine/Tests/ORM/Cache/DefaultRegionLegacyTest.php diff --git a/UPGRADE.md b/UPGRADE.md index 93de8c974ab..7c3da635ebf 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -1,5 +1,21 @@ # Upgrade to 2.11 +## PSR-6-based second level cache + +The second level cache has been reworked to consume a PSR-6 cache. Using a +Doctrine Cache instance is deprecated. + +* `DefaultCacheFactory`: The constructor expects a PSR-6 cache item pool as + second argument now. +* `DefaultMultiGetRegion`: This class is deprecated in favor of `DefaultRegion`. +* `DefaultRegion`: + * The constructor expects a PSR-6 cache item pool as second argument now. + * The protected `$cache` property is deprecated. + * The properties `$name` and `$lifetime` as well as the constant + `REGION_KEY_SEPARATOR` and the method `getCacheEntryKey()` are flagged as + `@internal` now. They all will become `private` in 3.0. + * The method `getCache()` is deprecated without replacement. + ## Deprecated: `Doctrine\ORM\Mapping\Driver\PHPDriver` Use `StaticPHPDriver` instead when you want to programmatically configure diff --git a/docs/en/reference/second-level-cache.rst b/docs/en/reference/second-level-cache.rst index 4b93cbaf3b4..5798eedbb0f 100644 --- a/docs/en/reference/second-level-cache.rst +++ b/docs/en/reference/second-level-cache.rst @@ -172,7 +172,7 @@ To enable the second-level-cache, you should provide a cache factory. cache = $cache; + if ($cacheItemPool instanceof LegacyCache) { + Deprecation::trigger( + 'doctrine/orm', + 'https://github.com/doctrine/orm/pull/9322', + 'Passing an instance of %s to %s is deprecated, pass a %s instead.', + get_debug_type($cacheItemPool), + __METHOD__, + CacheItemPoolInterface::class + ); + + $this->cacheItemPool = CacheAdapter::wrap($cacheItemPool); + } elseif (! $cacheItemPool instanceof CacheItemPoolInterface) { + throw new TypeError(sprintf( + '%s: Parameter #2 is expected to be an instance of %s, got %s.', + __METHOD__, + CacheItemPoolInterface::class, + get_debug_type($cacheItemPool) + )); + } else { + $this->cacheItemPool = $cacheItemPool; + } + $this->regionsConfig = $cacheConfig; } @@ -183,13 +209,9 @@ public function getRegion(array $cache) return $this->regions[$cache['region']]; } - $name = $cache['region']; - $cacheAdapter = $this->createRegionCache($name); - $lifetime = $this->regionsConfig->getLifetime($cache['region']); - - $region = $cacheAdapter instanceof MultiGetCache - ? new DefaultMultiGetRegion($name, $cacheAdapter, $lifetime) - : new DefaultRegion($name, $cacheAdapter, $lifetime); + $name = $cache['region']; + $lifetime = $this->regionsConfig->getLifetime($cache['region']); + $region = new DefaultRegion($name, $this->cacheItemPool, $lifetime); if ($cache['usage'] === ClassMetadata::CACHE_USAGE_READ_WRITE) { if ( @@ -209,25 +231,6 @@ public function getRegion(array $cache) return $this->regions[$cache['region']] = $region; } - private function createRegionCache(string $name): CacheAdapter - { - $cacheAdapter = clone $this->cache; - - if (! $cacheAdapter instanceof CacheProvider) { - return $cacheAdapter; - } - - $namespace = $cacheAdapter->getNamespace(); - - if ($namespace !== '') { - $namespace .= ':'; - } - - $cacheAdapter->setNamespace($namespace . $name); - - return $cacheAdapter; - } - /** * {@inheritdoc} */ @@ -237,7 +240,7 @@ public function getTimestampRegion() $name = Cache::DEFAULT_TIMESTAMP_REGION_NAME; $lifetime = $this->regionsConfig->getLifetime($name); - $this->timestampRegion = new UpdateTimestampCache($name, clone $this->cache, $lifetime); + $this->timestampRegion = new UpdateTimestampCache($name, $this->cacheItemPool, $lifetime); } return $this->timestampRegion; @@ -246,8 +249,8 @@ public function getTimestampRegion() /** * {@inheritdoc} */ - public function createCache(EntityManagerInterface $em) + public function createCache(EntityManagerInterface $entityManager) { - return new DefaultCache($em); + return new DefaultCache($entityManager); } } diff --git a/lib/Doctrine/ORM/Cache/Region/DefaultMultiGetRegion.php b/lib/Doctrine/ORM/Cache/Region/DefaultMultiGetRegion.php index 236b6985ca2..8fe5c7a9130 100644 --- a/lib/Doctrine/ORM/Cache/Region/DefaultMultiGetRegion.php +++ b/lib/Doctrine/ORM/Cache/Region/DefaultMultiGetRegion.php @@ -4,64 +4,11 @@ namespace Doctrine\ORM\Cache\Region; -use Doctrine\Common\Cache\Cache; -use Doctrine\Common\Cache\MultiGetCache; -use Doctrine\ORM\Cache\CacheEntry; -use Doctrine\ORM\Cache\CollectionCacheEntry; - -use function assert; -use function count; - /** * A cache region that enables the retrieval of multiple elements with one call + * + * @deprecated Use {@link DefaultRegion} instead. */ class DefaultMultiGetRegion extends DefaultRegion { - /** - * Note that the multiple type is due to doctrine/cache not integrating the MultiGetCache interface - * in its signature due to BC in 1.x - * - * @var MultiGetCache|Cache - */ - protected $cache; - - /** - * {@inheritDoc} - * - * @param MultiGetCache $cache - */ - public function __construct($name, MultiGetCache $cache, $lifetime = 0) - { - assert($cache instanceof Cache); - parent::__construct($name, $cache, $lifetime); - } - - /** - * {@inheritdoc} - */ - public function getMultiple(CollectionCacheEntry $collection) - { - $keysToRetrieve = []; - - foreach ($collection->identifiers as $index => $key) { - $keysToRetrieve[$index] = $this->getCacheEntryKey($key); - } - - $items = $this->cache->fetchMultiple($keysToRetrieve); - if (count($items) !== count($keysToRetrieve)) { - return null; - } - - $returnableItems = []; - - foreach ($keysToRetrieve as $index => $key) { - if (! $items[$key] instanceof CacheEntry) { - return null; - } - - $returnableItems[$index] = $items[$key]; - } - - return $returnableItems; - } } diff --git a/lib/Doctrine/ORM/Cache/Region/DefaultRegion.php b/lib/Doctrine/ORM/Cache/Region/DefaultRegion.php index 1d075c85e92..a33d825b90a 100644 --- a/lib/Doctrine/ORM/Cache/Region/DefaultRegion.php +++ b/lib/Doctrine/ORM/Cache/Region/DefaultRegion.php @@ -4,44 +4,94 @@ namespace Doctrine\ORM\Cache\Region; -use BadMethodCallException; -use Doctrine\Common\Cache\Cache as CacheAdapter; +use Closure; +use Doctrine\Common\Cache\Cache as LegacyCache; use Doctrine\Common\Cache\CacheProvider; -use Doctrine\Common\Cache\ClearableCache; +use Doctrine\Common\Cache\Psr6\CacheAdapter; +use Doctrine\Common\Cache\Psr6\DoctrineProvider; +use Doctrine\Deprecations\Deprecation; use Doctrine\ORM\Cache\CacheEntry; use Doctrine\ORM\Cache\CacheKey; use Doctrine\ORM\Cache\CollectionCacheEntry; use Doctrine\ORM\Cache\Lock; use Doctrine\ORM\Cache\Region; - -use function get_class; +use Psr\Cache\CacheItemInterface; +use Psr\Cache\CacheItemPoolInterface; +use Traversable; +use TypeError; + +use function array_map; +use function get_debug_type; +use function iterator_to_array; use function sprintf; +use function strtr; /** * The simplest cache region compatible with all doctrine-cache drivers. */ class DefaultRegion implements Region { + /** + * @internal since 2.11, this constant will be private in 3.0. + */ public const REGION_KEY_SEPARATOR = '_'; + private const REGION_PREFIX = 'DC2_REGION_'; - /** @var CacheAdapter */ + /** + * @deprecated since 2.11, this property will be removed in 3.0. + * + * @var LegacyCache + */ protected $cache; - /** @var string */ + /** + * @internal since 2.11, this property will be private in 3.0. + * + * @var string + */ protected $name; - /** @var int */ + /** + * @internal since 2.11, this property will be private in 3.0. + * + * @var int + */ protected $lifetime = 0; + /** @var CacheItemPoolInterface */ + private $cacheItemPool; + /** - * @param string $name - * @param int $lifetime + * @param CacheItemPoolInterface $cacheItemPool */ - public function __construct($name, CacheAdapter $cache, $lifetime = 0) + public function __construct(string $name, $cacheItemPool, int $lifetime = 0) { - $this->cache = $cache; - $this->name = (string) $name; - $this->lifetime = (int) $lifetime; + if ($cacheItemPool instanceof LegacyCache) { + Deprecation::trigger( + 'doctrine/orm', + 'https://github.com/doctrine/orm/pull/9322', + 'Passing an instance of %s to %s is deprecated, pass a %s instead.', + get_debug_type($cacheItemPool), + __METHOD__, + CacheItemPoolInterface::class + ); + + $this->cache = $cacheItemPool; + $this->cacheItemPool = CacheAdapter::wrap($cacheItemPool); + } elseif (! $cacheItemPool instanceof CacheItemPoolInterface) { + throw new TypeError(sprintf( + '%s: Parameter #2 is expected to be an instance of %s, got %s.', + __METHOD__, + CacheItemPoolInterface::class, + get_debug_type($cacheItemPool) + )); + } else { + $this->cache = DoctrineProvider::wrap($cacheItemPool); + $this->cacheItemPool = $cacheItemPool; + } + + $this->name = $name; + $this->lifetime = $lifetime; } /** @@ -53,6 +103,8 @@ public function getName() } /** + * @deprecated + * * @return CacheProvider */ public function getCache() @@ -65,7 +117,7 @@ public function getCache() */ public function contains(CacheKey $key) { - return $this->cache->contains($this->getCacheEntryKey($key)); + return $this->cacheItemPool->hasItem($this->getCacheEntryKey($key)); } /** @@ -73,7 +125,8 @@ public function contains(CacheKey $key) */ public function get(CacheKey $key) { - $entry = $this->cache->fetch($this->getCacheEntryKey($key)); + $item = $this->cacheItemPool->getItem($this->getCacheEntryKey($key)); + $entry = $item->isHit() ? $item->get() : null; if (! $entry instanceof CacheEntry) { return null; @@ -87,30 +140,33 @@ public function get(CacheKey $key) */ public function getMultiple(CollectionCacheEntry $collection) { - $result = []; + $keys = array_map( + Closure::fromCallable([$this, 'getCacheEntryKey']), + $collection->identifiers + ); + /** @var iterable $items */ + $items = $this->cacheItemPool->getItems($keys); + if ($items instanceof Traversable) { + $items = iterator_to_array($items); + } - foreach ($collection->identifiers as $key) { - $entryKey = $this->getCacheEntryKey($key); - $entryValue = $this->cache->fetch($entryKey); + $result = []; + foreach ($keys as $arrayKey => $cacheKey) { + if (! isset($items[$cacheKey]) || ! $items[$cacheKey]->isHit()) { + return null; + } - if (! $entryValue instanceof CacheEntry) { + $entry = $items[$cacheKey]->get(); + if (! $entry instanceof CacheEntry) { return null; } - $result[] = $entryValue; + $result[$arrayKey] = $entry; } return $result; } - /** - * @return string - */ - protected function getCacheEntryKey(CacheKey $key) - { - return $this->name . self::REGION_KEY_SEPARATOR . $key->hash; - } - /** * {@inheritdoc} * @@ -118,7 +174,15 @@ protected function getCacheEntryKey(CacheKey $key) */ public function put(CacheKey $key, CacheEntry $entry, ?Lock $lock = null) { - return $this->cache->save($this->getCacheEntryKey($key), $entry, $this->lifetime); + $item = $this->cacheItemPool + ->getItem($this->getCacheEntryKey($key)) + ->set($entry); + + if ($this->lifetime > 0) { + $item->expiresAfter($this->lifetime); + } + + return $this->cacheItemPool->save($item); } /** @@ -128,7 +192,7 @@ public function put(CacheKey $key, CacheEntry $entry, ?Lock $lock = null) */ public function evict(CacheKey $key) { - return $this->cache->delete($this->getCacheEntryKey($key)); + return $this->cacheItemPool->deleteItem($this->getCacheEntryKey($key)); } /** @@ -138,13 +202,16 @@ public function evict(CacheKey $key) */ public function evictAll() { - if (! $this->cache instanceof ClearableCache) { - throw new BadMethodCallException(sprintf( - 'Clearing all cache entries is not supported by the supplied cache adapter of type %s', - get_class($this->cache) - )); - } + return $this->cacheItemPool->clear(self::REGION_PREFIX . $this->name); + } - return $this->cache->deleteAll(); + /** + * @internal since 2.11, this method will be private in 3.0. + * + * @return string + */ + protected function getCacheEntryKey(CacheKey $key) + { + return self::REGION_PREFIX . $this->name . self::REGION_KEY_SEPARATOR . strtr($key->hash, '{}()/\@:', '________'); } } diff --git a/lib/Doctrine/ORM/Tools/Console/Command/ClearCache/CollectionRegionCommand.php b/lib/Doctrine/ORM/Tools/Console/Command/ClearCache/CollectionRegionCommand.php index 2548c3df207..b31c3bec2e6 100644 --- a/lib/Doctrine/ORM/Tools/Console/Command/ClearCache/CollectionRegionCommand.php +++ b/lib/Doctrine/ORM/Tools/Console/Command/ClearCache/CollectionRegionCommand.php @@ -5,7 +5,6 @@ namespace Doctrine\ORM\Tools\Console\Command\ClearCache; use Doctrine\ORM\Cache; -use Doctrine\ORM\Cache\Region\DefaultRegion; use Doctrine\ORM\Tools\Console\Command\AbstractEntityManagerCommand; use InvalidArgumentException; use Symfony\Component\Console\Input\InputArgument; @@ -14,7 +13,6 @@ use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Style\SymfonyStyle; -use function get_debug_type; use function sprintf; /** @@ -86,16 +84,8 @@ protected function execute(InputInterface $input, OutputInterface $output) } if ($input->getOption('flush')) { - $collectionRegion = $cache->getCollectionCacheRegion($ownerClass, $assoc); - - if (! $collectionRegion instanceof DefaultRegion) { - throw new InvalidArgumentException(sprintf( - 'The option "--flush" expects a "Doctrine\ORM\Cache\Region\DefaultRegion", but got "%s".', - get_debug_type($collectionRegion) - )); - } - - $collectionRegion->getCache()->flushAll(); + $cache->getCollectionCacheRegion($ownerClass, $assoc) + ->evictAll(); $ui->comment( sprintf( diff --git a/lib/Doctrine/ORM/Tools/Console/Command/ClearCache/EntityRegionCommand.php b/lib/Doctrine/ORM/Tools/Console/Command/ClearCache/EntityRegionCommand.php index 779666a6f60..1a689b37c89 100644 --- a/lib/Doctrine/ORM/Tools/Console/Command/ClearCache/EntityRegionCommand.php +++ b/lib/Doctrine/ORM/Tools/Console/Command/ClearCache/EntityRegionCommand.php @@ -5,7 +5,6 @@ namespace Doctrine\ORM\Tools\Console\Command\ClearCache; use Doctrine\ORM\Cache; -use Doctrine\ORM\Cache\Region\DefaultRegion; use Doctrine\ORM\Tools\Console\Command\AbstractEntityManagerCommand; use InvalidArgumentException; use Symfony\Component\Console\Input\InputArgument; @@ -14,7 +13,6 @@ use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Style\SymfonyStyle; -use function get_debug_type; use function sprintf; /** @@ -84,16 +82,8 @@ protected function execute(InputInterface $input, OutputInterface $output) } if ($input->getOption('flush')) { - $entityRegion = $cache->getEntityCacheRegion($entityClass); - - if (! $entityRegion instanceof DefaultRegion) { - throw new InvalidArgumentException(sprintf( - 'The option "--flush" expects a "Doctrine\ORM\Cache\Region\DefaultRegion", but got "%s".', - get_debug_type($entityRegion) - )); - } - - $entityRegion->getCache()->flushAll(); + $cache->getEntityCacheRegion($entityClass) + ->evictAll(); $ui->comment(sprintf('Flushing cache provider configured for entity named "%s"', $entityClass)); diff --git a/lib/Doctrine/ORM/Tools/Console/Command/ClearCache/QueryRegionCommand.php b/lib/Doctrine/ORM/Tools/Console/Command/ClearCache/QueryRegionCommand.php index c5800953268..8b665760316 100644 --- a/lib/Doctrine/ORM/Tools/Console/Command/ClearCache/QueryRegionCommand.php +++ b/lib/Doctrine/ORM/Tools/Console/Command/ClearCache/QueryRegionCommand.php @@ -5,7 +5,6 @@ namespace Doctrine\ORM\Tools\Console\Command\ClearCache; use Doctrine\ORM\Cache; -use Doctrine\ORM\Cache\Region\DefaultRegion; use Doctrine\ORM\Tools\Console\Command\AbstractEntityManagerCommand; use InvalidArgumentException; use Symfony\Component\Console\Input\InputArgument; @@ -14,7 +13,6 @@ use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Style\SymfonyStyle; -use function get_debug_type; use function sprintf; /** @@ -82,17 +80,9 @@ protected function execute(InputInterface $input, OutputInterface $output) } if ($input->getOption('flush')) { - $queryCache = $cache->getQueryCache($name); - $queryRegion = $queryCache->getRegion(); - - if (! $queryRegion instanceof DefaultRegion) { - throw new InvalidArgumentException(sprintf( - 'The option "--flush" expects a "Doctrine\ORM\Cache\Region\DefaultRegion", but got "%s".', - get_debug_type($queryRegion) - )); - } - - $queryRegion->getCache()->flushAll(); + $cache->getQueryCache($name) + ->getRegion() + ->evictAll(); $ui->comment( sprintf( diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 3f4cc263037..b44627ae8a9 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -95,11 +95,6 @@ parameters: count: 1 path: lib/Doctrine/ORM/Cache/Persister/Entity/ReadWriteCachedEntityPersister.php - - - message: "#^PHPDoc type Doctrine\\\\Common\\\\Cache\\\\Cache\\|Doctrine\\\\Common\\\\Cache\\\\MultiGetCache of property Doctrine\\\\ORM\\\\Cache\\\\Region\\\\DefaultMultiGetRegion\\:\\:\\$cache is not covariant with PHPDoc type Doctrine\\\\Common\\\\Cache\\\\Cache of overridden property Doctrine\\\\ORM\\\\Cache\\\\Region\\\\DefaultRegion\\:\\:\\$cache\\.$#" - count: 1 - path: lib/Doctrine/ORM/Cache/Region/DefaultMultiGetRegion.php - - message: "#^Method Doctrine\\\\ORM\\\\Cache\\\\Region\\\\DefaultRegion\\:\\:getCache\\(\\) should return Doctrine\\\\Common\\\\Cache\\\\CacheProvider but returns Doctrine\\\\Common\\\\Cache\\\\Cache\\.$#" count: 1 diff --git a/phpstan-dbal2.neon b/phpstan-dbal2.neon index 58fa8cd10a9..baee22e56e8 100644 --- a/phpstan-dbal2.neon +++ b/phpstan-dbal2.neon @@ -41,3 +41,6 @@ parameters: message: "#^Parameter \\#3 \\$length of method Doctrine\\\\DBAL\\\\Platforms\\\\AbstractPlatform\\:\\:getSubstringExpression\\(\\) expects int\\|null, string\\|null given\\.$#" count: 1 path: lib/Doctrine/ORM/Query/AST/Functions/SubstringFunction.php + + # Symfony cache supports passing a key prefix to the clear method. + - '/^Method Psr\\Cache\\CacheItemPoolInterface\:\:clear\(\) invoked with 1 parameter, 0 required\.$/' diff --git a/phpstan.neon b/phpstan.neon index 67a10eea343..6572a340e8d 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -38,3 +38,6 @@ parameters: message: '/^Call to an undefined method Doctrine\\Common\\Cache\\Cache::deleteAll\(\)\.$/' count: 1 path: lib/Doctrine/ORM/Tools/Console/Command/ClearCache/ResultCommand.php + + # Symfony cache supports passing a key prefix to the clear method. + - '/^Method Psr\\Cache\\CacheItemPoolInterface\:\:clear\(\) invoked with 1 parameter, 0 required\.$/' diff --git a/psalm-baseline.xml b/psalm-baseline.xml index 455936d88ff..e42cc6ea448 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -78,9 +78,6 @@ $this->fileLockRegionDirectory - - $em - (string) $fileLockRegionDirectory @@ -283,22 +280,6 @@ lock - - - MultiGetCache - MultiGetCache|Cache - - - $lifetime - $name - - - $cache - - - fetchMultiple - - $this->cache @@ -306,10 +287,6 @@ CacheProvider - - (int) $lifetime - (string) $name - @@ -3011,11 +2988,17 @@ configure + + evictAll + configure + + evictAll + diff --git a/psalm.xml b/psalm.xml index 75039c541c7..57dabceddeb 100644 --- a/psalm.xml +++ b/psalm.xml @@ -48,6 +48,11 @@ + + + + + @@ -103,6 +108,12 @@ + + + + + + diff --git a/tests/Doctrine/Tests/ORM/Cache/AbstractRegionTest.php b/tests/Doctrine/Tests/ORM/Cache/AbstractRegionTest.php index 142eac693d7..c9858700c35 100644 --- a/tests/Doctrine/Tests/ORM/Cache/AbstractRegionTest.php +++ b/tests/Doctrine/Tests/ORM/Cache/AbstractRegionTest.php @@ -4,12 +4,13 @@ namespace Doctrine\Tests\ORM\Cache; -use Doctrine\Common\Cache\Cache; -use Doctrine\Common\Cache\Psr6\DoctrineProvider; +use Doctrine\ORM\Cache\CacheEntry; +use Doctrine\ORM\Cache\CacheKey; use Doctrine\ORM\Cache\Region; use Doctrine\Tests\Mocks\CacheEntryMock; use Doctrine\Tests\Mocks\CacheKeyMock; use Doctrine\Tests\OrmFunctionalTestCase; +use Psr\Cache\CacheItemPoolInterface; use Symfony\Component\Cache\Adapter\ArrayAdapter; /** @@ -20,15 +21,15 @@ abstract class AbstractRegionTest extends OrmFunctionalTestCase /** @var Region */ protected $region; - /** @var Cache */ - protected $cache; + /** @var CacheItemPoolInterface */ + protected $cacheItemPool; protected function setUp(): void { parent::setUp(); - $this->cache = DoctrineProvider::wrap(new ArrayAdapter()); - $this->region = $this->createRegion(); + $this->cacheItemPool = new ArrayAdapter(); + $this->region = $this->createRegion(); } abstract protected function createRegion(): Region; @@ -45,7 +46,7 @@ public static function dataProviderCacheValues(): array /** * @dataProvider dataProviderCacheValues */ - public function testPutGetContainsEvict($key, $value): void + public function testPutGetContainsEvict(CacheKey $key, CacheEntry $value): void { self::assertFalse($this->region->contains($key)); diff --git a/tests/Doctrine/Tests/ORM/Cache/DefaultCacheFactoryTest.php b/tests/Doctrine/Tests/ORM/Cache/DefaultCacheFactoryTest.php index 88f3fa10205..9ccd8a1d45e 100644 --- a/tests/Doctrine/Tests/ORM/Cache/DefaultCacheFactoryTest.php +++ b/tests/Doctrine/Tests/ORM/Cache/DefaultCacheFactoryTest.php @@ -4,8 +4,6 @@ namespace Doctrine\Tests\ORM\Cache; -use Doctrine\Common\Cache\Cache; -use Doctrine\Common\Cache\CacheProvider; use Doctrine\ORM\Cache\CacheFactory; use Doctrine\ORM\Cache\DefaultCacheFactory; use Doctrine\ORM\Cache\Persister\Collection\CachedCollectionPersister; @@ -16,7 +14,6 @@ use Doctrine\ORM\Cache\Persister\Entity\NonStrictReadWriteCachedEntityPersister; use Doctrine\ORM\Cache\Persister\Entity\ReadOnlyCachedEntityPersister; use Doctrine\ORM\Cache\Persister\Entity\ReadWriteCachedEntityPersister; -use Doctrine\ORM\Cache\Region\DefaultMultiGetRegion; use Doctrine\ORM\Cache\Region\DefaultRegion; use Doctrine\ORM\Cache\RegionsConfiguration; use Doctrine\ORM\EntityManager; @@ -32,8 +29,7 @@ use InvalidArgumentException; use LogicException; use PHPUnit\Framework\MockObject\MockObject; - -use function assert; +use Psr\Cache\CacheItemPoolInterface; /** * @group DDC-2183 @@ -56,7 +52,7 @@ protected function setUp(): void $this->em = $this->getTestEntityManager(); $this->regionsConfig = new RegionsConfiguration(); - $arguments = [$this->regionsConfig, $this->getSharedSecondLevelCacheDriverImpl()]; + $arguments = [$this->regionsConfig, $this->getSharedSecondLevelCache()]; $this->factory = $this->getMockBuilder(DefaultCacheFactory::class) ->setMethods(['getRegion']) ->setConstructorArgs($arguments) @@ -73,7 +69,7 @@ public function testBuildCachedEntityPersisterReadOnly(): void $em = $this->em; $metadata = clone $em->getClassMetadata(State::class); $persister = new BasicEntityPersister($em, $metadata); - $region = new ConcurrentRegionMock(new DefaultRegion('regionName', $this->getSharedSecondLevelCacheDriverImpl())); + $region = new ConcurrentRegionMock(new DefaultRegion('regionName', $this->getSharedSecondLevelCache())); $metadata->cache['usage'] = ClassMetadata::CACHE_USAGE_READ_ONLY; @@ -93,7 +89,7 @@ public function testBuildCachedEntityPersisterReadWrite(): void $em = $this->em; $metadata = clone $em->getClassMetadata(State::class); $persister = new BasicEntityPersister($em, $metadata); - $region = new ConcurrentRegionMock(new DefaultRegion('regionName', $this->getSharedSecondLevelCacheDriverImpl())); + $region = new ConcurrentRegionMock(new DefaultRegion('regionName', $this->getSharedSecondLevelCache())); $metadata->cache['usage'] = ClassMetadata::CACHE_USAGE_READ_WRITE; @@ -113,7 +109,7 @@ public function testBuildCachedEntityPersisterNonStrictReadWrite(): void $em = $this->em; $metadata = clone $em->getClassMetadata(State::class); $persister = new BasicEntityPersister($em, $metadata); - $region = new ConcurrentRegionMock(new DefaultRegion('regionName', $this->getSharedSecondLevelCacheDriverImpl())); + $region = new ConcurrentRegionMock(new DefaultRegion('regionName', $this->getSharedSecondLevelCache())); $metadata->cache['usage'] = ClassMetadata::CACHE_USAGE_NONSTRICT_READ_WRITE; @@ -134,7 +130,7 @@ public function testBuildCachedCollectionPersisterReadOnly(): void $metadata = $em->getClassMetadata(State::class); $mapping = $metadata->associationMappings['cities']; $persister = new OneToManyPersister($em); - $region = new ConcurrentRegionMock(new DefaultRegion('regionName', $this->getSharedSecondLevelCacheDriverImpl())); + $region = new ConcurrentRegionMock(new DefaultRegion('regionName', $this->getSharedSecondLevelCache())); $mapping['cache']['usage'] = ClassMetadata::CACHE_USAGE_READ_ONLY; @@ -155,7 +151,7 @@ public function testBuildCachedCollectionPersisterReadWrite(): void $metadata = $em->getClassMetadata(State::class); $mapping = $metadata->associationMappings['cities']; $persister = new OneToManyPersister($em); - $region = new ConcurrentRegionMock(new DefaultRegion('regionName', $this->getSharedSecondLevelCacheDriverImpl())); + $region = new ConcurrentRegionMock(new DefaultRegion('regionName', $this->getSharedSecondLevelCache())); $mapping['cache']['usage'] = ClassMetadata::CACHE_USAGE_READ_WRITE; @@ -176,7 +172,7 @@ public function testBuildCachedCollectionPersisterNonStrictReadWrite(): void $metadata = $em->getClassMetadata(State::class); $mapping = $metadata->associationMappings['cities']; $persister = new OneToManyPersister($em); - $region = new ConcurrentRegionMock(new DefaultRegion('regionName', $this->getSharedSecondLevelCacheDriverImpl())); + $region = new ConcurrentRegionMock(new DefaultRegion('regionName', $this->getSharedSecondLevelCache())); $mapping['cache']['usage'] = ClassMetadata::CACHE_USAGE_NONSTRICT_READ_WRITE; @@ -198,7 +194,7 @@ public function testInheritedEntityCacheRegion(): void $metadata2 = clone $em->getClassMetadata(AttractionLocationInfo::class); $persister1 = new BasicEntityPersister($em, $metadata1); $persister2 = new BasicEntityPersister($em, $metadata2); - $factory = new DefaultCacheFactory($this->regionsConfig, $this->getSharedSecondLevelCacheDriverImpl()); + $factory = new DefaultCacheFactory($this->regionsConfig, $this->getSharedSecondLevelCache()); $cachedPersister1 = $factory->buildCachedEntityPersister($em, $persister1, $metadata1); $cachedPersister2 = $factory->buildCachedEntityPersister($em, $persister2, $metadata2); @@ -217,7 +213,7 @@ public function testCreateNewCacheDriver(): void $metadata2 = clone $em->getClassMetadata(City::class); $persister1 = new BasicEntityPersister($em, $metadata1); $persister2 = new BasicEntityPersister($em, $metadata2); - $factory = new DefaultCacheFactory($this->regionsConfig, $this->getSharedSecondLevelCacheDriverImpl()); + $factory = new DefaultCacheFactory($this->regionsConfig, $this->getSharedSecondLevelCache()); $cachedPersister1 = $factory->buildCachedEntityPersister($em, $persister1, $metadata1); $cachedPersister2 = $factory->buildCachedEntityPersister($em, $persister2, $metadata2); @@ -260,7 +256,7 @@ public function testBuildCachedCollectionPersisterException(): void public function testInvalidFileLockRegionDirectoryException(): void { - $factory = new DefaultCacheFactory($this->regionsConfig, $this->getSharedSecondLevelCacheDriverImpl()); + $factory = new DefaultCacheFactory($this->regionsConfig, $this->getSharedSecondLevelCache()); $this->expectException(LogicException::class); $this->expectExceptionMessage( @@ -279,7 +275,7 @@ public function testInvalidFileLockRegionDirectoryException(): void public function testInvalidFileLockRegionDirectoryExceptionWithEmptyString(): void { - $factory = new DefaultCacheFactory($this->regionsConfig, $this->getSharedSecondLevelCacheDriverImpl()); + $factory = new DefaultCacheFactory($this->regionsConfig, $this->getSharedSecondLevelCache()); $factory->setFileLockRegionDirectory(''); @@ -298,57 +294,9 @@ public function testInvalidFileLockRegionDirectoryExceptionWithEmptyString(): vo ); } - public function testBuildsNewNamespacedCacheInstancePerRegionInstance(): void - { - $factory = new DefaultCacheFactory($this->regionsConfig, $this->getSharedSecondLevelCacheDriverImpl()); - - $fooRegion = $factory->getRegion( - [ - 'region' => 'foo', - 'usage' => ClassMetadata::CACHE_USAGE_READ_ONLY, - ] - ); - $barRegion = $factory->getRegion( - [ - 'region' => 'bar', - 'usage' => ClassMetadata::CACHE_USAGE_READ_ONLY, - ] - ); - - self::assertSame('foo', $fooRegion->getCache()->getNamespace()); - self::assertSame('bar', $barRegion->getCache()->getNamespace()); - } - - public function testAppendsNamespacedCacheInstancePerRegionInstanceWhenItsAlreadySet(): void - { - $cache = clone $this->getSharedSecondLevelCacheDriverImpl(); - $cache->setNamespace('testing'); - - $factory = new DefaultCacheFactory($this->regionsConfig, $cache); - - $fooRegion = $factory->getRegion( - [ - 'region' => 'foo', - 'usage' => ClassMetadata::CACHE_USAGE_READ_ONLY, - ] - ); - $barRegion = $factory->getRegion( - [ - 'region' => 'bar', - 'usage' => ClassMetadata::CACHE_USAGE_READ_ONLY, - ] - ); - - self::assertSame('testing:foo', $fooRegion->getCache()->getNamespace()); - self::assertSame('testing:bar', $barRegion->getCache()->getNamespace()); - } - public function testBuildsDefaultCacheRegionFromGenericCacheRegion(): void { - $cache = $this->createMock(Cache::class); - assert($cache instanceof Cache); - - $factory = new DefaultCacheFactory($this->regionsConfig, $cache); + $factory = new DefaultCacheFactory($this->regionsConfig, $this->createMock(CacheItemPoolInterface::class)); self::assertInstanceOf( DefaultRegion::class, @@ -360,22 +308,4 @@ public function testBuildsDefaultCacheRegionFromGenericCacheRegion(): void ) ); } - - public function testBuildsMultiGetCacheRegionFromGenericCacheRegion(): void - { - $cache = $this->getMockForAbstractClass(CacheProvider::class); - assert($cache instanceof CacheProvider); - - $factory = new DefaultCacheFactory($this->regionsConfig, $cache); - - self::assertInstanceOf( - DefaultMultiGetRegion::class, - $factory->getRegion( - [ - 'region' => 'bar', - 'usage' => ClassMetadata::CACHE_USAGE_READ_ONLY, - ] - ) - ); - } } diff --git a/tests/Doctrine/Tests/ORM/Cache/DefaultRegionLegacyTest.php b/tests/Doctrine/Tests/ORM/Cache/DefaultRegionLegacyTest.php new file mode 100644 index 00000000000..54f07d4d652 --- /dev/null +++ b/tests/Doctrine/Tests/ORM/Cache/DefaultRegionLegacyTest.php @@ -0,0 +1,22 @@ +expectDeprecationWithIdentifier('https://github.com/doctrine/orm/pull/9322'); + + return new DefaultRegion('default.region.test', DoctrineProvider::wrap($this->cacheItemPool)); + } +} diff --git a/tests/Doctrine/Tests/ORM/Cache/DefaultRegionTest.php b/tests/Doctrine/Tests/ORM/Cache/DefaultRegionTest.php index d405d0af113..d54e4d92c88 100644 --- a/tests/Doctrine/Tests/ORM/Cache/DefaultRegionTest.php +++ b/tests/Doctrine/Tests/ORM/Cache/DefaultRegionTest.php @@ -4,19 +4,15 @@ namespace Doctrine\Tests\ORM\Cache; -use BadMethodCallException; -use Doctrine\Common\Cache\Cache; use Doctrine\Common\Cache\Psr6\DoctrineProvider; use Doctrine\ORM\Cache\CollectionCacheEntry; use Doctrine\ORM\Cache\Region; use Doctrine\ORM\Cache\Region\DefaultRegion; use Doctrine\Tests\Mocks\CacheEntryMock; use Doctrine\Tests\Mocks\CacheKeyMock; -use Psr\Cache\CacheItemInterface; -use Psr\Cache\CacheItemPoolInterface; use Symfony\Component\Cache\Adapter\ArrayAdapter; -use function assert; +use function array_map; /** * @group DDC-2183 @@ -25,22 +21,21 @@ class DefaultRegionTest extends AbstractRegionTest { protected function createRegion(): Region { - return new DefaultRegion('default.region.test', $this->cache); + return new DefaultRegion('default.region.test', $this->cacheItemPool); } public function testGetters(): void { self::assertEquals('default.region.test', $this->region->getName()); - self::assertSame($this->cache, $this->region->getCache()); + self::assertSame($this->cacheItemPool, $this->region->getCache()->getPool()); } public function testSharedRegion(): void { - $cache = new SharedArrayCache(); $key = new CacheKeyMock('key'); $entry = new CacheEntryMock(['value' => 'foo']); - $region1 = new DefaultRegion('region1', DoctrineProvider::wrap($cache->createChild())); - $region2 = new DefaultRegion('region2', DoctrineProvider::wrap($cache->createChild())); + $region1 = new DefaultRegion('region1', $this->cacheItemPool); + $region2 = new DefaultRegion('region2', $this->cacheItemPool); self::assertFalse($region1->contains($key)); self::assertFalse($region2->contains($key)); @@ -69,18 +64,6 @@ public function testDoesNotModifyCacheNamespace(): void self::assertSame('foo', $cache->getNamespace()); } - public function testEvictAllWithGenericCacheThrowsUnsupportedException(): void - { - $cache = $this->createMock(Cache::class); - assert($cache instanceof Cache); - - $region = new DefaultRegion('foo', $cache); - - $this->expectException(BadMethodCallException::class); - - $region->evictAll(); - } - public function testGetMulti(): void { $key1 = new CacheKeyMock('key.1'); @@ -104,6 +87,28 @@ public function testGetMulti(): void self::assertEquals($value2, $actual[1]); } + public function testGetMultiPreservesOrderAndKeys(): void + { + $key1 = new CacheKeyMock('key.1'); + $value1 = new CacheEntryMock(['id' => 1]); + + $key2 = new CacheKeyMock('key.2'); + $value2 = new CacheEntryMock(['id' => 2]); + + $this->region->put($key1, $value1); + $this->region->put($key2, $value2); + + $actual = array_map( + 'iterator_to_array', + $this->region->getMultiple(new CollectionCacheEntry(['one' => $key1, 'two' => $key2])) + ); + + self::assertSame([ + 'one' => ['id' => 1], + 'two' => ['id' => 2], + ], $actual); + } + /** * @test * @group GH7266 @@ -111,7 +116,11 @@ public function testGetMulti(): void public function corruptedDataDoesNotLeakIntoApplicationWhenGettingSingleEntry(): void { $key1 = new CacheKeyMock('key.1'); - $this->cache->save($this->region->getName() . '_' . $key1->hash, 'a-very-invalid-value'); + $this->cacheItemPool->save( + $this->cacheItemPool + ->getItem('DC2_REGION_' . $this->region->getName() . '_' . $key1->hash) + ->set('a-very-invalid-value') + ); self::assertTrue($this->region->contains($key1)); self::assertNull($this->region->get($key1)); @@ -124,78 +133,13 @@ public function corruptedDataDoesNotLeakIntoApplicationWhenGettingSingleEntry(): public function corruptedDataDoesNotLeakIntoApplicationWhenGettingMultipleEntries(): void { $key1 = new CacheKeyMock('key.1'); - $this->cache->save($this->region->getName() . '_' . $key1->hash, 'a-very-invalid-value'); + $this->cacheItemPool->save( + $this->cacheItemPool + ->getItem('DC2_REGION_' . $this->region->getName() . '_' . $key1->hash) + ->set('a-very-invalid-value') + ); self::assertTrue($this->region->contains($key1)); self::assertNull($this->region->getMultiple(new CollectionCacheEntry([$key1]))); } } - -/** - * Cache provider that offers child cache items (sharing the same array) - * - * Declared as a different class for readability purposes and kept in this file - * to keep its monstrosity contained. - * - * @internal - */ -final class SharedArrayCache extends ArrayAdapter -{ - public function createChild(): CacheItemPoolInterface - { - return new class ($this) implements CacheItemPoolInterface { - /** @var CacheItemPoolInterface */ - private $parent; - - public function __construct(CacheItemPoolInterface $parent) - { - $this->parent = $parent; - } - - public function getItem($key): CacheItemInterface - { - return $this->parent->getItem($key); - } - - public function getItems(array $keys = []): iterable - { - return $this->parent->getItems($keys); - } - - public function hasItem($key): bool - { - return $this->parent->hasItem($key); - } - - public function clear(): bool - { - return $this->parent->clear(); - } - - public function deleteItem($key): bool - { - return $this->parent->deleteItem($key); - } - - public function deleteItems(array $keys): bool - { - return $this->parent->deleteItems($keys); - } - - public function save(CacheItemInterface $item): bool - { - return $this->parent->save($item); - } - - public function saveDeferred(CacheItemInterface $item): bool - { - return $this->parent->saveDeferred($item); - } - - public function commit(): bool - { - return $this->parent->commit(); - } - }; - } -} diff --git a/tests/Doctrine/Tests/ORM/Cache/FileLockRegionTest.php b/tests/Doctrine/Tests/ORM/Cache/FileLockRegionTest.php index 7ee858308a2..0685c46adf1 100644 --- a/tests/Doctrine/Tests/ORM/Cache/FileLockRegionTest.php +++ b/tests/Doctrine/Tests/ORM/Cache/FileLockRegionTest.php @@ -58,7 +58,7 @@ protected function createRegion(): Region { $this->directory = sys_get_temp_dir() . '/doctrine_lock_' . uniqid(); - $region = new DefaultRegion('concurren_region_test', $this->cache); + $region = new DefaultRegion('concurren_region_test', $this->cacheItemPool); return new FileLockRegion($region, $this->directory, 60); } diff --git a/tests/Doctrine/Tests/ORM/Cache/MultiGetRegionTest.php b/tests/Doctrine/Tests/ORM/Cache/MultiGetRegionTest.php index 3f10d9652c8..4ade1ec9c32 100644 --- a/tests/Doctrine/Tests/ORM/Cache/MultiGetRegionTest.php +++ b/tests/Doctrine/Tests/ORM/Cache/MultiGetRegionTest.php @@ -14,7 +14,7 @@ class MultiGetRegionTest extends AbstractRegionTest { protected function createRegion(): Region { - return new DefaultMultiGetRegion('default.region.test', $this->cache); + return new DefaultMultiGetRegion('default.region.test', $this->cacheItemPool); } public function testGetMulti(): void @@ -47,7 +47,11 @@ public function testGetMulti(): void public function corruptedDataDoesNotLeakIntoApplication(): void { $key1 = new CacheKeyMock('key.1'); - $this->cache->save($this->region->getName() . '_' . $key1->hash, 'a-very-invalid-value'); + $this->cacheItemPool->save( + $this->cacheItemPool + ->getItem('DC2_REGION_' . $this->region->getName() . '_' . $key1->hash) + ->set('a-very-invalid-value') + ); self::assertTrue($this->region->contains($key1)); self::assertNull($this->region->getMultiple(new CollectionCacheEntry([$key1]))); diff --git a/tests/Doctrine/Tests/ORM/Cache/Persister/Collection/AbstractCollectionPersisterTest.php b/tests/Doctrine/Tests/ORM/Cache/Persister/Collection/AbstractCollectionPersisterTest.php index 75bded05593..fc98917b28e 100644 --- a/tests/Doctrine/Tests/ORM/Cache/Persister/Collection/AbstractCollectionPersisterTest.php +++ b/tests/Doctrine/Tests/ORM/Cache/Persister/Collection/AbstractCollectionPersisterTest.php @@ -60,7 +60,7 @@ abstract protected function createPersister(EntityManager $em, CollectionPersist protected function setUp(): void { - $this->getSharedSecondLevelCacheDriverImpl()->flushAll(); + $this->getSharedSecondLevelCache()->clear(); $this->enableSecondLevelCache(); parent::setUp(); diff --git a/tests/Doctrine/Tests/ORM/Cache/Persister/Entity/AbstractEntityPersisterTest.php b/tests/Doctrine/Tests/ORM/Cache/Persister/Entity/AbstractEntityPersisterTest.php index b387e46826e..7cccc87e866 100644 --- a/tests/Doctrine/Tests/ORM/Cache/Persister/Entity/AbstractEntityPersisterTest.php +++ b/tests/Doctrine/Tests/ORM/Cache/Persister/Entity/AbstractEntityPersisterTest.php @@ -37,7 +37,7 @@ abstract protected function createPersister(EntityManager $em, EntityPersister $ protected function setUp(): void { - $this->getSharedSecondLevelCacheDriverImpl()->flushAll(); + $this->getSharedSecondLevelCache()->clear(); $this->enableSecondLevelCache(); parent::setUp(); diff --git a/tests/Doctrine/Tests/ORM/Functional/SecondLevelCacheConcurrentTest.php b/tests/Doctrine/Tests/ORM/Functional/SecondLevelCacheConcurrentTest.php index 53619538ecb..edab3e36446 100644 --- a/tests/Doctrine/Tests/ORM/Functional/SecondLevelCacheConcurrentTest.php +++ b/tests/Doctrine/Tests/ORM/Functional/SecondLevelCacheConcurrentTest.php @@ -4,7 +4,6 @@ namespace Doctrine\Tests\ORM\Functional; -use Doctrine\Common\Cache\Cache; use Doctrine\ORM\Cache\CollectionCacheKey; use Doctrine\ORM\Cache\DefaultCacheFactory; use Doctrine\ORM\Cache\EntityCacheKey; @@ -15,6 +14,7 @@ use Doctrine\Tests\Mocks\TimestampRegionMock; use Doctrine\Tests\Models\Cache\Country; use Doctrine\Tests\Models\Cache\State; +use Psr\Cache\CacheItemPoolInterface; use function assert; @@ -34,7 +34,7 @@ protected function setUp(): void $this->enableSecondLevelCache(); parent::setUp(); - $this->cacheFactory = new CacheFactorySecondLevelCacheConcurrentTest($this->getSharedSecondLevelCacheDriverImpl()); + $this->cacheFactory = new CacheFactorySecondLevelCacheConcurrentTest($this->getSharedSecondLevelCache()); $this->_em->getConfiguration() ->getSecondLevelCacheConfiguration() @@ -133,7 +133,10 @@ public function testBasicConcurrentCollectionReadLock(): void class CacheFactorySecondLevelCacheConcurrentTest extends DefaultCacheFactory { - public function __construct(Cache $cache) + /** @var CacheItemPoolInterface */ + private $cache; + + public function __construct(CacheItemPoolInterface $cache) { $this->cache = $cache; } diff --git a/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC7969Test.php b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC7969Test.php index 507b0a979ab..c09f5c3b5a5 100644 --- a/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC7969Test.php +++ b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC7969Test.php @@ -4,7 +4,6 @@ namespace tests\Doctrine\Tests\ORM\Functional\Ticket; -use Doctrine\ORM\Cache\Region\DefaultMultiGetRegion; use Doctrine\Tests\Models\Cache\Attraction; use Doctrine\Tests\Models\Cache\Bar; use Doctrine\Tests\ORM\Functional\SecondLevelCacheAbstractTest; @@ -21,11 +20,7 @@ public function testChildEntityRetrievedFromCache(): void $this->loadFixturesAttractions(); // Entities are already cached due to fixtures - hence flush before testing - $region = $this->cache->getEntityCacheRegion(Attraction::class); - - if ($region instanceof DefaultMultiGetRegion) { - $region->getCache()->flushAll(); - } + $this->cache->getEntityCacheRegion(Attraction::class)->evictAll(); $bar = $this->attractions[0]; assert($bar instanceof Bar); diff --git a/tests/Doctrine/Tests/OrmFunctionalTestCase.php b/tests/Doctrine/Tests/OrmFunctionalTestCase.php index 8e142e1c2f0..7fabb882a24 100644 --- a/tests/Doctrine/Tests/OrmFunctionalTestCase.php +++ b/tests/Doctrine/Tests/OrmFunctionalTestCase.php @@ -746,8 +746,10 @@ protected function getEntityManager( if ($this->isSecondLevelCacheEnabled || $enableSecondLevelCache) { $cacheConfig = new CacheConfiguration(); - $cache = $this->getSharedSecondLevelCacheDriverImpl(); - $factory = new DefaultCacheFactory($cacheConfig->getRegionsConfiguration(), $cache); + $factory = new DefaultCacheFactory( + $cacheConfig->getRegionsConfiguration(), + $this->getSharedSecondLevelCache() + ); $this->secondLevelCacheFactory = $factory; diff --git a/tests/Doctrine/Tests/OrmTestCase.php b/tests/Doctrine/Tests/OrmTestCase.php index a63afcfee59..476c30177ea 100644 --- a/tests/Doctrine/Tests/OrmTestCase.php +++ b/tests/Doctrine/Tests/OrmTestCase.php @@ -5,8 +5,6 @@ namespace Doctrine\Tests; use Doctrine\Common\Annotations; -use Doctrine\Common\Cache\Cache; -use Doctrine\Common\Cache\Psr6\DoctrineProvider; use Doctrine\Common\EventManager; use Doctrine\DBAL\Connection; use Doctrine\DBAL\DriverManager; @@ -54,8 +52,8 @@ abstract class OrmTestCase extends DoctrineTestCase /** @var StatisticsCacheLogger */ protected $secondLevelCacheLogger; - /** @var Cache|null */ - protected $secondLevelCacheDriverImpl = null; + /** @var CacheItemPoolInterface|null */ + protected $secondLevelCache = null; protected function createAnnotationDriver(array $paths = []): AnnotationDriver { @@ -102,8 +100,10 @@ protected function getTestEntityManager( if ($this->isSecondLevelCacheEnabled) { $cacheConfig = new CacheConfiguration(); - $cache = $this->getSharedSecondLevelCacheDriverImpl(); - $factory = new DefaultCacheFactory($cacheConfig->getRegionsConfiguration(), $cache); + $factory = new DefaultCacheFactory( + $cacheConfig->getRegionsConfiguration(), + $this->getSharedSecondLevelCache() + ); $this->secondLevelCacheFactory = $factory; @@ -152,12 +152,9 @@ private static function getSharedQueryCache(): CacheItemPoolInterface return self::$queryCache; } - protected function getSharedSecondLevelCacheDriverImpl(): Cache + protected function getSharedSecondLevelCache(): CacheItemPoolInterface { - if ($this->secondLevelCacheDriverImpl === null) { - $this->secondLevelCacheDriverImpl = DoctrineProvider::wrap(new ArrayAdapter()); - } - - return $this->secondLevelCacheDriverImpl; + return $this->secondLevelCache + ?? $this->secondLevelCache = new ArrayAdapter(); } }