我在捆绑包扩展中定义了一些配置:
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));
}
}
}
}
然后在MyService
中,我有:
public function addElement($name, $class_name) {
$this->elements[$name] = new $class_name();
}
所有这些元素都实现了MyInterface
,一切都很好,直到我有了对其他服务或参数有一些依赖性的新元素。这些新类可以定义为从DI中受益的服务。但现在我需要重写MyExtension
和MyService
以满足新的要求。
如何从以这种方式调用的setter注入中的容器获取服务?
我找到了一个解决方案。我可以测试我的$class
变量:
- 如果它是POPO的类名,那么只需在setter注入中使用它的构造函数,就像我已经做过的那样
- 如果它是服务的名称,我可以通过将
$class
封装在Symfony'Component'DependencyInjection'Reference
对象中来向我的setter注入提供服务对象
在MyExtension
中,我需要下一行:
$service_definition->addMethodCall('addElement', array($name, new Reference($class)));
在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
}
}
但是,如果你没有很多POPO,你可以将所有对象注册为服务,正如@Marino Di Clemente所提到的,你可以使用标记来获得所有可以为你做这项工作的服务。
在这种情况下,您必须将所有对象定义为服务,并在其配置中添加适当的标记。然后,您需要在扩展中获得它,并将其传递给setter注入。代码将与我的类似,但您需要获得标记的服务,而不是解析配置:
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))
);
}
}