diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index 0d016ee0b..cc1e67475 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -9,6 +9,8 @@ use Symfony\Component\Config\Definition\Builder\TreeBuilder; use Symfony\Component\Config\Definition\ConfigurationInterface; use Symfony\Component\DependencyInjection\Exception\LogicException; +use function array_key_exists; +use function is_array; /** * This class contains the configuration information for the bundle @@ -687,18 +689,27 @@ private function getOrmCacheDriverNode($name) ->addDefaultsIfNotSet() ->beforeNormalization() ->ifString() - ->then(static function ($v) { + ->then(static function ($v) : array { return ['type' => $v]; }) ->end() + ->beforeNormalization() + ->ifTrue(static function ($v) : bool { + return is_array($v) && array_key_exists('cache_provider', $v); + }) + ->then(static function ($v) : array { + return ['type' => 'provider'] + $v; + }) + ->end() ->children() ->scalarNode('type')->defaultValue('array')->end() + ->scalarNode('id')->end() + ->scalarNode('pool')->end() ->scalarNode('host')->end() ->scalarNode('port')->end() ->scalarNode('database')->end() ->scalarNode('instance_class')->end() ->scalarNode('class')->end() - ->scalarNode('id')->end() ->scalarNode('namespace')->defaultNull()->end() ->scalarNode('cache_provider')->defaultNull()->end() ->end(); diff --git a/DependencyInjection/DoctrineExtension.php b/DependencyInjection/DoctrineExtension.php index 41a3b879b..edb11a1f9 100644 --- a/DependencyInjection/DoctrineExtension.php +++ b/DependencyInjection/DoctrineExtension.php @@ -13,6 +13,7 @@ use Symfony\Bridge\Doctrine\Messenger\DoctrineTransactionMiddleware; use Symfony\Bridge\Doctrine\PropertyInfo\DoctrineExtractor; use Symfony\Bridge\Doctrine\Validator\DoctrineLoader; +use Symfony\Component\Cache\DoctrineProvider; use Symfony\Component\Config\FileLocator; use Symfony\Component\DependencyInjection\Alias; use Symfony\Component\DependencyInjection\ChildDefinition; @@ -24,6 +25,8 @@ use Symfony\Component\Messenger\MessageBusInterface; use Symfony\Component\Messenger\Transport\Doctrine\DoctrineTransportFactory; use Symfony\Component\Validator\Mapping\Loader\LoaderInterface; +use function class_exists; +use function sprintf; /** * DoctrineExtension is an extension for the Doctrine DBAL and ORM library. @@ -707,10 +710,24 @@ protected function getMappingResourceExtension() */ protected function loadCacheDriver($driverName, $entityManagerName, array $driverMap, ContainerBuilder $container) { - if (! empty($driverMap['cache_provider'])) { - $aliasId = $this->getObjectManagerElementName(sprintf('%s_%s', $entityManagerName, $driverName)); - $serviceId = sprintf('doctrine_cache.providers.%s', $driverMap['cache_provider']); + $serviceId = null; + $aliasId = $this->getObjectManagerElementName(sprintf('%s_%s', $entityManagerName, $driverName)); + switch ($driverMap['type']) { + case 'service': + $serviceId = $driverMap['id']; + break; + + case 'pool': + $serviceId = $this->createPoolCacheDefinition($container, $aliasId, $driverMap['pool']); + break; + + case 'provider': + $serviceId = sprintf('doctrine_cache.providers.%s', $driverMap['cache_provider']); + break; + } + + if ($serviceId !== null) { $container->setAlias($aliasId, new Alias($serviceId, false)); return $aliasId; @@ -824,4 +841,19 @@ private function loadMessengerServices(ContainerBuilder $container) : void $transportFactoryDefinition = $container->getDefinition('messenger.transport.doctrine.factory'); $transportFactoryDefinition->addTag('messenger.transport_factory'); } + + private function createPoolCacheDefinition(ContainerBuilder $container, string $aliasId, string $poolName) : string + { + if (! class_exists(DoctrineProvider::class)) { + throw new LogicException('Using the "pool" cache type is only supported when symfony/cache is installed.'); + } + + $serviceId = sprintf('doctrine.orm.cache.pool.%s', $poolName); + + $definition = $container->register($aliasId, DoctrineProvider::class); + $definition->addArgument(new Reference($poolName)); + $definition->setPrivate(true); + + return $serviceId; + } } diff --git a/Resources/doc/configuration.rst b/Resources/doc/configuration.rst index d8e2d83a7..0387aa0b8 100644 --- a/Resources/doc/configuration.rst +++ b/Resources/doc/configuration.rst @@ -273,29 +273,32 @@ Configuration Reference some_em: query_cache_driver: type: array + id: ~ + pool: ~ host: ~ port: ~ instance_class: ~ class: ~ - id: ~ namespace: ~ cache_provider: ~ metadata_cache_driver: type: array + id: ~ + pool: ~ host: ~ port: ~ instance_class: ~ class: ~ - id: ~ namespace: ~ cache_provider: ~ result_cache_driver: type: array + id: ~ + pool: ~ host: ~ port: ~ instance_class: ~ class: ~ - id: ~ namespace: ~ cache_provider: ~ entity_listeners: @@ -323,11 +326,12 @@ Configuration Reference second_level_cache: region_cache_driver: type: array + pool: ~ + id: ~ host: ~ port: ~ instance_class: ~ class: ~ - id: ~ namespace: ~ cache_provider: ~ region_lock_lifetime: 60 @@ -341,11 +345,12 @@ Configuration Reference name: cache_driver: type: array + id: ~ + pool: ~ host: ~ port: ~ instance_class: ~ class: ~ - id: ~ namespace: ~ cache_provider: ~ lock_path: '%kernel.cache_dir%/doctrine/orm/slc/filelock' @@ -621,33 +626,36 @@ Configuration Reference @@ -682,11 +690,12 @@ Configuration Reference @@ -703,11 +712,12 @@ Configuration Reference @@ -825,8 +835,11 @@ The environment variables that doctrine is going to change in the Oracle DB sess Caching Drivers ~~~~~~~~~~~~~~~ -For the caching drivers you can specify the values ``array``, ``apc``, ``apcu``, ``memcache``, -``memcached`` or ``xcache``. +For the caching drivers you can specify the values ``array``, ``apc``, ``apcu``, +``memcache``, ``memcached``, ``redis``, ``wincache``, ``zenddata`` and +``xcache``. You can use a Symfony Cache pool by using the ``pool`` type and +creating a cache bool through the FrameworkBundle configuration. The ``service`` +type lets you define the ``ID`` of your own caching service. The following example shows an overview of the caching configurations: @@ -835,13 +848,22 @@ The following example shows an overview of the caching configurations: doctrine: orm: auto_mapping: true - metadata_cache_driver: apcu - query_cache_driver: xcache + # each caching driver type defines its own config options + metadata_cache_driver: apc + # the 'pool' type requires to define the 'pool' option and configure a cache pool using the FrameworkBundle result_cache_driver: - type: memcache - host: localhost - port: 11211 - instance_class: Memcache + type: pool + pool: doctrine.result_cache_pool + # the 'service' type requires to define the 'id' option too + query_cache_driver: + type: service + id: App\ORM\MyCacheService + + framework: + cache: + pools: + doctrine.result_cache_pool: + adapter: cache.app Mapping Configuration ~~~~~~~~~~~~~~~~~~~~~ diff --git a/Tests/DependencyInjection/DoctrineExtensionTest.php b/Tests/DependencyInjection/DoctrineExtensionTest.php index cd20392d6..f7bf28624 100644 --- a/Tests/DependencyInjection/DoctrineExtensionTest.php +++ b/Tests/DependencyInjection/DoctrineExtensionTest.php @@ -665,33 +665,88 @@ public function testMessengerIntegration() $this->assertCount(1, $middlewarePrototype->getArguments()); } - public function testCacheConfiguration() + /** + * @param array|string $cacheConfig + * + * @dataProvider cacheConfigurationProvider + */ + public function testCacheConfiguration(string $expectedAliasName, string $expectedAliasTarget, string $cacheName, $cacheConfig) : void { $container = $this->getContainer(); $extension = new DoctrineExtension(); $config = BundleConfigurationBuilder::createBuilder() - ->addBaseConnection() - ->addEntityManager([ - 'metadata_cache_driver' => ['cache_provider' => 'metadata_cache'], - 'query_cache_driver' => ['cache_provider' => 'query_cache'], - 'result_cache_driver' => ['cache_provider' => 'result_cache'], - ]) + ->addBaseConnection() + ->addEntityManager([$cacheName => $cacheConfig]) ->build(); $extension->load([$config], $container); - $this->assertTrue($container->hasAlias('doctrine.orm.default_metadata_cache')); - $alias = $container->getAlias('doctrine.orm.default_metadata_cache'); - $this->assertEquals('doctrine_cache.providers.metadata_cache', (string) $alias); + $this->assertTrue($container->hasAlias($expectedAliasName)); + $alias = $container->getAlias($expectedAliasName); + $this->assertEquals($expectedAliasTarget, (string) $alias); + } + + public static function cacheConfigurationProvider() : array + { + return [ + 'metadata_cache_provider' => [ + 'expectedAliasName' => 'doctrine.orm.default_metadata_cache', + 'expectedAliasTarget' => 'doctrine_cache.providers.metadata_cache', + 'cacheName' => 'metadata_cache_driver', + 'cacheConfig' => ['cache_provider' => 'metadata_cache'], + ], + 'query_cache_provider' => [ + 'expectedAliasName' => 'doctrine.orm.default_query_cache', + 'expectedAliasTarget' => 'doctrine_cache.providers.query_cache', + 'cacheName' => 'query_cache_driver', + 'cacheConfig' => ['cache_provider' => 'query_cache'], + ], + 'result_cache_provider' => [ + 'expectedAliasName' => 'doctrine.orm.default_result_cache', + 'expectedAliasTarget' => 'doctrine_cache.providers.result_cache', + 'cacheName' => 'result_cache_driver', + 'cacheConfig' => ['cache_provider' => 'result_cache'], + ], - $this->assertTrue($container->hasAlias('doctrine.orm.default_query_cache')); - $alias = $container->getAlias('doctrine.orm.default_query_cache'); - $this->assertEquals('doctrine_cache.providers.query_cache', (string) $alias); + 'metadata_cache_service' => [ + 'expectedAliasName' => 'doctrine.orm.default_metadata_cache', + 'expectedAliasTarget' => 'service_target_metadata', + 'cacheName' => 'metadata_cache_driver', + 'cacheConfig' => ['type' => 'service', 'id' => 'service_target_metadata'], + ], + 'query_cache_service' => [ + 'expectedAliasName' => 'doctrine.orm.default_query_cache', + 'expectedAliasTarget' => 'service_target_query', + 'cacheName' => 'query_cache_driver', + 'cacheConfig' => ['type' => 'service', 'id' => 'service_target_query'], + ], + 'result_cache_service' => [ + 'expectedAliasName' => 'doctrine.orm.default_result_cache', + 'expectedAliasTarget' => 'service_target_result', + 'cacheName' => 'result_cache_driver', + 'cacheConfig' => ['type' => 'service', 'id' => 'service_target_result'], + ], - $this->assertTrue($container->hasAlias('doctrine.orm.default_result_cache')); - $alias = $container->getAlias('doctrine.orm.default_result_cache'); - $this->assertEquals('doctrine_cache.providers.result_cache', (string) $alias); + 'metadata_cache_array' => [ + 'expectedAliasName' => 'doctrine.orm.default_metadata_cache', + 'expectedAliasTarget' => 'doctrine_cache.providers.doctrine.orm.default_metadata_cache', + 'cacheName' => 'metadata_cache_driver', + 'cacheConfig' => 'array', + ], + 'query_cache_array' => [ + 'expectedAliasName' => 'doctrine.orm.default_query_cache', + 'expectedAliasTarget' => 'doctrine_cache.providers.doctrine.orm.default_query_cache', + 'cacheName' => 'query_cache_driver', + 'cacheConfig' => 'array', + ], + 'result_cache_array' => [ + 'expectedAliasName' => 'doctrine.orm.default_result_cache', + 'expectedAliasTarget' => 'doctrine_cache.providers.doctrine.orm.default_result_cache', + 'cacheName' => 'result_cache_driver', + 'cacheConfig' => 'array', + ], + ]; } public function testShardManager() diff --git a/composer.json b/composer.json index 8ccda79fa..4e36d0df8 100644 --- a/composer.json +++ b/composer.json @@ -36,6 +36,7 @@ }, "require-dev": { "doctrine/orm": "^2.6", + "symfony/cache": "^3.4|^4.1", "symfony/yaml": "^3.4|^4.1", "symfony/validator": "^3.4|^4.1", "symfony/property-info": "^3.4|^4.1",