Multiple region caches with Doctrine 2 second level cache and Symfony 3.3 Multiple region caches with Doctrine 2 second level cache and Symfony 3.3 symfony symfony

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 DefaultRegions generated on flight will use array cache:

            second_level_cache:                enabled: true                region_cache_driver:                     type: service                    id: doctrine.orm.default_result_cache