Skip to content
Snippets Groups Projects
Commit 048a4ebc authored by catch's avatar catch
Browse files

Issue #3309334 by el7cosmos, smustgrave: Service collector won't collect child services

(cherry picked from commit 9e52085b)
parent 2f93f58b
No related branches found
No related tags found
No related merge requests found
Pipeline #537908 canceled
Pipeline: drupal

#537912

    ......@@ -3,8 +3,10 @@
    namespace Drupal\Core\DependencyInjection\Compiler;
    use Drupal\Component\Utility\Reflection;
    use Symfony\Component\DependencyInjection\ChildDefinition;
    use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
    use Symfony\Component\DependencyInjection\ContainerBuilder;
    use Symfony\Component\DependencyInjection\Definition;
    use Symfony\Component\DependencyInjection\Exception\LogicException;
    use Symfony\Component\DependencyInjection\Reference;
    ......@@ -180,7 +182,8 @@ protected function processServiceCollectorPass(array $pass, $consumer_id, Contai
    foreach ($this->tagCache[$tag] ?? [] as $id => $attributes) {
    // Validate the interface.
    $handler = $container->getDefinition($id);
    if (!is_a($handler->getClass(), $interface, TRUE)) {
    $class = $this->resolveDefinitionClass($handler, $container);
    if (!is_a($class, $interface, TRUE)) {
    throw new LogicException("Service '$id' for consumer '$consumer_id' does not implement $interface.");
    }
    $handlers[$id] = $attributes[0]['priority'] ?? 0;
    ......@@ -251,4 +254,33 @@ protected function processServiceIdCollectorPass(array $pass, $consumer_id, Cont
    $consumer->addArgument(array_keys($handlers));
    }
    /**
    * Resolves the definition class.
    *
    * @param \Symfony\Component\DependencyInjection\Definition $definition
    * The service definition.
    * @param \Symfony\Component\DependencyInjection\ContainerBuilder $container
    * The service container.
    *
    * @return class-string|null
    * The resolved class-string or null if the class cannot be resolved.
    */
    protected function resolveDefinitionClass(Definition $definition, ContainerBuilder $container): ?string {
    $class = $definition->getClass();
    if ($class) {
    return $class;
    }
    if (!$definition instanceof ChildDefinition) {
    return NULL;
    }
    if (!$container->hasDefinition($definition->getParent())) {
    return NULL;
    }
    $parent = $container->getDefinition($definition->getParent());
    return $this->resolveDefinitionClass($parent, $container);
    }
    }
    ......@@ -6,6 +6,7 @@
    use Drupal\Core\DependencyInjection\Compiler\TaggedHandlersPass;
    use Drupal\Tests\UnitTestCase;
    use Symfony\Component\DependencyInjection\ChildDefinition;
    use Symfony\Component\DependencyInjection\ContainerBuilder;
    use Symfony\Component\DependencyInjection\Exception\LogicException;
    use Symfony\Component\DependencyInjection\Reference;
    ......@@ -306,6 +307,31 @@ public function testProcessInterfaceMismatch(): void {
    $handler_pass->process($container);
    }
    /**
    * Tests child handler with parent service.
    *
    * @covers ::process
    */
    public function testProcessChildDefinition(): void {
    $container = $this->buildContainer();
    $container
    ->register('consumer_id', __NAMESPACE__ . '\ValidConsumer')
    ->addTag('service_collector');
    $container
    ->register('root_handler', __NAMESPACE__ . '\ValidHandler');
    $container->addDefinitions([
    'parent_handler' => new ChildDefinition('root_handler'),
    'child_handler' => (new ChildDefinition('parent_handler'))->addTag('consumer_id'),
    ]);
    $handler_pass = new TaggedHandlersPass();
    $handler_pass->process($container);
    $method_calls = $container->getDefinition('consumer_id')->getMethodCalls();
    $this->assertCount(1, $method_calls);
    }
    /**
    * Tests consumer method with extra parameters.
    *
    ......
    0% Loading or .
    You are about to add 0 people to the discussion. Proceed with caution.
    Please register or to comment