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:
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. These new classes can be defined as services to benefit from DI. But now I need to rewrite MyExtension
and MyService
to meet new requirements.
How can I get services from container in setter injection that is invoked this way?
I found a solution. I can just test my $class
variable:
$class
in Symfony\\Component\\DependencyInjection\\Reference
object. In the MyExtension
I need next line:
$service_definition->addMethodCall('addElement', array($name, new Reference($class)));
and in 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.
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. 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))
);
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.