Multiple region caches with Doctrine 2 second level cache and Symfony 3.3
After much playing around with the PHP-Cache library, it's clear from looking in the CacheBundle compiler that it will only ever support one DoctrineBridge instance from the configuration. https://github.com/php-cache/cache-bundle/blob/master/src/DependencyInjection/Compiler/DoctrineCompilerPass.php
Solution was to create my own compiler, not pretty but it seems to work.
src/AppBundle/DependencyInjection/Compiler/DoctrineCompilerPass.php
namespace AppBundle\DependencyInjection\Compiler;use Cache\Bridge\Doctrine\DoctrineCacheBridge;use Cache\CacheBundle\Factory\DoctrineBridgeFactory;use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;use Symfony\Component\DependencyInjection\ContainerBuilder;use Symfony\Component\DependencyInjection\Reference;class DoctrineCompilerPass implements CompilerPassInterface{ /** @var ContainerBuilder */ private $container; public function process(ContainerBuilder $container) { $this->container = $container; $this->enableDoctrineCache('local'); $this->enableDoctrineCache('remote'); } private function enableDoctrineCache(string $configName) { $typeConfig = [ 'entity_managers' => [ 'default' ], 'use_tagging' => true, 'service_id' => 'cache.provider.' . $configName ]; $bridgeServiceId = sprintf('cache.service.doctrine.%s.entity_managers.bridge', $configName); $this->container->register($bridgeServiceId, DoctrineCacheBridge::class) ->setFactory([DoctrineBridgeFactory::class, 'get']) ->addArgument(new Reference($typeConfig['service_id'])) ->addArgument($typeConfig) ->addArgument(['doctrine', $configName]); }}
src/AppBundle/AppBundle.php
use AppBundle\DependencyInjection\Compiler\DoctrineCompilerPass;use Symfony\Component\DependencyInjection\ContainerBuilder;use Symfony\Component\HttpKernel\Bundle\Bundle;class AppBundle extends Bundle{ public function build(ContainerBuilder $container) { parent::build($container); $container->addCompilerPass(new DoctrineCompilerPass()); }}
app/config/config.yml
doctrine: dbal: # ... params orm: auto_generate_proxy_classes: "%kernel.debug%" entity_managers: default: auto_mapping: true second_level_cache: enabled: true regions: remote: cache_driver: type: service id: cache.service.doctrine.remote.entity_managers.bridge local: cache_driver: type: service id: cache.service.doctrine.local.entity_managers.bridgecache_adapter: providers: local: factory: 'cache.factory.redis' options: host: '%redis_local.host%' port: '%redis_local.port%' pool_namespace: "local_%hash%" remote: factory: 'cache.factory.redis' options: host: '%redis_result.host%' port: '%redis_result.port%' pool_namespace: 'result'cache: doctrine: enabled: true use_tagging: true metadata: service_id: 'cache.provider.local' entity_managers: [ default ] query: service_id: 'cache.provider.local' entity_managers: [ default ]
While this seems to work to some extent, there's some inconsistencies local cache calls resulting in 500 errors when theres probably something missing in the cache. Overall think I'm trying to bend the second level cache more than it was designed to.
The error message you are getting entirely reflects the root of your issue. You are passing DoctrineCacheBridge
instances (the underlying class of doctrine.orm.default_result_cache
) when instances of the Doctrine\ORM\Cache\Region
interface expected:
second_level_cache: #... regions: local: type: service service: "region_service_not_cache_service" # Here is a Region instance expected remote: type: service service: "region_service_not_cache_service" #Here is a Region instance expected
In your former configuration the doctrine.orm.default_result_cache
cache service is set as the default cache through the region_cache_driver
setting. \Doctrine\ORM\Cache\DefaultCacheFactory
generates instances of DefaultRegion
on flight (as none was preconfigured) and feeds the default cache to them.
The latter configuration is expected to have pre-configured regions and could be fixed several ways. I suggest the next:
dbal: # .. paramsorm: #... second_level_cache: #... regions: local: type: default cache_driver: type: service id: "doctrine.orm.default_query_cache" # NOTE that this is the service id of your local cache generated by PHP-Cache Bundle remote: type: default cache_driver: type: service id: "doctrine.orm.default_result_cache" # NOTE that this is the service id of your remote cache generated by PHP-Cache Bundle
Here you tell Doctrine to create 2 DefaultRegion
regions under the local
and remote
keys and pass local_cache
and remote_cache
to them correspondingly.
And it's better to return region_cache_driver
to the former value otherwise DefaultRegion
s generated on flight will use array
cache:
second_level_cache: enabled: true region_cache_driver: type: service id: doctrine.orm.default_result_cache