是否可以将一些服务放入另一个容器中,该容器将缩小到特定的一组服务?还是将某些特定服务分离到某种子容器中?我问这个问题是因为我需要将一组服务注入另一个服务,而将整个容器投入服务是,我相信,是个坏主意。当然,我可以在我的服务类中为我想要注入的所有服务创建一个属性,但这是我试图避免的解决方案。
我将不胜感激,如果您需要有关该问题的更多信息,请询问。
是否可以将一些服务放入另一个容器中,该容器将缩小到特定的一组服务?还是将某些特定服务分离到某种子容器中?我问这个问题是因为我需要将一组服务注入另一个服务,而将整个容器投入服务是,我相信,是个坏主意。当然,我可以在我的服务类中为我想要注入的所有服务创建一个属性,但这是我试图避免的解决方案。
我将不胜感激,如果您需要有关该问题的更多信息,请询问。
基本上,您可以通过编写一些带有特殊名称的“标记”服务来使用 DIC。
为此,您需要将您的服务定义到一个文件中(遵循 DIC 规范)并以特定方式标记它们(在这种情况下,代码将由 Sonata Admin Bundle 获取,用于解释)
# MyBundle/Resources/config/admin.yml
services:
sonata.admin.tag:
class: YourNS\AdminBundle\Admin\BlogAdmin
tags:
- { name: sonata.admin, manager_type: orm, group: posts, label: "Blog" }
arguments:
- ~
- YourNS\AdminBundle\Entity\Course
- 'SonataAdminBundle:CRUD'
calls:
- [ setTranslationDomain, [YourNSAdminBundle]]
在这种情况下,我正在定义一个名为sonata.admin.tag
标签的服务sonata.admin
。
我可以定义十几个,所有这些都带有sonata.admin.tag
标签名称。
完成此操作后,我必须创建一个“特殊”文件(我将把它放入 bundle 的DependencyInjection
文件夹 [用于约定]),它是一个CompilerPass
文件.
什么是 CompilerPass 文件?
编译器通道让您有机会操作已在服务容器中注册的其他服务定义。[...] 编译器通道最常见的用例之一是使用标记服务(阅读有关组件中标记的更多信息“使用标记服务”部分)。
这正是您所需要的!
现在您必须搜索(到此文件中)标记为(在此特定示例中)的服务sonata.admin
class AddDependencyCallsCompilerPass implements CompilerPassInterface
{
/**
* {@inheritDoc}
*/
public function process(ContainerBuilder $container)
{
$groupDefaults = $admins = $classes = array();
$pool = $container->getDefinition('sonata.admin.pool');
foreach ($container->findTaggedServiceIds('sonata.admin') as $id => $tags) {
foreach ($tags as $attributes) {
$definition = $container->getDefinition($id);
$arguments = $definition->getArguments();
if (strlen($arguments[0]) == 0) {
$definition->replaceArgument(0, $id);
}
if (strlen($arguments[2]) == 0) {
$definition->replaceArgument(2, 'SonataAdminBundle:CRUD');
}
$this->applyConfigurationFromAttribute($definition, $attributes);
$this->applyDefaults($container, $id, $attributes);
$arguments = $definition->getArguments();
$admins[] = $id;
//other logic here
$pool->addMethodCall('setAdminClasses', array($classes));
正如您在此处看到的,我们正在搜索带有sonata.admin
( $container->findTaggedServiceIds('sonata.admin')
) 标记的服务,并将这些服务(在这种情况下,是特定于奏鸣曲管理包的)添加$pool
到ContainerBuilder
现在,我们必须将 CompilerPass 注册到我们的捆绑文件中(您在将捆绑注册到应用程序之前创建的那个)
class SonataAdminBundle extends Bundle
{
/**
* {@inheritDoc}
*/
public function build(ContainerBuilder $container)
{
$container->addCompilerPass(new AddDependencyCallsCompilerPass());
}
}
现在,您已经为这个捆绑包注册了某种服务。服务工厂更面向
Symfony2 的服务容器提供了一种强大的方法来控制对象的创建,允许您指定传递给构造函数的参数以及调用方法和设置参数。然而,有时这不会为您提供构建对象所需的一切。
或将其视为服务实例化的“入口点”。
出于性能和可测试性的原因,确实不推荐注入整个容器。
如果所有依赖项的构造函数或 getter/setter 注入不是您想要的方式...
...服务工厂是您正在寻找的。
通过这种方式,您可以构建一个包含其他服务的服务并只注入这个服务。
那将是您正在谈论的“子容器”。