Thanks to visit codestin.com
Credit goes to github.com

Skip to content

[6.2] Decorating the framework "router" service breaks the service container #48622

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
egonolieux opened this issue Dec 13, 2022 · 2 comments
Closed

Comments

@egonolieux
Copy link

egonolieux commented Dec 13, 2022

Symfony version(s) affected

6.2.*

Description

I have a service that decorates the framework router service with the following signature:

#[AsDecorator(decorates: 'router')]
final class AppRouter implements RequestMatcherInterface, RouterInterface, ServiceSubscriberInterface, WarmableInterface
{
    public function __construct(
        #[MapDecorated()]
        private readonly Router $router,
    ) {}
}

This worked fine until upgrading to 6.2 (from 6.1) with the following error:

The definition ".service_locator.kV3NDIb" has a reference to an abstract definition "Symfony\Component\Config\Loader\LoaderInterface". Abstract definitions cannot be the target of references.

As I'm not very knowledgable about the inner workings of the service container, this error seemed quite cryptic to me at first. After many hours or debugging and disabling services one by one, I discovered that this error originates from the decorated router service.

This is the full stack trace:

Symfony\Component\DependencyInjection\Exception\RuntimeException:
The definition ".service_locator.kV3NDIb" has a reference to an abstract definition "Symfony\Component\Config\Loader\LoaderInterface". Abstract definitions cannot be the target of references.

  at /home/egonolieux/projects/tcgcollector/vendor/symfony/dependency-injection/Compiler/CheckReferenceValidityPass.php:37
  at Symfony\Component\DependencyInjection\Compiler\CheckReferenceValidityPass->processValue()
     (/home/egonolieux/projects/tcgcollector/vendor/symfony/dependency-injection/Compiler/AbstractRecursivePass.php:80)
  at Symfony\Component\DependencyInjection\Compiler\AbstractRecursivePass->processValue()
     (/home/egonolieux/projects/tcgcollector/vendor/symfony/dependency-injection/Compiler/CheckReferenceValidityPass.php:41)
  at Symfony\Component\DependencyInjection\Compiler\CheckReferenceValidityPass->processValue()
     (/home/egonolieux/projects/tcgcollector/vendor/symfony/dependency-injection/Compiler/AbstractRecursivePass.php:85)
  at Symfony\Component\DependencyInjection\Compiler\AbstractRecursivePass->processValue()
     (/home/egonolieux/projects/tcgcollector/vendor/symfony/dependency-injection/Compiler/CheckReferenceValidityPass.php:41)
  at Symfony\Component\DependencyInjection\Compiler\CheckReferenceValidityPass->processValue()
     (/home/egonolieux/projects/tcgcollector/vendor/symfony/dependency-injection/Compiler/AbstractRecursivePass.php:80)
  at Symfony\Component\DependencyInjection\Compiler\AbstractRecursivePass->processValue()
     (/home/egonolieux/projects/tcgcollector/vendor/symfony/dependency-injection/Compiler/CheckReferenceValidityPass.php:41)
  at Symfony\Component\DependencyInjection\Compiler\CheckReferenceValidityPass->processValue()
     (/home/egonolieux/projects/tcgcollector/vendor/symfony/dependency-injection/Compiler/AbstractRecursivePass.php:80)
  at Symfony\Component\DependencyInjection\Compiler\AbstractRecursivePass->processValue()
     (/home/egonolieux/projects/tcgcollector/vendor/symfony/dependency-injection/Compiler/CheckReferenceValidityPass.php:41)
  at Symfony\Component\DependencyInjection\Compiler\CheckReferenceValidityPass->processValue()
     (/home/egonolieux/projects/tcgcollector/vendor/symfony/dependency-injection/Compiler/AbstractRecursivePass.php:89)
  at Symfony\Component\DependencyInjection\Compiler\AbstractRecursivePass->processValue()
     (/home/egonolieux/projects/tcgcollector/vendor/symfony/dependency-injection/Compiler/CheckReferenceValidityPass.php:41)
  at Symfony\Component\DependencyInjection\Compiler\CheckReferenceValidityPass->processValue()
     (/home/egonolieux/projects/tcgcollector/vendor/symfony/dependency-injection/Compiler/AbstractRecursivePass.php:80)
  at Symfony\Component\DependencyInjection\Compiler\AbstractRecursivePass->processValue()
     (/home/egonolieux/projects/tcgcollector/vendor/symfony/dependency-injection/Compiler/CheckReferenceValidityPass.php:41)
  at Symfony\Component\DependencyInjection\Compiler\CheckReferenceValidityPass->processValue()
     (/home/egonolieux/projects/tcgcollector/vendor/symfony/dependency-injection/Compiler/AbstractRecursivePass.php:44)
  at Symfony\Component\DependencyInjection\Compiler\AbstractRecursivePass->process()
     (/home/egonolieux/projects/tcgcollector/vendor/symfony/dependency-injection/Compiler/Compiler.php:73)
  at Symfony\Component\DependencyInjection\Compiler\Compiler->compile()
     (/home/egonolieux/projects/tcgcollector/vendor/symfony/dependency-injection/ContainerBuilder.php:721)
  at Symfony\Component\DependencyInjection\ContainerBuilder->compile()
     (/home/egonolieux/projects/tcgcollector/vendor/symfony/http-kernel/Kernel.php:487)
  at Symfony\Component\HttpKernel\Kernel->initializeContainer()
     (/home/egonolieux/projects/tcgcollector/vendor/symfony/http-kernel/Kernel.php:709)
  at Symfony\Component\HttpKernel\Kernel->preBoot()
     (/home/egonolieux/projects/tcgcollector/vendor/symfony/http-kernel/Kernel.php:172)
  at Symfony\Component\HttpKernel\Kernel->handle()
     (/home/egonolieux/projects/tcgcollector/vendor/symfony/runtime/Runner/Symfony/HttpKernelRunner.php:35)
  at Symfony\Component\Runtime\Runner\Symfony\HttpKernelRunner->run()
     (/home/egonolieux/projects/tcgcollector/vendor/autoload_runtime.php:29)
  at require_once('/home/egonolieux/projects/tcgcollector/vendor/autoload_runtime.php')
     (/home/egonolieux/projects/tcgcollector/public/index.php:5)     

