Autowire symfony CacheInterface depending on environment

天涯浪子 提交于 2021-01-27 22:50:10

问题


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 Psr\SimpleCache\CacheInterface;

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:

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

services:
    Symfony\Component\Cache\Simple\FilesystemCache: ~

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 Psr\Cache\CacheItemPoolInterface;

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:

# ...
Psr\Cache\CacheItemPoolInterface:
    alias: 'app.cache.api'

回答1:


Even though factory pattern is a good option to solve this kind of problematic, normally you don't need to do that for Symfony cache system. Typehints CacheItemPoolInterface instead:

use Psr\Cache\CacheItemPoolInterface;

public function __construct(CacheItemPoolInterface $cache)

It automatically inject 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: Symfony\Component\Cache\Adapter\NullAdapter
        arguments: [~] # small trick to avoid arguments errors on compile-time.

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




回答2:


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 AppBundle\Cache;

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:
    Psr\SimpleCache\CacheInterface:
        factory: 'AppBundle\Cache\CacheFactory: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.



来源:https://stackoverflow.com/questions/46893809/autowire-symfony-cacheinterface-depending-on-environment

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!