2016-11-07 3 views
0

У меня есть config.yml, где я хочу разрешить разработчику передавать имя службы кеша.Внесите службу Symfony, указанную в 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().

Но я получаю это:

ServiceNotFoundException в ContainerBuilder.php линии 816: Вы запросили несуществующий сервис «кэш».

Даже если в конфигурационном/services.yml я определил:

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

и файл загружает в первую очередь.

Как я мог бы правильно включить услугу переключения/конфигурирования в службу связи?

Спасибо! :-)

ответ

0

Сделайте это на переходе компилятора вместо расширения. Расширение загружает только конфигурацию, но не обрабатывает ее в Container Builder. Обязанность компилятора Passes - манипулировать определениями сервисов, как описано in the documentation.

Во-первых, в расширении, вы должны прочитать запись конфигурации и сохраните его в качестве параметра в контейнере:

public function load(array $configs, ContainerBuilder $container) 
{ 
    // ... 
    $container->setParameter('cache_service', $config['cache_service']); 
} 

Затем создать свой компилятор Pass и настроить службу там. Поскольку службы еще не созданы, вы должны использовать ссылку на свою службу. Получить имя службы из контейнера:

// 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))); 
    } 
} 

Затем зарегистрировать свой компилятор Pass в классе Bundle:

// 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 вместо имени службы. Он работает хорошо, но было бы лучше, если бы я смог передать идентификатор службы.