How to get more than Request in Controller Action

Found a typo? Edit me
This post is deprecated since May 2017. Its knowledge is old and should not be used.
Why?

You can inject services into actions using controller.service_arguments tag since Symfony 3.3.

Combined with PSR4-based service discovery and registration and autoconfiguration this is amazing feature.

I recommend using it instead!


You already know you can get Request object in your controller action. Cool, but there is more.

In Symfony 3.1 is new Action Argument Resolving feature, so you can get any service you need. With a bit of work. Today I will show you how.

Disclaimer: What happened to controller constructor injection?

I still prefer constructor injection in controllers. Are you asking why and how to achieve that in Symfony?

In 3 minutes you will find out in my other article. I will wait here...




...ok. Now you are probably in one of these 2 groups:

1. You want to use constructor injection in controllers, because you like advantages of service design

Stop reading, because this article describes only method injection, which is not so clean. It would add unnecessary complexity to your already solid system with no added value. So go install Symplify/ControllerAutowire bundle and enjoy your day!

2. You consider constructor injection in controller too much writing with not much added value

This is article for you. Keep reading!

To be honest, first I was completely ignoring this second group, but Jáchym explained me why it's important.

How named services bring less writing

Typical controller in Symfony looks like this:

// src/AppBundle/Controller/MeetupController.php
namespace AppBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;

class MeetupController extends Controller
{
    public function listAction()
    {
        $meetupRepository = $this->get('meetup_repository');

        return $this->render('meetup/list.twig', [
            'meetups' => $meetupRepository->findAll()
        ]);
    }
}

These 2 lines are the most important:

$meetupRepository = $this->get('meetup_repository');
['meetups' => $meetupRepository->findAll()]

Hidden vendor lock

How do we know, that meetup_repository service has findAll() method?

You need 3 things to work at once:

Is this really necessary?

Nope. Any IDE can autocomplete on object or interface typehint. And without plugins.

But how to get that there? We can use constructor injection with typehints, but it would be too much writing.

Compare yourself this:

/**
 * @var MeetupRepository
 */
private $meetupRepository;

public function __construct(MeetupRepository $meetupRepository)
{
    $this->meetupRepository = $meetupRepository;
}

public function listAction()
{
    // $this->meetupRepository;
}

to this:

public function listAction()
{
    // $this->get('meetup_repository');
}

I've counted that for you:

It's 11 lines to 1 just to just get a service!

I must admit, this is killer argument why not to use constructor injection in controllers.

Meet me half way?

What if you could inject the service via method?

public function listAction(MeetupRepository $meetupRepository)
{
    $meetups = $meetupRepository->findAll();
    // ...
}

Result?

This all brings greater secondary advantages:

To make this happened, I made Symplify\ActionAutowire bundle.

How to enable controllers action autowiring in 3 steps

1. Install package

composer require symplify/action-autowire

2. Register bundle

// app/AppKernel.php
class AppKernel extends Kernel
{
    public function registerBundles()
    {
        $bundles = [
            new Symplify\ActionAutowire\SymplifyActionAutowireBundle(),
            // ...
        ];
    }
}

3. Add some dependency for your controller via constructor

// src/AppBundle/Controller/MeetupController.php
namespace AppBundle\Controller;

class MeetupController extends Controller
{
    public function listAction(MeetupRepository $meetupRepository)
    {
        return $this->render('meetup/list.twig', [
            'meetups' => $meetupRepository->findAll()
        ]);
    }
}

And that's it!

For further use, just check Readme for Symplify/ActionAutowire.

Made for you

Missing some feature or found a bug? Let me know. I want to make this package suit your needs and work as best as possible.


Have you find this post useful? Do you want more?

Follow me on Twitter, RSS or support me on GitHub Sponsors.