From 728a3b83af7bed961d688cdda65fff1add49c321 Mon Sep 17 00:00:00 2001 From: Gocha Ossinkine Date: Thu, 20 Aug 2020 21:28:51 +0500 Subject: [PATCH 1/2] Add PhpArrayAdapter to cache metadata We decorate the existing metadata cache of each entity manager with a PHP Array Cache when not in debug mode. That cache is warmed up by getting all the metadata for all entities. --- CacheWarmer/DoctrineMetadataCacheWarmer.php | 37 +++++++++++++++++ DependencyInjection/DoctrineExtension.php | 40 +++++++++++++++++++ .../DoctrineExtensionTest.php | 20 ++++++++-- 3 files changed, 94 insertions(+), 3 deletions(-) create mode 100644 CacheWarmer/DoctrineMetadataCacheWarmer.php diff --git a/CacheWarmer/DoctrineMetadataCacheWarmer.php b/CacheWarmer/DoctrineMetadataCacheWarmer.php new file mode 100644 index 000000000..d6ae59d42 --- /dev/null +++ b/CacheWarmer/DoctrineMetadataCacheWarmer.php @@ -0,0 +1,37 @@ +entityManager = $entityManager; + + parent::__construct($phpArrayFile); + } + + /** + * @param string $cacheDir + * + * @return bool false if there is nothing to warm-up + */ + protected function doWarmUp($cacheDir, ArrayAdapter $arrayAdapter) + { + $metadataFactory = new ClassMetadataFactory(); + $metadataFactory->setEntityManager($this->entityManager); + $metadataFactory->setCacheDriver(new DoctrineProvider($arrayAdapter)); + $metadataFactory->getAllMetadata(); + + return true; + } +} diff --git a/DependencyInjection/DoctrineExtension.php b/DependencyInjection/DoctrineExtension.php index 07afe8f6a..8e9e77871 100644 --- a/DependencyInjection/DoctrineExtension.php +++ b/DependencyInjection/DoctrineExtension.php @@ -2,6 +2,7 @@ namespace Doctrine\Bundle\DoctrineBundle\DependencyInjection; +use Doctrine\Bundle\DoctrineBundle\CacheWarmer\DoctrineMetadataCacheWarmer; use Doctrine\Bundle\DoctrineBundle\Dbal\ManagerRegistryAwareConnectionProvider; use Doctrine\Bundle\DoctrineBundle\Dbal\RegexSchemaAssetFilter; use Doctrine\Bundle\DoctrineBundle\DependencyInjection\Compiler\ServiceRepositoryCompilerPass; @@ -21,6 +22,8 @@ use Symfony\Bridge\Doctrine\SchemaListener\PdoCacheAdapterDoctrineSchemaSubscriber; use Symfony\Bridge\Doctrine\Validator\DoctrineLoader; use Symfony\Component\Cache\Adapter\ArrayAdapter; +use Symfony\Component\Cache\Adapter\DoctrineAdapter; +use Symfony\Component\Cache\Adapter\PhpArrayAdapter; use Symfony\Component\Cache\DoctrineProvider; use Symfony\Component\Config\FileLocator; use Symfony\Component\DependencyInjection\Alias; @@ -814,6 +817,11 @@ protected function loadOrmCacheDrivers(array $entityManager, ContainerBuilder $c $this->loadCacheDriver('metadata_cache', $entityManager['name'], $entityManager['metadata_cache_driver'], $container); $this->loadCacheDriver('result_cache', $entityManager['name'], $entityManager['result_cache_driver'], $container); $this->loadCacheDriver('query_cache', $entityManager['name'], $entityManager['query_cache_driver'], $container); + + if (! $container->getParameter('kernel.debug')) { + $this->registerMetadataPhpArrayCacheWarmer($entityManager['name'], $container); + $this->registerMetadataPhpArrayCache($entityManager['name'], $container); + } } /** @@ -927,4 +935,36 @@ private function createArrayAdapterCachePool(ContainerBuilder $container, string return $id; } + + private function registerMetadataPhpArrayCacheWarmer(string $entityManagerName, ContainerBuilder $container): void + { + $cacheWarmerDefinition = $container->register(sprintf('doctrine.orm.%s_metadata_cache.php_array_warmer', $entityManagerName), DoctrineMetadataCacheWarmer::class); + $cacheWarmerDefinition->setArguments([ + new Reference(sprintf('doctrine.orm.%s_entity_manager', $entityManagerName)), + $this->getPhpArrayFile($entityManagerName), + ]); + $cacheWarmerDefinition->addTag('kernel.cache_warmer'); + } + + private function registerMetadataPhpArrayCache(string $entityManagerName, ContainerBuilder $container): void + { + $aliasId = sprintf('doctrine.orm.%s_metadata_cache', $entityManagerName); + $serviceId = (string) $container->getAlias($aliasId); + + $phpArrayAdapterDefinition = new Definition(PhpArrayAdapter::class, [ + $this->getPhpArrayFile($entityManagerName), + new Definition(DoctrineAdapter::class, [new Reference($serviceId)]), + ]); + + $serviceId .= '.php_array'; + + $doctrineCacheDefinition = $container->register($serviceId, DoctrineProvider::class); + $doctrineCacheDefinition->addArgument($phpArrayAdapterDefinition); + $container->setAlias($aliasId, $serviceId); + } + + private function getPhpArrayFile(string $entityManagerName): string + { + return '%kernel.cache_dir%' . sprintf('/doctrine/orm/%s_metadata.php', $entityManagerName); + } } diff --git a/Tests/DependencyInjection/DoctrineExtensionTest.php b/Tests/DependencyInjection/DoctrineExtensionTest.php index a0e568e8f..633540941 100644 --- a/Tests/DependencyInjection/DoctrineExtensionTest.php +++ b/Tests/DependencyInjection/DoctrineExtensionTest.php @@ -12,6 +12,8 @@ use PHPUnit\Framework\TestCase; use Symfony\Bridge\Doctrine\Messenger\DoctrineClearEntityManagerWorkerSubscriber; use Symfony\Component\Cache\Adapter\ArrayAdapter; +use Symfony\Component\Cache\Adapter\DoctrineAdapter; +use Symfony\Component\Cache\Adapter\PhpArrayAdapter; use Symfony\Component\Cache\DoctrineProvider; use Symfony\Component\DependencyInjection\Compiler\ResolveChildDefinitionsPass; use Symfony\Component\DependencyInjection\ContainerBuilder; @@ -347,6 +349,18 @@ public function testDependencyInjectionConfigurationDefaults(): void $definition = $container->getDefinition((string) $container->getAlias('doctrine.orm.default_metadata_cache')); $this->assertEquals(DoctrineProvider::class, $definition->getClass()); $arguments = $definition->getArguments(); + $this->assertInstanceOf(Definition::class, $arguments[0]); + $this->assertEquals(PhpArrayAdapter::class, $arguments[0]->getClass()); + $arguments = $arguments[0]->getArguments(); + $this->assertSame('%kernel.cache_dir%/doctrine/orm/default_metadata.php', $arguments[0]); + $this->assertInstanceOf(Definition::class, $arguments[1]); + $this->assertEquals(DoctrineAdapter::class, $arguments[1]->getClass()); + $arguments = $arguments[1]->getArguments(); + $this->assertInstanceOf(Reference::class, $arguments[0]); + $this->assertEquals('doctrine.orm.cache.provider.cache.doctrine.orm.default.metadata', (string) $arguments[0]); + $definition = $container->getDefinition((string) $arguments[0]); + $this->assertEquals(DoctrineProvider::class, $definition->getClass()); + $arguments = $definition->getArguments(); $this->assertInstanceOf(Reference::class, $arguments[0]); $this->assertEquals('cache.doctrine.orm.default.metadata', (string) $arguments[0]); $this->assertSame(ArrayAdapter::class, $container->getDefinition((string) $arguments[0])->getClass()); @@ -803,7 +817,7 @@ public static function cacheConfigurationProvider(): array return [ 'metadata_cache_default' => [ 'expectedAliasName' => 'doctrine.orm.default_metadata_cache', - 'expectedAliasTarget' => 'doctrine.orm.cache.provider.cache.doctrine.orm.default.metadata', + 'expectedAliasTarget' => 'doctrine.orm.cache.provider.cache.doctrine.orm.default.metadata.php_array', 'cacheName' => 'metadata_cache_driver', 'cacheConfig' => ['type' => null], ], @@ -822,7 +836,7 @@ public static function cacheConfigurationProvider(): array 'metadata_cache_pool' => [ 'expectedAliasName' => 'doctrine.orm.default_metadata_cache', - 'expectedAliasTarget' => 'doctrine.orm.cache.provider.metadata_cache_pool', + 'expectedAliasTarget' => 'doctrine.orm.cache.provider.metadata_cache_pool.php_array', 'cacheName' => 'metadata_cache_driver', 'cacheConfig' => ['type' => 'pool', 'pool' => 'metadata_cache_pool'], ], @@ -841,7 +855,7 @@ public static function cacheConfigurationProvider(): array 'metadata_cache_service' => [ 'expectedAliasName' => 'doctrine.orm.default_metadata_cache', - 'expectedAliasTarget' => 'service_target_metadata', + 'expectedAliasTarget' => 'service_target_metadata.php_array', 'cacheName' => 'metadata_cache_driver', 'cacheConfig' => ['type' => 'service', 'id' => 'service_target_metadata'], ], From 3e2946e7288df9b1a70cad1ea773dcff2dd16af3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Ostroluck=C3=BD?= Date: Sat, 31 Oct 2020 22:58:48 +0100 Subject: [PATCH 2/2] Deprecate "metadata_cache_driver" configuration key Since metadata is not supposed to be discovered at runtime, the fallback cache, which is the one configured through this key, is never supposed to be used. There is no point in configuring it. --- CacheWarmer/DoctrineMetadataCacheWarmer.php | 4 +- DependencyInjection/Configuration.php | 7 +++ DependencyInjection/DoctrineExtension.php | 54 ++++++++----------- .../DoctrineExtensionTest.php | 46 ++++++++++------ UPGRADE-2.2.md | 1 + 5 files changed, 62 insertions(+), 50 deletions(-) diff --git a/CacheWarmer/DoctrineMetadataCacheWarmer.php b/CacheWarmer/DoctrineMetadataCacheWarmer.php index d6ae59d42..81585b4ef 100644 --- a/CacheWarmer/DoctrineMetadataCacheWarmer.php +++ b/CacheWarmer/DoctrineMetadataCacheWarmer.php @@ -22,10 +22,8 @@ public function __construct(EntityManagerInterface $entityManager, string $phpAr /** * @param string $cacheDir - * - * @return bool false if there is nothing to warm-up */ - protected function doWarmUp($cacheDir, ArrayAdapter $arrayAdapter) + protected function doWarmUp($cacheDir, ArrayAdapter $arrayAdapter): bool { $metadataFactory = new ClassMetadataFactory(); $metadataFactory->setEntityManager($this->entityManager); diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index 00fd91518..f5c5c79b1 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -688,6 +688,13 @@ private function getOrmCacheDriverNode(string $name): ArrayNodeDefinition ->scalarNode('pool')->end() ->end(); + if ($name === 'metadata_cache_driver') { + $node->setDeprecated(...$this->getDeprecationMsg( + 'The "metadata_cache_driver" configuration key is deprecated. PHP Array cache is now automatically registered when %kernel.debug% is false.', + '2.2' + )); + } + return $node; } diff --git a/DependencyInjection/DoctrineExtension.php b/DependencyInjection/DoctrineExtension.php index 8e9e77871..589dadac5 100644 --- a/DependencyInjection/DoctrineExtension.php +++ b/DependencyInjection/DoctrineExtension.php @@ -818,10 +818,11 @@ protected function loadOrmCacheDrivers(array $entityManager, ContainerBuilder $c $this->loadCacheDriver('result_cache', $entityManager['name'], $entityManager['result_cache_driver'], $container); $this->loadCacheDriver('query_cache', $entityManager['name'], $entityManager['query_cache_driver'], $container); - if (! $container->getParameter('kernel.debug')) { - $this->registerMetadataPhpArrayCacheWarmer($entityManager['name'], $container); - $this->registerMetadataPhpArrayCache($entityManager['name'], $container); + if ($container->getParameter('kernel.debug')) { + return; } + + $this->registerMetadataPhpArrayCaching($entityManager['name'], $container); } /** @@ -936,35 +937,24 @@ private function createArrayAdapterCachePool(ContainerBuilder $container, string return $id; } - private function registerMetadataPhpArrayCacheWarmer(string $entityManagerName, ContainerBuilder $container): void - { - $cacheWarmerDefinition = $container->register(sprintf('doctrine.orm.%s_metadata_cache.php_array_warmer', $entityManagerName), DoctrineMetadataCacheWarmer::class); - $cacheWarmerDefinition->setArguments([ - new Reference(sprintf('doctrine.orm.%s_entity_manager', $entityManagerName)), - $this->getPhpArrayFile($entityManagerName), - ]); - $cacheWarmerDefinition->addTag('kernel.cache_warmer'); - } - - private function registerMetadataPhpArrayCache(string $entityManagerName, ContainerBuilder $container): void - { - $aliasId = sprintf('doctrine.orm.%s_metadata_cache', $entityManagerName); - $serviceId = (string) $container->getAlias($aliasId); - - $phpArrayAdapterDefinition = new Definition(PhpArrayAdapter::class, [ - $this->getPhpArrayFile($entityManagerName), - new Definition(DoctrineAdapter::class, [new Reference($serviceId)]), - ]); - - $serviceId .= '.php_array'; - - $doctrineCacheDefinition = $container->register($serviceId, DoctrineProvider::class); - $doctrineCacheDefinition->addArgument($phpArrayAdapterDefinition); - $container->setAlias($aliasId, $serviceId); - } - - private function getPhpArrayFile(string $entityManagerName): string + private function registerMetadataPhpArrayCaching(string $entityManagerName, ContainerBuilder $container): void { - return '%kernel.cache_dir%' . sprintf('/doctrine/orm/%s_metadata.php', $entityManagerName); + $metadataCacheAlias = $this->getObjectManagerElementName($entityManagerName . '_metadata_cache'); + $decoratedMetadataCacheServiceId = (string) $container->getAlias($metadataCacheAlias); + $phpArrayCacheDecoratorServiceId = $decoratedMetadataCacheServiceId . '.php_array'; + $phpArrayFile = '%kernel.cache_dir%' . sprintf('/doctrine/orm/%s_metadata.php', $entityManagerName); + + $container->register(DoctrineMetadataCacheWarmer::class) + ->setArguments([new Reference(sprintf('doctrine.orm.%s_entity_manager', $entityManagerName)), $phpArrayFile]) + ->addTag('kernel.cache_warmer'); + + $container->setAlias($metadataCacheAlias, $phpArrayCacheDecoratorServiceId); + $container->register($phpArrayCacheDecoratorServiceId, DoctrineProvider::class) + ->addArgument( + new Definition(PhpArrayAdapter::class, [ + $phpArrayFile, + new Definition(DoctrineAdapter::class, [new Reference($decoratedMetadataCacheServiceId)]), + ]) + ); } } diff --git a/Tests/DependencyInjection/DoctrineExtensionTest.php b/Tests/DependencyInjection/DoctrineExtensionTest.php index 633540941..b0ef02dd1 100644 --- a/Tests/DependencyInjection/DoctrineExtensionTest.php +++ b/Tests/DependencyInjection/DoctrineExtensionTest.php @@ -766,6 +766,9 @@ public function testMessengerIntegration(): void } } + /** + * @group legacy + */ public function testInvalidCacheConfiguration(): void { if (! interface_exists(EntityManagerInterface::class)) { @@ -812,7 +815,16 @@ public function testCacheConfiguration(string $expectedAliasName, string $expect $this->assertEquals($expectedAliasTarget, (string) $alias); } - public static function cacheConfigurationProvider(): array + /** + * @dataProvider legacyCacheConfigurationProvider + * @group legacy + */ + public function testLegacyCacheConfiguration(string $expectedAliasName, string $expectedAliasTarget, string $cacheName, array $cacheConfig): void + { + $this->testCacheConfiguration($expectedAliasName, $expectedAliasTarget, $cacheName, $cacheConfig); + } + + public static function legacyCacheConfigurationProvider(): array { return [ 'metadata_cache_default' => [ @@ -821,6 +833,24 @@ public static function cacheConfigurationProvider(): array 'cacheName' => 'metadata_cache_driver', 'cacheConfig' => ['type' => null], ], + 'metadata_cache_pool' => [ + 'expectedAliasName' => 'doctrine.orm.default_metadata_cache', + 'expectedAliasTarget' => 'doctrine.orm.cache.provider.metadata_cache_pool.php_array', + 'cacheName' => 'metadata_cache_driver', + 'cacheConfig' => ['type' => 'pool', 'pool' => 'metadata_cache_pool'], + ], + 'metadata_cache_service' => [ + 'expectedAliasName' => 'doctrine.orm.default_metadata_cache', + 'expectedAliasTarget' => 'service_target_metadata.php_array', + 'cacheName' => 'metadata_cache_driver', + 'cacheConfig' => ['type' => 'service', 'id' => 'service_target_metadata'], + ], + ]; + } + + public static function cacheConfigurationProvider(): array + { + return [ 'query_cache_default' => [ 'expectedAliasName' => 'doctrine.orm.default_query_cache', 'expectedAliasTarget' => 'doctrine.orm.cache.provider.cache.doctrine.orm.default.query', @@ -833,13 +863,6 @@ public static function cacheConfigurationProvider(): array 'cacheName' => 'result_cache_driver', 'cacheConfig' => ['type' => null], ], - - 'metadata_cache_pool' => [ - 'expectedAliasName' => 'doctrine.orm.default_metadata_cache', - 'expectedAliasTarget' => 'doctrine.orm.cache.provider.metadata_cache_pool.php_array', - 'cacheName' => 'metadata_cache_driver', - 'cacheConfig' => ['type' => 'pool', 'pool' => 'metadata_cache_pool'], - ], 'query_cache_pool' => [ 'expectedAliasName' => 'doctrine.orm.default_query_cache', 'expectedAliasTarget' => 'doctrine.orm.cache.provider.query_cache_pool', @@ -852,13 +875,6 @@ public static function cacheConfigurationProvider(): array 'cacheName' => 'result_cache_driver', 'cacheConfig' => ['type' => 'pool', 'pool' => 'result_cache_pool'], ], - - 'metadata_cache_service' => [ - 'expectedAliasName' => 'doctrine.orm.default_metadata_cache', - 'expectedAliasTarget' => 'service_target_metadata.php_array', - 'cacheName' => 'metadata_cache_driver', - 'cacheConfig' => ['type' => 'service', 'id' => 'service_target_metadata'], - ], 'query_cache_service' => [ 'expectedAliasName' => 'doctrine.orm.default_query_cache', 'expectedAliasTarget' => 'service_target_query', diff --git a/UPGRADE-2.2.md b/UPGRADE-2.2.md index caa96166d..eaf6f5eaa 100644 --- a/UPGRADE-2.2.md +++ b/UPGRADE-2.2.md @@ -13,3 +13,4 @@ Configuration * `doctrine.dbal.keep_slave`. Use `doctrine.dbal.keep_replica` Similarly, if you use XML configuration, please replace `` with ``. + * The `metadata_cache_driver` configuration key has been deprecated. PHP Array cache is now automatically registered when `%kernel.debug%` is false.