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

Skip to content

Controller using ServiceSubscriberTrait has service locator overwritten by service container #49382

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
edsrzf opened this issue Feb 14, 2023 · 1 comment

Comments

@edsrzf
Copy link

edsrzf commented Feb 14, 2023

Symfony version(s) affected

6.2.5

Description

A controller using ServiceSubscriberTrait is wired up correctly. However, when a request is served, its service locator is overwritten by the service container. This usually causes an error when a service is retrieved from the service container, since the service names are likely to be incompatible.

How to reproduce

Repo demonstrating the issue here: https://github.com/edsrzf/symfony_reproducer

To reproduce:

  • Start the local server with symfony server:start
  • Navigate to http://127.0.0.1:8000
  • See the error: You have requested a non-existent service "App\Controller\Controller::getService". Did you mean this: "App\Controller\Controller"?

Possible Solution

The cause is this bit of code in Symfony\Bundle\FrameworkBundle\Controller\ControllerResolver:

if (null === $previousContainer = $controller->setContainer($this->container)) {
throw new \LogicException(sprintf('"%s" has no container set, did you forget to define it as a service subscriber?', $class));
} else {
$controller->setContainer($previousContainer);
}

when combined with setContainer from ServiceSubscriberTrait:

#[Required]
public function setContainer(ContainerInterface $container): ?ContainerInterface
{
$this->container = $container;
if (method_exists(get_parent_class(self::class) ?: '', __FUNCTION__)) {
return parent::setContainer($container);
}
return null;
}

setContainer is called a total of 3 times in the process of serving a request:

  • Once by the service container, passing in the service locator. It returns null.
  • The first time by ControllerResolver, passing in the service container. The trait sets the container property, and then AbstractController returns the "previous" container property value, which is actually not the previous value. It's the service container.
  • The second time by ControllerResolver, which passes the "previous" value back in. It should be the service locator, but it's actually the service container.

It feels like the fix needs to be inside ServiceSubscriberTrait. Maybe parent::setContainer could be called before setting $this->container?

Additional Context

Workaround

The issue can be worked around by overriding setContainer, skipping the trait's method:

#[Required]
public function setContainer(ContainerInterface $container): ?ContainerInterface
{
    return parent::setContainer($container);
}
@lyrixx
Copy link
Member

lyrixx commented Feb 14, 2023

may be related to #49083?

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