symfony: Cannot access the container from inside a controller

Q A
Bug report? yes
Feature request? no
BC Break report? no
Symfony version 3.3.2

I’m migrating my app from Symfony 2.8 to Symfony 3.3.

NOTE: I’m not upgrading the 2.8 version, but installed a fresh project of Symfony 3.3 and moving all relvant files to it from the old 2.8 Symfony project.

From inside a controller of mine I have this:

public function indexAction()
{
    $email = new Email();

    $form = $this->createForm(GetStartedType::class, $email, [
        'action' => $this->generateUrl('get_started_end'),
        'method' => 'POST',
    ]);

    return [
        'form' => $form->createView(),
    ];
}

But I receive this exception:

Call to a member function get() on null

My controller extends Symfony\Bundle\FrameworkBundle\Controller\Controller:

/**
 * {@inheritdoc}
 */
class DefaultController extends Controller
{
...
}

So I have access to the container.

Putting some dumps around in the Symfony’s code, I see that the container is correctly set:

namespace Symfony\Component\DependencyInjection;

/**
 * ContainerAware trait.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
trait ContainerAwareTrait
{
    /**
     * @var ContainerInterface
     */
    protected $container;

    /**
     * Sets the container.
     *
     * @param ContainerInterface|null $container A ContainerInterface instance or null
     */
    public function setContainer(ContainerInterface $container = null)
    {
        dump('Here in the ContainerAwareTrait');
        dump(null === $container);
        $this->container = $container;
    }
}

This dumps

Here in the ContainerAwareTrait
false

So the autowiring works well and sets the container.

But in the ControllerTrait I have this:

trait ControllerTrait
{
    /**
     * Generates a URL from the given parameters.
     *
     * @param string $route         The name of the route
     * @param mixed  $parameters    An array of parameters
     * @param int    $referenceType The type of reference (one of the constants in UrlGeneratorInterface)
     *
     * @return string The generated URL
     *
     * @see UrlGeneratorInterface
     */
    protected function generateUrl($route, $parameters = array(), $referenceType = UrlGeneratorInterface::ABSOLUTE_PATH)
    {
        dump('Here in the ControllerTrait');
        die(dump(null === $this->container));
        return $this->container->get('router')->generate($route, $parameters, $referenceType);
    }

    ...

this is the dump:

Here in the ControllerTrait
true

So here the container is null and this causes the error.

Anyone can help me solve this issue?

Why is the container null?

If may help, this is the services.yml configuration (the default that cames with Symfony):

# controllers are imported separately to make sure they're public
# and have a tag that allows actions to type-hint services
AppBundle\Controller\:
    resource: '../../src/AppBundle/Controller'
    public: true
    tags: ['controller.service_arguments']

This issue is a copy and paste of a Stackoverflow question I opened.

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Reactions: 6
  • Comments: 39 (29 by maintainers)

Commits related to this issue

Most upvoted comments

TEST 2: Skipped

TEST 3: Try to explicitly call the setContainer method on the controllers Expected result: The controller action works as expected

With this configuration in services.yml:

services:
    # default configuration for services in *this* file
    _defaults:
        # automatically injects dependencies in your services
        autowire: true
        # automatically registers your services as commands, event subscribers, etc.
        autoconfigure: true
        # this means you cannot fetch services directly from the container via $container->get()
        # if you need to do this, you can override this setting on individual services
        public: false

    # makes classes in src/AppBundle available to be used as services
    # this creates a service per class whose id is the fully-qualified class name
    AppBundle\:
        resource: '../../src/AppBundle/*'
        # you can exclude directories or files
        # but if a service is unused, it's removed anyway
        exclude: '../../src/AppBundle/{Entity,Repository,Tests,EventListener,Validator,Twig}'

