2016-11-07 101 views
0

我有一個config.yml,我想讓開發人員傳遞緩存服務的名稱。將config.yml中指定的Symfony服務注入到包的服務

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'])); 
    } 
} 

在上線I有一個服務(在配置中指定)的注射轉換爲setCache()方法中的包的內部服務。

但我發現了這一點:

在ServiceNotFoundException的行ContainerBuilder.php 816: 您已請求不存在的服務「緩存」。

即使在配置/ services.yml我已經定義:

services: 
    cache: 
     class: Doctrine\Common\Cache\ApcuCache 

和文件首先加載。

我該如何將可切換/可配置服務正確注入到該服務的服務中?

謝謝! :-)

回答

0

在編譯通行證而不是擴展中執行。該擴展只加載配置,它不會將其處理到容器生成器中。正如編號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))); 
    } 
} 

然後,註冊您的編譯器傳遞到自己的包類:

// Wolnosciowiec\FileRepositoryBundle: 

public function build(ContainerBuilder $container) 
{ 
    parent::build($container); 

    $container->addCompilerPass(new CacheCompilerPass()); 
} 
+0

[Symfony \ Component \ DependencyInjection \ Exception \ RuntimeException] 如果參數是對象或資源,則無法轉儲服務容器。 這也不會工作:) –

+0

對不起,忘了你必須在編譯器通過使用引用,而不是實際的服務。編輯我的答案。現在您將可以使用服務名稱而不是其類別。 –

0

我發現了一個線索在這裏: Alter service (ClientManager) based on configuration inside bundle extension class

所以,最後一個妥協的編譯器通過看起來像這樣:

<?php 

namespace Wolnosciowiec\FileRepositoryBundle\DependencyInjection\Compiler; 

use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; 
use Symfony\Component\DependencyInjection\ContainerBuilder; 
use Symfony\Component\DependencyInjection\Definition; 
use Symfony\Component\Serializer\Serializer; 

class CacheCompilerPass implements CompilerPassInterface 
{ 
    public function process(ContainerBuilder $container) 
    { 
     $config = $container->getExtensionConfig('file_repository'); 

     // inject the cache service into the Comrade Reader 
     $comrade = $container->getDefinition('wolnosciowiec.comrade.reader'); 

     $comrade->addMethodCall('setUrl',  [$config[0]['url']]); 
     $comrade->addMethodCall('setToken',  [$config[0]['token']]); 

     // serializer 
     $serializer = new Definition(Serializer::class, []); 
     $serializer->setPublic(false); 
     $container->setDefinition('wolnosciowiec.file_repository.serializer', $serializer); 
     $comrade->addMethodCall('setSerializer', array($serializer)); 

     // cache 
     $cache = new Definition($config[0]['cache_class'], []); 
     $cache->setPublic(false); 
     $container->setDefinition('wolnosciowiec.file_repository.cache', $cache); 
     $comrade->addMethodCall('setCache', array($cache)); 
    } 
} 

妥協我的意思是我必須從config.yml而不是服務名稱傳遞類名稱。它工作的很好,但如果我能夠通過服務ID也會更好。