我希望能够从配置参数中连接服务,以便我可以在开发环境中使用Web服务客户端的模拟实现,并且我可以在prod env中使用正确的客户端。
以下是来自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?
答案 0 :(得分:3)
执行您尝试执行的操作的最佳方法是为捆绑包定义语义配置。无论如何,我认为如果不编写一些PHP代码就可以做到这一点。
这意味着您应该编写一个Configuration类和一个Dependency Injection Extension类。这是一个非常简单的过程,尽管它没有在Symfony2文档上详尽记录。我的建议是采取一些简单的捆绑(例如,我非常了解FOSUserBundle),看看他们如何定义他们的配置。
Here you can find an introduction到DIC扩展系统。
答案 1 :(得分:2)
要允许在配置中定义服务类,您将使用语义配置(如上所述)。一个例子如下:
这是一个简单的服务(服务可以是任何php类):
<?php
namespace Sample\Bundle\ServiceBundle\Service;
class Awesomeness {
public function doSomething()
{
return 'I did something';
}
}
有几种方法可以将服务连接到Symfony2服务容器中。在本例中,我们将在ServiceBundle / Resources / config中创建一个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>
请注意,我没有将标准部分添加到services.xml。这是故意的。我们将修改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']);
}
}
$ container-&gt; setParameter()方法调用将一个参数注入您的容器,然后由您的服务定义使用。
此时,您无需像往常一样使用您的服务。
如果要更改服务在配置中实例化的类,可以编辑config_dev.yml:
...
sample_service:
awesomeness_class: SomeOtherBundle/SomeOtherClass
现在您的应用程序将使用不同的类来提供此服务。
答案 2 :(得分:0)
我从来没有弄清楚如何定义动态参数(使用参数作为服务ID)。我找到的唯一方法就是使用工厂和语义配置。
基本上你应该做的是:
您可以在http://symfony.com/doc/current/components/dependency_injection/factories.html
找到有关DIC和工厂的信息它有点棘手,因为你需要工厂类,但它有效。我不确定这是唯一的方法,但仍然找不到更好的方法。
在这里,您可以找到我所做的一些小例子:https://gist.github.com/32378f4000df482a8b9b
它不是整个代码库,但您可以看到“vich_uploader.storage”服务,它使用工厂服务来实例化实际服务。 StorageFactory将根据'vich_uploader.storage_service'DIC参数返回正确的服务,该参数由bundle语义配置定义。
所有其他服务将使用“vich_uploader.storage”作为参数。