title: Multiple region caches with Doctrine 2 second level cache and Symfony 3.3
body: <p>Have a distributed SF3.3 application running on multiple AWS EC2 instances with a central ElastiCache (redis) cluster. </p>
  
  <p>Each EC2 instance also runs a local Redis instance which is used for Doctrine meta and query caching.</p>
  
  <p>This application utilises Doctrines Second Level Cache, which works very well from a functional point of view. But performance is poor (900-1200ms page loads) on AWS due to the 400+ cache calls it makes to load in our Country and VatRate entities required on many of our pages. </p>
  
  <p>As these Country and VatRate entities change rarely I'd like to utilise both the local Redis instance and ElastiCache for result caching by using different regions defined in the second level cache. This should reduce the latency problem with the 400+ cache calls as when running on a single box page loads are sub 100ms. Reading the documentation this all seems to be possible, just not entirely sure how to configure it with Symfony and PHP-Cache.</p>
  
  <h1>An example of the current configuration:</h1>
  
  <p><em>app/config/config.yml</em></p>
  
  <pre><code>doctrine:
      dbal:
          # .. params
  
      orm:
          auto_generate_proxy_classes: "%kernel.debug%"
          entity_managers:
              default:
                  auto_mapping: true
                  second_level_cache:
                      enabled: true
                      region_cache_driver:
                          type: service
                          id: doctrine.orm.default_result_cache
  
  cache_adapter:
      providers:
          meta: # Used for version specific
              factory: 'cache.factory.redis'
              options:
                  host: 'localhost'
                  port: '%redis_local.port%'
                  pool_namespace: "meta_%hash%"
          result: # Used for result data
              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.meta'
              entity_managers:    [ default ]
          query:
              service_id:         'cache.provider.meta'
              entity_managers:    [ default ]
          result:
              service_id:         'cache.provider.result'
              entity_managers:    [ default ]
  </code></pre>
  
  <p><em>src/AppBundle/Entity/Country.php</em></p>
  
  <pre><code>/**
   * @ORM\Table(name = "countries")
   * @ORM\Cache(usage = "READ_ONLY")
   */
  class Country
  {
      // ...
  
      /**
       * @var VatRate
       *
       * @ORM\OneToMany(targetEntity = "VatRate", mappedBy = "country")
       * @ORM\Cache("NONSTRICT_READ_WRITE")
       */
      private $vatRates;
  
      // ...
  }
  </code></pre>
  
  <p><em>src/AppBundle/Entity/VatRate.php</em></p>
  
  <pre><code>/**
   * @ORM\Table(name = "vatRates")
   * @ORM\Cache(usage = "READ_ONLY")
   */
  class VatRate
  {
      // ...
  
      /**
       * @var Country
       *
       * @ORM\ManyToOne(targetEntity = "Country", inversedBy = "vatRates")
       * @ORM\JoinColumn(name = "countryId", referencedColumnName = "countryId")
       */
      private $country;
  
      // ...
  }
  </code></pre>
  
  <p><em>src/AppBundle/Entity/Order.php</em></p>
  
  <pre><code>/**
   * @ORM\Table(name = "orders")
   * @ORM\Cache(usage = "NONSTRICT_READ_WRITE")
   */
  class Order
  {
      // ...
  
      /**
       * @var Country
       *
       * @ORM\ManyToOne(targetEntity = "Country")
       * @ORM\JoinColumn(name = "countryId", referencedColumnName = "countryId")
       */
      private $country;
      // ...
  }
  </code></pre>
  
  <h1>Attempted Configuration</h1>
  
  <p><em>app/config/config.yml</em></p>
  
  <pre><code>doctrine:
      dbal:
          # .. params
  
      orm:
          auto_generate_proxy_classes: "%kernel.debug%"
          entity_managers:
              default:
                  auto_mapping: true
                  second_level_cache:
                      enabled: true
                      region_cache_driver: array
                      regions:
                          local:
                              type: service
                              service: "doctrine.orm.default_result_cache" # TODO: needs to be local redis 
                          remote:
                              type: service
                              service: "doctrine.orm.default_result_cache" # TODO: needs to be remote redis
  
  cache_adapter:
      providers:
          meta: # Used for version specific
              factory: 'cache.factory.redis'
              options:
                  host: 'localhost'
                  port: '%redis_local.port%'
                  pool_namespace: "meta_%hash%"
          result: # Used for result data
              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.meta'
              entity_managers:    [ default ]
          query:
              service_id:         'cache.provider.meta'
              entity_managers:    [ default ]
          result:
              service_id:         'cache.provider.result'
              entity_managers:    [ default ]
  </code></pre>
  
  <p><em>src/AppBundle/Entity/Country.php</em></p>
  
  <pre><code>/**
   * @ORM\Table(name = "countries")
   * @ORM\Cache(usage = "READ_ONLY", region = "local")
   */
  class Country
  {
      // as above
  }
  </code></pre>
  
  <p><em>src/AppBundle/Entity/VatRate.php</em></p>
  
  <pre><code>/**
   * @ORM\Table(name = "vatRates")
   * @ORM\Cache(usage = "READ_ONLY", region = "local")
   */
  class VatRate
  {
      // as above
  }
  </code></pre>
  
  <p><em>src/AppBundle/Entity/Order.php</em></p>
  
  <pre><code>/**
   * @ORM\Table(name = "orders")
   * @ORM\Cache(usage = "NONSTRICT_READ_WRITE", region = "remote")
   */
  class Order
  {
      // as above
  }
  </code></pre>
  
  <p>Which results in</p>
  
  <pre><code>Type error: Argument 1 passed to Doctrine\ORM\Cache\DefaultCacheFactory::setRegion() must be an instance of Doctrine\ORM\Cache\Region, instance of Cache\Bridge\Doctrine\DoctrineCacheBridge given,
  </code></pre>
  
  <p>Not too sure where to go from here, been working from the tests here: <a href="https://github.com/doctrine/DoctrineBundle/blob/74b408d0b6b06b9758a4d29116d42f5bfd83daf0/Tests/DependencyInjection/Fixtures/config/yml/orm_second_level_cache.yml" rel="noreferrer">https://github.com/doctrine/DoctrineBundle/blob/74b408d0b6b06b9758a4d29116d42f5bfd83daf0/Tests/DependencyInjection/Fixtures/config/yml/orm_second_level_cache.yml</a> but the lack of documentation for configuring this makes it a little more challenging! </p>