Fosrestbundle: Container not injected in controllers with FosRest 2.2 and Symfony 3.3 in rest routes

Created on 14 Jun 2017  路  24Comments  路  Source: FriendsOfSymfony/FOSRestBundle

When trying to set up a route for my rest api, when I visit my "/places" route I get a FatalThrowableError: "Call to a member function has() on null" in vendor\symfony\symfony\src\Symfony\Bundle\FrameworkBundle\Controller\ControllerTrait.php (line 356)

The problem only happens when I switch my routes from annotation to rest.

This doesn't work:

places:
    type:     rest
    resource: AppBundle\Controller\PlaceController

This works:

places:
    type:     annotation
    resource: AppBundle\Controller\PlaceController

The method is almost empty, only a call to getDoctrine:

    /**
     * @Get("/places")
     */
    public function getPlacesAction(Request $request)
    {
        dump($this->container);
        $this->getDoctrine();

        return new JsonResponse($formatted);
    }

And the container is null. I checked and the setContainer method is never called on my Controller and I can't find why.

The same thing works with identical configuration with Symfony 3.2.9, but not with Symfony 3.3.

Most helpful comment

Symfony 3.3.3 containing this fix was released.

All 24 comments

Are you able to set up a small example project that makes it possible to reproduce your issue?

I have the same problem with Symfony 3.3.2. $this->container is null. So I get:
"Error: Call to a member function has() on null" when I invoke $this->getDoctrine() in controller.

Maybe related to symfony/symfony#23200?

Do you make use of the new feature that makes it possible to easily register controllers as services?

Yes it might be related.
I've tried this solution for my controller(service.yml) as was mentioned in symfony/symfony#23200 thread:

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

and it works. But it's obvious that something wrong with auto injecting container in controller.

Do you use JMSDiExtraBundle?

I don't. Here is my composer.json deps:

{
    "name": "root/api",
    "license": "proprietary",
    "type": "project",
    "autoload": {
        "psr-4": {
            "": "src/"
        },
        "classmap": [
            "app/AppKernel.php",
            "app/AppCache.php"
        ]
    },
    "autoload-dev": {
        "psr-4": {
            "Tests\\": "tests/"
        },
        "files": [
            "vendor/symfony/symfony/src/Symfony/Component/VarDumper/Resources/functions/dump.php"
        ]
    },
    "require": {
        "php": ">=5.5.9",
        "doctrine/doctrine-bundle": "^1.6",
        "doctrine/doctrine-migrations-bundle": "^1.2",
        "doctrine/orm": "^2.5",
        "friendsofsymfony/user-bundle": "~2.0",
        "incenteev/composer-parameter-handler": "^2.0",
        "lexik/jwt-authentication-bundle": "^2.4",
        "sensio/distribution-bundle": "^5.0.19",
        "sensio/framework-extra-bundle": "^3.0.2",
        "symfony/monolog-bundle": "^3.1.0",
        "symfony/polyfill-apcu": "^1.0",
        "symfony/swiftmailer-bundle": "^2.3.10",
        "symfony/symfony": "3.3.*",
        "twig/twig": "^1.0||^2.0",

        "nelmio/cors-bundle": "^1.4",
        "nelmio/api-doc-bundle": "^2.11",
        "friendsofsymfony/rest-bundle": "^2.1",
        "jms/serializer-bundle": "^1.1"
    },
    "require-dev": {
        "sensio/generator-bundle": "^3.0",
        "symfony/phpunit-bridge": "^3.0"
    },
    "scripts": {
        "symfony-scripts": [
            "Incenteev\\ParameterHandler\\ScriptHandler::buildParameters",
            "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::buildBootstrap",
            "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::clearCache",
            "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::installAssets",
            "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::installRequirementsFile",
            "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::prepareDeploymentTarget"
        ],
        "post-install-cmd": [
            "@symfony-scripts"
        ],
        "post-update-cmd": [
            "@symfony-scripts"
        ]
    },
    "config": {
        "sort-packages": true
    },
    "extra": {
        "symfony-app-dir": "app",
        "symfony-bin-dir": "bin",
        "symfony-var-dir": "var",
        "symfony-web-dir": "web",
        "symfony-tests-dir": "tests",
        "symfony-assets-install": "relative",
        "incenteev-parameters": {
            "file": "app/config/parameters.yml"
        },
        "branch-alias": null
    }
}

Do you register your controllers as services? If yes, what does your config look like? Can you also show the code of your controller?

This is the controller I stuck with:

namespace AppBundle\Controller;

use FOS\RestBundle\Controller\Annotations\RouteResource;
use FOS\RestBundle\Controller\FOSRestController;
use FOS\RestBundle\Routing\ClassResourceInterface;

/**
 * Class UserController
 * @package AppBundle\Controller
 *
 * @RouteResource("user")
 */
class UserController extends FOSRestController implements ClassResourceInterface
{
    public function getAction($id) {
        var_dump($this->container); // display null
        exit;

        // next code gives error because container is null:

//        return $this->getDoctrine()
//            ->getRepository('AppBundle:User')
//            ->find($id);
    } // "get_user"      [GET] /users/{slug}
}

My services.yml:

# Learn more about services, parameters and containers at
# http://symfony.com/doc/current/service_container.html
parameters:
    #parameter_name: value

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}'

    # 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']

    # add more services, or override services that need manual wiring
    # AppBundle\Service\ExampleService:
    #     arguments:
    #         $someArgument: 'some_value'


# ----------------------------------------------------------------
# !!!!!!! Next code inject container and the code is start working
#    AppBundle\Controller\UserController:
#        calls:
#            - [setContainer, ["@service_container"]]

I got the same issue, it is a pain in the ass

Can someone of you create a small example project that makes it easily possible to reproduce your issue?

@xabbuh Here is a test project with the problem:
https://github.com/maxixcom/symfony-container

But it use db. You need configure and create some db. And run migrations:

./bin/console doctrine:migration:migrate

Actually it creates FOSUserBundle User table.
Look at UserController::getAction - (GET request - /users/1). There is a problem.
But if you try DefaultController::indexAction (GET request - /) you'll see that container exist

Thank you for providing this useful example. I think I was able to reproduce the issue. Can you please check if symfony/symfony#23239 fixes it for you?

@xabbuh Yes, it fixes the issue. Container is in controller now.

Hi,
I have the same issue. How to fix the problem? Manually?

Thanks.

to fix it you have to update Framework Bundle... or just edit it and add the new content

https://github.com/symfony/symfony/pull/23239/files

vendor/symfony/symfony/src/Symfony/Bundle/FrameworkBundle/Controller/ControllerResolver.php

Will it be fixed somehow in the bundle or should we wait for the next symfony release and until then apply some custom fixes?

Symfony 3.3.3 containing this fix was released.

Symfony 3.3.9 has this issue when using JMSDiExtraBundle. The "solution" (I bracket it as I have NO idea whats going on) was to add the setContainer call to my controllers in the "generic" autowiring section:

# 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"]]**

Also Symfony 3.3.13 is still affected. The solution is the same above... but didn't have it been fixed already?

Are you using JMSDiExtraBundle?

Yes, version 1.9.0

Then it's probably related to their code. I don't know if they ever fixed the issue on their side.

@ventuc you need to downgrade JMSDiExtraBundle to 1.7.0 version.
It solves the issue.

Was this page helpful?
0 / 5 - 0 ratings