skip to Main Content

I am trying to use different cache system on my environments. I would like to have, for example, Filesystem for dev and memcached for prod.

I am using symfony 3.3.10.

To achieve this, I would like to autowire the CacheInterface as follow:

use PsrSimpleCacheCacheInterface;

class Api {

    public function __construct(CacheInterface $cache)
    {
        $this->cache = $cache;
    }
}

Here are my configuration files:

config_dev.yml:

framework:
    cache:
        app: cache.adapter.filesystem

config_prod.yml:

framework:
    cache:
        app: cache.adapter.memcached
        ...

Here is the error I get:
enter image description here

The error disappears when the FilesystemCache is declared as a service:

services:
    SymfonyComponentCacheSimpleFilesystemCache: ~

But now I cannot have another cache system for the test environment like NullCache. In fact, I have to declare only one service inheriting from CacheInterface. It is not possible as config_test is using config_dev too.

This is the beginning of services.yml if it can help:

services:
    _defaults:
        autowire: true
        autoconfigure: true
        public: false

Any idea on how to autowire different cache system depending on the environment?

EDIT:

Here is the working configuration:

use PsrCacheCacheItemPoolInterface;

class MyApi
{
    /**
     * @var CacheItemPoolInterface
     */
    private $cache;

    public function __construct(CacheItemPoolInterface $cache)
    {
        $this->cache = $cache;
    }
}

config.yml:

framework:
    # ...
    cache:
        pools:
            app.cache.api:
                default_lifetime: 3600

services.yml:

# ...
PsrCacheCacheItemPoolInterface:
    alias: 'app.cache.api'

2

Answers


  1. In Symfony 3.3+/4 and 2017/2019 you can omit any config dependency and keep full control of the behavior with factory pattern:

    // AppBundle/Cache/CacheFactory.php
    
    namespace AppBundleCache;
    
    final class CacheFactory
    {
        public function create(string $environment): CacheInterface
        {
            if ($environment === 'prod') {
                // do this
                return new ...;
            }
    
            // default 
            return new ...;
        }
    }
    

    And services.yml of course:

    # app/config/services.yml
    services:
        PsrSimpleCacheCacheInterface:
            factory: 'AppBundleCacheCacheFactory:create'
            arguments: ['%kernel.environment%']
    

    See more about service factory in Symfony Documentation.

    You can read more about this in my Why Config Coding Sucks post.

    Login or Signup to reply.
  2. Even though factory pattern is a good option to solve this kind of problem, normally you don’t need to do that for Symfony cache system. Typehints CacheItemPoolInterface instead:

    use PsrCacheCacheItemPoolInterface;
    
    public function __construct(CacheItemPoolInterface $cache)
    

    It automatically injects the current cache.app service depending on the active environment, so Symfony does the job for you!

    Just make sure to configure the framework.cache.app for each environment config file:

    # app/config/config_test.yml
    imports:
        - { resource: config_dev.yml }
    
    framework:
        #...
        cache:
            app: cache.adapter.null
    
    services:
        cache.adapter.null:
            class: SymfonyComponentCacheAdapterNullAdapter
            arguments: [~] # small trick to avoid arguments errors on compile-time.
    

    As cache.adapter.null service isn’t available by default, you might need to define it manually.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search