问题
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