[英]How can I inject service with setter injection in my Symfony2 extension?
I defined some configuration in my bundle extension: 我在捆绑扩展中定义了一些配置:
public function load(array $configs, ContainerBuilder $container)
{
$configuration = new Configuration();
$config = $this->processConfiguration($configuration, $configs);
$loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config'));
$loader->load('services.yml');
if (!empty($config['my_config'])) {
$my_config = $config['my_config'];
if (is_array($my_config)) {
$service_definition = $container->getDefinition('my_service');
foreach ($my_config as $name => $class) {
$reflection_class = new \ReflectionClass($class);
if (!$reflection_class->implementsInterface('MyInterface')) {
throw new \Exception(
"'$class' must implement MyInterface'"
);
}
$service_definition->addMethodCall('addElement', array($name, $class));
}
}
}
}
And then in MyService
I have: 然后在
MyService
我有:
public function addElement($name, $class_name) {
$this->elements[$name] = new $class_name();
}
All these elements implement MyInterface
and all is fine until I have new elements that has some dependencies on other services or parameters. 所有这些元素都实现
MyInterface
并且在我拥有对其他服务或参数有一定依赖性的新元素之前,一切都很好。 These new classes can be defined as services to benefit from DI. 这些新类可以定义为可以从DI中受益的服务。 But now I need to rewrite
MyExtension
and MyService
to meet new requirements. 但是现在我需要重写
MyExtension
和MyService
以满足新的要求。
How can I get services from container in setter injection that is invoked this way? 如何通过以这种方式调用的setter注入从容器中获取服务?
I found a solution. 我找到了解决方案。 I can just test my
$class
variable: 我可以测试
$class
变量:
$class
in Symfony\\Component\\DependencyInjection\\Reference
object. $class
包装在Symfony\\Component\\DependencyInjection\\Reference
对象中来为setter注入提供服务对象。 In the MyExtension
I need next line: 在
MyExtension
我需要下一行:
$service_definition->addMethodCall('addElement', array($name, new Reference($class)));
and in MyService
: 并在
MyService
:
public function addElement($name, $object) {
if (class_exist($object)) {
$this->elements[$name] = new $object();
}
elseif ($object instanceof MyInterface) {
$this->elements[$name] = $object;
} else {
// throw an exception
}
}
But if you don't have a lot of POPO you can register all your objects as services and as mentioned by @Marino Di Clemente you can just use tagging for getting all the services that can do the work for you. 但是,如果您没有很多POPO,则可以将所有对象注册为服务,就像@Marino Di Clemente提到的那样,您可以使用标记来获取所有可以为您完成工作的服务。
In this case you will have to define all objects as services and add appropriate tags in its configs. 在这种情况下,您将必须将所有对象定义为服务,并在其配置中添加适当的标签。 Then you need get it in extension and pass to the setter injection.
然后,您需要扩展它并传递给setter注入。 Code will be similar as mine but instead of parsing config you will need to get tagged services:
代码将与我的相似,但是除了解析配置之外,您还需要获取带标签的服务:
public function load(array $configs, ContainerBuilder $container)
{
$configuration = new Configuration();
$config = $this->processConfiguration($configuration, $configs);
$loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config'));
$loader->load('services.yml');
$service_definition = $container->getDefinition('my_service');
$taggedServices = $container->findTaggedServiceIds(
'my_tag'
);
foreach ($taggedServices as $id => $tags) {
$service_definition->addMethodCall(
'addElement',
array(new Reference($id))
);
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.