将config.yml中指定的Symfony服务注入到bundle的服务中

时间:2016-11-07 07:13:30

标签: php symfony dependency-injection bundle

我有一个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

文件首先加载。

如何将可切换/可配置服务正确地注入到捆绑服务中?

谢谢! : - )

3 个答案:

答案 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也会更好。