我有一个config.yml,我想让开发人员传递缓存服务的名称。
file_repository:
cache_service: "cache"
现在我有了捆绑配置
<?php
namespace Wolnosciowiec\FileRepositoryBundle\DependencyInjection;
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\Config\Definition\ConfigurationInterface;
/**
* @package Wolnosciowiec\FileRepositoryBundle\DependencyInjection
*/
class Configuration implements ConfigurationInterface
{
public function getConfigTreeBuilder()
{
$treeBuilder = new TreeBuilder();
$rootNode = $treeBuilder->root('file_repository');
$rootNode
->children()
->scalarNode('cache_service')
->isRequired()
->end()
->end()
;
return $treeBuilder;
}
}
我有扩展名:
<?php
namespace Wolnosciowiec\FileRepositoryBundle\DependencyInjection;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Extension\Extension;
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
/**
* @package Wolnosciowiec\FileRepositoryBundle\DependencyInjection
*/
class FileRepositoryExtension extends Extension
{
/**
* Load configuration definition from "Configuration.php"
*
* @param array $configs
* @param ContainerBuilder $container
*/
public function load(array $configs, ContainerBuilder $container)
{
$configuration = new Configuration();
$config = $this->processConfiguration($configuration, $configs);
$loader = new YamlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config'));
$loader->load('services.yml');
// inject the cache service into the Comrade Reader
$comrade = $container->getDefinition('wolnosciowiec.comrade.reader');
$comrade->addMethodCall('setCache', $container->get($config['cache_service']));
}
}
在最后几行中,我在setCache()方法中将服务(在配置中指定)注入到bundle的内部服务中。
但我得到了这个:
ContainerBuilder.php第816行中的ServiceNotFoundException: 您已请求不存在的服务“缓存”。
即使在config / services.yml中我定义了:
services:
cache:
class: Doctrine\Common\Cache\ApcuCache
文件首先加载。
如何将可切换/可配置服务正确地注入到捆绑服务中?
谢谢! : - )
答案 0 :(得分:1)
在编译器通行证而不是扩展程序中执行此操作。 Extension仅加载配置,它不会将其处理到Container Builder中。正如编译in the documentation所述,编译器通行证负责操纵服务定义。
首先,在扩展中,您必须读取配置条目并将其作为参数存储在容器中:
public function load(array $configs, ContainerBuilder $container)
{
// ...
$container->setParameter('cache_service', $config['cache_service']);
}
然后,创建您的编译器通行证并在那里配置您的服务。由于尚未实例化服务,因此您必须使用对服务的引用。从容器中检索服务的名称:
// Wolnosciowiec\DependencyInjection\CacheCompilerPass:
use Symfony\Component\DependencyInjection\Reference;
class CacheCompilerPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
// get the service name from the container
$id = $container->getParameter('cache_service');
// inject the cache service into the Comrade Reader
$comrade = $container->getDefinition('wolnosciowiec.comrade.reader');
$comrade->addMethodCall('setCache', new Reference($id)));
}
}
然后,在Bundle类中注册Compiler Pass:
// Wolnosciowiec\FileRepositoryBundle:
public function build(ContainerBuilder $container)
{
parent::build($container);
$container->addCompilerPass(new CacheCompilerPass());
}
答案 1 :(得分:1)
在构建容器时,您不能从容器中获得服务,而只能从服务定义中获得服务。您想做的是:
$ID
在实例化服务时将解析此类引用,并在必要时实例化缓存。
答案 2 :(得分:0)
我在这里找到了一条线索: Alter service (ClientManager) based on configuration inside bundle extension class
所以,最后一次妥协,编译器传递看起来像这样:
function oddAndEven(numbers){
var odd = [];
var even = [];
for(num = 0; num < numbers.length; num++){
if(numbers[num] % 2 == 0){ //Even
even.push(numbers[num]);
}else { // Odd
odd.push(numbers[num]);
}
}
console.log(odd + "is odd and " + even + " is even");
}
通过妥协我的意思是我必须从config.yml而不是服务名称传递类名。它工作得很好,但如果我能够传递服务ID也会更好。