function TaggedHandlersPass::processServiceCollectorPass

Same name and namespace in other branches
  1. 9 core/lib/Drupal/Core/DependencyInjection/Compiler/TaggedHandlersPass.php \Drupal\Core\DependencyInjection\Compiler\TaggedHandlersPass::processServiceCollectorPass()
  2. 8.9.x core/lib/Drupal/Core/DependencyInjection/Compiler/TaggedHandlersPass.php \Drupal\Core\DependencyInjection\Compiler\TaggedHandlersPass::processServiceCollectorPass()
  3. 11.x core/lib/Drupal/Core/DependencyInjection/Compiler/TaggedHandlersPass.php \Drupal\Core\DependencyInjection\Compiler\TaggedHandlersPass::processServiceCollectorPass()

Processes a service collector service pass.

Parameters

array $pass: The service collector pass data.

string $consumer_id: The consumer service ID.

\Symfony\Component\DependencyInjection\ContainerBuilder $container: The service container.

1 call to TaggedHandlersPass::processServiceCollectorPass()
TaggedHandlersPass::process in core/lib/Drupal/Core/DependencyInjection/Compiler/TaggedHandlersPass.php
Finds services tagged with 'service_collector' or 'service_id_collector', then finds all corresponding tagged services.

File

core/lib/Drupal/Core/DependencyInjection/Compiler/TaggedHandlersPass.php, line 138

Class

TaggedHandlersPass
Collects services to add/inject them into a consumer service.

Namespace

Drupal\Core\DependencyInjection\Compiler

Code

protected function processServiceCollectorPass(array $pass, $consumer_id, ContainerBuilder $container) {
    $tag = $pass['tag'] ?? $consumer_id;
    $method_name = $pass['call'] ?? 'addHandler';
    $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) {
        $class = Reflection::getParameterClassName($param);
        if ($class !== NULL) {
            $interface = $class;
        }
        elseif ($param->getName() === 'id') {
            $id_pos = $pos;
        }
        elseif ($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.", [
            $consumer_id,
            $consumer->getClass(),
            $method_name,
        ]));
    }
    // Find all tagged handlers.
    $handlers = [];
    $extra_arguments = [];
    foreach ($this->tagCache[$tag] ?? [] as $id => $attributes) {
        // Validate the interface.
        $handler = $container->getDefinition($id);
        if (!is_a($handler->getClass(), $interface, TRUE)) {
            throw new LogicException("Service '{$id}' for consumer '{$consumer_id}' does not implement {$interface}.");
        }
        $handlers[$id] = $attributes[0]['priority'] ?? 0;
        // Keep track of other tagged handlers arguments.
        foreach ($extra_params as $name => $pos) {
            $extra_arguments[$id][$pos] = $attributes[0][$name] ?? $params[$pos]->getDefaultValue();
        }
    }
    if ($required && empty($handlers)) {
        throw new LogicException(sprintf("At least one service tagged with '%s' is required.", $tag));
    }
    // 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 = [];
        $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);
    }
}

Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.