public function TaggedHandlersPass::process in Zircon Profile 8.0
Same name and namespace in other branches
- 8 core/lib/Drupal/Core/DependencyInjection/Compiler/TaggedHandlersPass.php \Drupal\Core\DependencyInjection\Compiler\TaggedHandlersPass::process()
Finds services tagged with 'service_collector', then finds all corresponding tagged services and adds a method call for each to the consuming/collecting service definition.
Supported 'service_collector' tag attributes:
- tag: The tag name used by handler services to collect. Defaults to the service ID of the consumer.
- call: The method name to call on the consumer service. Defaults to
'addHandler'. The called method receives two arguments:
- The handler instance as first argument.
- Optionally the handler's priority as second argument, if the method accepts a second parameter and its name is "priority". In any case, all handlers registered at compile time are sorted already.
- required: Boolean indicating if at least one handler service is required. Defaults to FALSE.
Example (YAML):
tags:
- { name: service_collector, tag: breadcrumb_builder, call: addBuilder }
Supported handler tag attributes:
- priority: An integer denoting the priority of the handler. Defaults to 0.
Example (YAML):
tags:
- { name: breadcrumb_builder, priority: 100 }
Throws
\Symfony\Component\DependencyInjection\Exception\LogicException If the method of a consumer service to be called does not type-hint an interface.
\Symfony\Component\DependencyInjection\Exception\LogicException If a tagged handler does not implement the required interface.
\Symfony\Component\DependencyInjection\Exception\LogicException If at least one tagged service is required but none are found.
Overrides CompilerPassInterface::process
File
- core/
lib/ Drupal/ Core/ DependencyInjection/ Compiler/ TaggedHandlersPass.php, line 82 - Contains \Drupal\Core\DependencyInjection\Compiler\TaggedHandlersPass.
Class
- TaggedHandlersPass
- Collects services to add/inject them into a consumer service.
Namespace
Drupal\Core\DependencyInjection\CompilerCode
public function process(ContainerBuilder $container) {
foreach ($container
->findTaggedServiceIds('service_collector') as $consumer_id => $passes) {
foreach ($passes as $pass) {
$tag = isset($pass['tag']) ? $pass['tag'] : $consumer_id;
$method_name = isset($pass['call']) ? $pass['call'] : 'addHandler';
$required = isset($pass['required']) ? $pass['required'] : FALSE;
// Determine parameters.
$consumer = $container
->getDefinition($consumer_id);
$method = new \ReflectionMethod($consumer
->getClass(), $method_name);
$params = $method
->getParameters();
$interface_pos = 0;
$id_pos = NULL;
$priority_pos = NULL;
$extra_params = [];
foreach ($params as $pos => $param) {
if ($param
->getClass()) {
$interface = $param
->getClass();
}
else {
if ($param
->getName() === 'id') {
$id_pos = $pos;
}
else {
if ($param
->getName() === 'priority') {
$priority_pos = $pos;
}
else {
$extra_params[$param
->getName()] = $pos;
}
}
}
}
// Determine the ID.
if (!isset($interface)) {
throw new LogicException(vsprintf("Service consumer '%s' class method %s::%s() has to type-hint an interface.", array(
$consumer_id,
$consumer
->getClass(),
$method_name,
)));
}
$interface = $interface
->getName();
// Find all tagged handlers.
$handlers = array();
$extra_arguments = array();
foreach ($container
->findTaggedServiceIds($tag) as $id => $attributes) {
// Validate the interface.
$handler = $container
->getDefinition($id);
if (!is_subclass_of($handler
->getClass(), $interface)) {
throw new LogicException("Service '{$id}' for consumer '{$consumer_id}' does not implement {$interface}.");
}
$handlers[$id] = isset($attributes[0]['priority']) ? $attributes[0]['priority'] : 0;
// Keep track of other tagged handlers arguments.
foreach ($extra_params as $name => $pos) {
$extra_arguments[$id][$pos] = isset($attributes[0][$name]) ? $attributes[0][$name] : $params[$pos]
->getDefaultValue();
}
}
if (empty($handlers)) {
if ($required) {
throw new LogicException(sprintf("At least one service tagged with '%s' is required.", $tag));
}
continue;
}
// Sort all handlers by priority.
arsort($handlers, SORT_NUMERIC);
// Add a method call for each handler to the consumer service
// definition.
foreach ($handlers as $id => $priority) {
$arguments = array();
$arguments[$interface_pos] = new Reference($id);
if (isset($priority_pos)) {
$arguments[$priority_pos] = $priority;
}
if (isset($id_pos)) {
$arguments[$id_pos] = $id;
}
// Add in extra arguments.
if (isset($extra_arguments[$id])) {
// Place extra arguments in their right positions.
$arguments += $extra_arguments[$id];
}
// Sort the arguments by position.
ksort($arguments);
$consumer
->addMethodCall($method_name, $arguments);
}
}
}
}