Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

[DI] controller.service_arguments does not handle invokable controllers #22202

Copy link
Copy link
Closed
@BPScott

Description

@BPScott
Issue body actions
Q A
Bug report? yes
Feature request? no
BC Break report? no
RFC? no
Symfony version 3.3.0-dev

#21771 added support for the controller.service_arguments tag to let you stop using $this->get() and instead use autowired arguments for Controller actions. This works great when the controller is a regular method, e.g.:

A services YAML:

services:
    _defaults:
        autowire: true
        public: false

    AppBundle\Controller\:
        resource: '../../src/Controller'
        public: true # Mandatory
        tags: ['controller.service_arguments']

A routing YAML:

home:
    path: /home
    defaults: { _controller: AppBundle\Controller\HomeController::homeAction }

Controller:

class HomeController extends Controller
{
    public function homeAction(Request $request, ProgrammesService $programmesService)
    {
        $programmeCount = $programmesService->countAll();
        // ...
    }
}

However it does not work when I attempt to use an invokable Controller:

A routing YAML:

home:
    path: /home
    defaults: { _controller: AppBundle\Controller\HomeController }

Controller:

class HomeController extends Controller
{
    public function __invoke(Request $request, ProgrammesService $programmesService)
    {
        $programmeCount = $programmesService->countAll();
        // ...
    }
}

Using this configuration I get the error:

'Controller "AppBundle\Controller\HomeController" requires that you provide a value for the "$programmesService" argument. Either the argument is nullable and no null value has been provided, no default value has been provided or because there is a non optional argument after this one.' in vendor/symfony/symfony/src/Symfony/Component/HttpKernel/Controller/ArgumentResolver.php at line 78


I can solve this using constructor injection, by making the Controller look like this:

class HomeController extends Controller
{
    private $programmesService;

    public function __construct(ProgrammesService $programmesService)
    {
        $this->programmesService = $programmesService;
    }

    public function __invoke(Request $request)
    {
        $programmeCount = $this->programmesService->countAll();
        // ...
    }
}

But having to setup that constructor and instance variable seems like boilerplate that could be sidestepped by using parameters within the __invoke function.

I spent quite a bit of time assuming that invokable controllers would be equivalent to *Action-style controllers in all but name and how they are referenced in the routing and think this symmetry would be useful.

Are there any performance reasons why using constructor injection is preferable to adding the arguments to the action method?

Expected Behaviour:

I expect the arguments on __invoke would be autowired in the same way as they would be on other class functions (e.g. one named homeAction) so that my notion of symmetry between invokable controllers and "an Action method in a Controller class" is preserved.

Alternatively, I expect exception messaging making it clear that invokable controllers are not supported when using controller.service_arguments and that I should use constructor injection instead.

/cc @nicolas-grekas

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

      Morty Proxy This is a proxified and sanitized view of the page, visit original site.