How to reproduce

Simply create a service that decorates the framework router service:

<?php

declare(strict_types=1);

namespace App\Service;

use Symfony\Bundle\FrameworkBundle\Routing\Router;
use Symfony\Component\DependencyInjection\Attribute\AsDecorator;
use Symfony\Component\DependencyInjection\Attribute\MapDecorated;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\CacheWarmer\WarmableInterface;
use Symfony\Component\Routing\Matcher\RequestMatcherInterface;
use Symfony\Component\Routing\RequestContext;
use Symfony\Component\Routing\RouteCollection;
use Symfony\Component\Routing\RouterInterface;
use Symfony\Contracts\Service\ServiceSubscriberInterface;

#[AsDecorator(decorates: 'router')]
final class AppRouter implements RequestMatcherInterface, RouterInterface, ServiceSubscriberInterface, WarmableInterface
{
    public function __construct(
        #[MapDecorated()]
        private readonly Router $router,
    ) {}

    public function getContext(): RequestContext
    {
        return $this->router->getContext();
    }

    public function setContext(RequestContext $context): void
    {
        $this->router->setContext($context);
    }

    /**
     * @param array<string, string> $parameters
     */
    public function generate(
        string $name,
        array $parameters = [],
        int $referenceType = RouterInterface::ABSOLUTE_PATH): string
    {
        return $this->router->generate($name, $parameters, $referenceType);
    }

    /**
     * @return array<string, mixed>
     */
    public function match(string $pathinfo): array
    {
        return $this->router->match($pathinfo);
    }

    public function getRouteCollection(): RouteCollection
    {
        return $this->router->getRouteCollection();
    }

    /**
     * @return array<string, mixed>
     */
    public function matchRequest(Request $request): array
    {
        return $this->router->matchRequest($request);
    }

    /**
     * @return array<int, mixed>
     */
    public function warmUp(string $cacheDir): array
    {
        return $this->router->warmUp($cacheDir);
    }

    /**
     * @return array<string, string>
     */
    public static function getSubscribedServices(): array
    {
        return Router::getSubscribedServices();
    }
}

Possible Solution

No response

Additional Context

No response

@MatTheCat
Copy link
Contributor

MatTheCat commented Dec 14, 2022

Feels like it is related to #46279 (because of this change) made but this is as far as I can push the investigation 😅

@nicolas-grekas does it ring a bell?

@nicolas-grekas
Copy link
Member

nicolas-grekas commented Dec 14, 2022

I'm closing as invalid: the class you have implements ServiceSubscriberInterface but provides no injection point for the container. The issue is that the class is autowired, and because you return Router::getSubscribedServices() from getSubscribedServices(), you declare that this class requires a LoaderInterface implementation. There is no such interface to wire.

(I get that the error is a bit cryptic. Not sure how we can improve this.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants