2011-11-21 43 views
2

我希望能夠通過配置參數連接服務,以便我可以在開發環境中使用Web服務客戶端的模擬實現,並且我可以使用適當的客戶在prod env。使用配置參數連接DIC中的Symfony2服務

這裏是我的services.xml中的一個片段:

<parameters> 
    ... 
    <parameter key="api_client.api_service.id">ic_domain_security.api_mock_service</parameter> 
    ... 
</parameters> 

<services> 
... 
    <service id="ic_domain_security.api_client" 
       class="%api_client.class%" 
       public="true"> 
      <tag name="monolog.logger" channel="domainApiClient"/> 
      <argument type="service" id="%api_client.api_service.id%"/> 
      <call method="setLogger"> 
       <argument type="service" id="logger" on-invalid="null"/> 
      </call> 
     </service> 

     <service id="ic_domain_security.api_restful_webservice" 
       class="IC\DomainSecurityBundle\ApiClient\ApiRestfulWebService" 
       public="false"> 
      <tag name="monolog.logger" channel="domainApiRestfulWebService"/> 
      <argument>%ic_domain_security.service_url%</argument> 
      <argument type="service" id="logger" on-invalid="null"/> 
     </service> 

     <service id="ic_domain_security.api_mock_service" 
       class="IC\DomainSecurityBundle\Tests\Mock\ApiMockService" 
       public="false"> 
      <call method="setLogger"> 
       <argument type="service" id="logger" on-invalid="null"/> 
      </call> 
     </service> 
... 
</services> 

<argument type="service" id="%api_client.api_service.id%"/>試圖定義服務通過基於參數。所以我最終試圖將api_client.api_service.id參數推送到配置文件。

不幸的是,似乎沒有可以使用的參數,我收到以下錯誤服務ID定義:

ServiceNotFoundException: The service "ic_domain_security.api_client" has a dependency on a non-existent service "%api_client.api_service.id%". 

有沒有辦法做我上面所解釋的,這樣的服務ID可以通過使用配置參數?

回答

3

要做你正在嘗試做的最好的方法是爲你的包定義一個語義配置。無論如何,我認爲你不需要編寫一些PHP代碼就可以做到這一點。

這意味着您應該編寫一個Configuration類和一個Dependency Injection Extension類。這是一個相當簡單的過程,雖然在Symfony2文檔中沒有詳盡記錄。我的建議是採取一些簡單的捆綁(例如,我非常瞭解FOSUserBundle),並瞭解他們如何定義他們的配置。

Here you can find an introduction到DIC擴展系統。

2

要允許在配置中定義服務的類,可以使用語義配置(如上所述)。一個例子如下:

下面是一個簡單的服務(服務可以是任何PHP類):

<?php 

namespace Sample\Bundle\ServiceBundle\Service; 

class Awesomeness { 
    public function doSomething() 
    { 
    return 'I did something'; 
    } 
} 

有幾種方法接線服務到服務Symfony2的容器。在這個例子中,我們將創造ServiceBundle /資源/配置一個services.xml文件(這是所有在Symfony2的文檔中描述):

<?xml version="1.0" ?> 

    <container xmlns="http://symfony.com/schema/dic/services" 
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
     xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"> 
     <services> 
       <service id="sample_service_bundle.awesomess" class="%sample_service_bundle.awesomeness.class%"> 
       </service> 
     </services> 
</container> 

注意,我並沒有標準的部分添加到中聲明。 。這是故意的。我們將修改bundle的擴展類和語義配置類,以從config.yml注入參數。

要允許在配置中定義的服務類,我們首先將配置添加到DependencyInjection /的configuration.php:

class Configuration implements ConfigurationInterface 
{ 
    /** 
    * {@inheritDoc} 
    */ 
    public function getConfigTreeBuilder() 
    { 
     $treeBuilder = new TreeBuilder(); 
     $rootNode = $treeBuilder->root('brain_glove_site'); 

     $rootNode 
       ->children() 
         ->scalarNode('awesomeness_class')->cannnotBeEmpty()->defaultValue('Sample\\Bundle\\ServiceBundle\\Service\\Awesomeness')->end() 
       ->end() 
     ; 

     return $treeBuilder; 
    } 
} 

在這裏,我們創建了一個叫做「awesomeness_class」的新配置參數,它可能是在config.yml中設置並提供一個默認值。

但是,我們仍然需要創建服務可以使用的實際參數。這是在您的軟件包將使用的擴展類中完成的。如果你的包被稱爲SampleServiceBundle,那麼你編輯類將是DependencyInjection \ SampleServiceExtension:

class SampleServiceExtension extends Extension 
{ 
    /** 
    * {@inheritDoc} 
    */ 
    public function load(array $configs, ContainerBuilder $container) 
    { 
     $configuration = new Configuration(); 
     $config = $this->processConfiguration($configuration, $configs); 

     $loader = new Loader\XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); 

     $loader->load('services.xml'); 

     $container->setParameter('sample_service_bundle.awesomeness.class', $config['awesomeness_class']); 
    } 
} 

的$容器 - >的setParameter()方法調用注入參數傳入你的容器然後將由您的服務定義中使用。

在這一點上,沒有什麼你需要做的像平常一樣使用你的服務。

如果你想改變的是,服務配置實例類,你可以編輯config_dev.yml:

... 
sample_service: 
    awesomeness_class: SomeOtherBundle/SomeOtherClass 

現在你的應用程序將使用一個不同的類此服務。

0

我從來沒有想過如何定義動態參數(使用參數作爲服務ID)。我發現得到這個工作的唯一方法是使用工廠和語義配置。

基本上,你應該做的是:

  • 使用語義配置
  • 創建一個工廠,可以返回基於該參數的正確的服務定義參數(您的工廠需要的ServiceContainer實例本身爲)
  • 定義使用工廠實例化的服務(這將爲您提供引用動態創建的對象的服務ID)
  • 使用此服務名稱是其他服務的依賴關係。

您可以發現有關DIC和這裏的工廠信息http://symfony.com/doc/current/components/dependency_injection/factories.html

它有點棘手,因爲你需要的工廠類,但它的作品。我不確定這是否是唯一的方法,但仍然沒有找到更好的方法。

在這裏你能找到什麼,我做了一些例子:https://gist.github.com/32378f4000df482a8b9b

這是不是整個代碼庫,但你可以看到「vich_uploader.storage」服務,使用工廠服務實例的實際服務。 StorageFactory將根據由捆綁語義配置定義的'vich_uploader.storage_service'DIC參數返回正確的服務。

所有其他服務將使用「vich_uploader.storage」作爲參數。