    # controllers are imported separately to make sure they're public
    # and have a tag that allows actions to type-hint services
    AppBundle\Controller\:
        resource: '../../src/AppBundle/Controller'
        public: true
        tags: ['controller.service_arguments']
        calls:
            - [setContainer, ["@service_container"]]

The issue is resolved: the controller shows the page and no exception is thrown.

So the problem, I think, is with the tag controller.service_arguments: this should call automatically the setContainer method on controllers that implements the ContainerAwareInterface, doesn’t it?

It doesn’t, but I don’t know if this is the right behavior or not.

I have determined that in my case this was caused by using the JMSDiExtraBundle. Unregistering that bundle from my kernel fixed the issue. It appears that this was because that bundle was taking over control of instantiating controllers. Specifically the instantiateController method which does not inject the container if the controller is a service.

@Aerendir: Are you also using this bundle in your project?

@Aerendir the problem is from that JMSDiExtraBundle. Tried using it yesterday because of the JMSTranslationBundle … and i found out it breaks the container. Your getting get() null because i think it won’t load the container. Didn’t try to stay longer on it because i only wanted to test out the translation bundle.

I just upgraded from 3.2.x to v3.3.0 and I encountered that exact same problem. Adding

calls:
        - [setContainer, ["@service_container"]]

Fixed the problem immediately (thanks for the trick). So I guess there is something broken in the service_container automatic injection

Best Regards

Reproducing case? How I could? Is an entire app!

More than the code of the controller I cannot give… It is a lot of code!

Maybe you know some fine details I can check other than the involved traits (ContainerAwareTrait and ControllerTrait)…

@william-greatcontent I believe your comment here is off topic, but I went ahead and answered it on SO for you.

i encounter the very same prob out of nowhere . did not upgrade or do any maneuver pf any kind… solved inmmediately by adding calls: - [setContainer, [“@service_container”]] thx a lot

closing here as this should be fixed by #23239

@Aerendir Yes, that PR indeed does not tackle any issues related to JSMDiExtraBundle. If they are replacing the core controller resolver, it’s likely that something needs to be changed over there.

@xabbuh , this didn’t solved my issue, instead.

Going deeper, I’ve tried to put a simple die(dump('here it is)) at the beginning of the method ControllerResolver::createController() and it is never intercepted… As if the method is never called…

Can this depend by the fact I’m using JMSDiExtraBundle and JMSTranslationBundle? Removing both of them (plus removing JMSAopBundle) I now receive an error in Twig about an invalid resource provided.

This means for me that the problem is actually JMS*Bundles as they do somthing that broke the autowiring functionality.

Because if I receive an error in Twig, this means the controller is correctly created, and the controller set as the routes and all other short methods can work regularly…

So the problem, is in JMS bundles…

No. I’m not saying the behavior you’re experiencing is right. I’m still in troubles identifying/reproducing your issue.

I’m only expressing facts, not any conclusion about your issue. You talk a lot about “autowired injection of the container”:

my controllers extend Symfony\Bundle\FrameworkBundle\Controller\Controller that implements Symfony\Component\DependencyInjection\ContainerAwareInterface, so the autowired injection could happen… Doesn’t it?

I’m just saying there isn’t any container autowiring expected currently by extending Controller or implementing ContainerAwareInterface. This is only runtime injection, once the controller is resolved. Autowired injection is made by using the AbstractController which implements ServiceSubscriberInterface, hence a setContainer method call is added to the service definition with a specific PSR-11 container instance containing services described in ServiceSubscriberInterface::getSubscribedServices().

Hope it’s a bit clearer.

@nicolas-grekas , my controllers extend Symfony\Bundle\FrameworkBundle\Controller\Controller that implements Symfony\Component\DependencyInjection\ContainerAwareInterface, so the autowired injection could happen… Doesn’t it?

@ogizanagi I’ll investigate if this is my case and I’ll tell you…

There is a misunderstanding here: controller.service_arguments does NOT mean “inject the container”. The things that trigger automatic injection of the container are implementing the ContainerAwareInterface or implementing the ServiceSubscriberInterface basically.

But to recreate the issue I should already know which the cause is, and this is exactly what I’m trying to understand! o.O

How can I reproduce something of which I don’t know the cause?

Just because is something specific to my way of using Symfony (that, anyway, is the “normal” way of using it, relying on its built-in functionalities) is something that I cannot reproduce in a fresh installation of the framework.

For this reason I were asking for some suggestions on how to debug the issue.

For example, I will do the following two things:

  1. Disable the autowiring at all to understand if the cause is the autowiring itself or not;
  2. Enabling the autowiring again and dump the class assigned ID, both in ContainerAwareTrait and in ControllerTrait to understand if the autowired class is the same I’m using in my controller;
  3. Try to explicitly call the setContainer method.

I’m asking for this kind of advice, that can help me debug the issue in my project, with my way of using Symfony, also to understand if it really is a bug to fix or if it is a mistake of mine.

PS Maybe it’s true that I’m the first to report this is issue, but for sure I’m not the first to encounter it: this is not an issue related to my way of using Symfony, but to the autowire functionality in itself.

See this other discussion on Stackoverflow where the solution were to simply disable the autowiring.