Ryan Weaver
Contributed by Ryan Weaver in #26658

Allow binding scalar values to controllers

When using service autowiring, the _defaults.bind option allows to bind arguments by name or type. For example, you can define the value of $projectDir once in your app and every service that uses a constructor argument with that name will use its value:

1
2
3
4
5
# config/services.yaml
services:
    _defaults:
        bind:
            $projectDir: '%kernel.project_dir%'

However, if some controller action defines a $projectDir argument, this configuration doesn't apply to it and the argument is not autowired:

1
2
3
4
5
6
7
/**
 * @Route("/do-something")
 */
public function somethingAction($projectDir)
{
    // the $projectDir argument is not given the configured value
}

In controllers, you needed to use the $this->getParameter('kernel.project_dir') shortcut or pass the value through the controller's __construct() method. This behavior didn't provide a consistent experience (service constructor binding behaved differently than controller action binding) and it was the last rough edge about autowiring.

That's why in Symfony 4.1 you can bind scalar values to controller arguments. Define the binding as usual in _defaults.bind and then add the arguments to the controller actions (there's no need to define a constructor method for them).

Service decoration autowiring

Kévin Dunglas
Contributed by Kévin Dunglas in #25631

Service decoration allows to change the behavior of a service without affecting to the other uses of the original service. When decorating services, the config requires to pass the decorated service as an argument using a special naming syntax:

1
2
3
4
5
6
7
8
9
10
11
# config/services.yaml
services:
    # this is the service you want to decorate
    App\Mailer: ~

    App\DecoratingMailer:
        decorates: App\Mailer

        # you must pass the original service as an argument, and its name
        # is: "decorating service ID" + ".inner"
        arguments: ['@App\DecoratingMailer.inner']

Although explicit, this config looks like an internal Symfony detail. That's why in Symfony 4.1 the inner service is automatically autowired if possible. This is the new config for the same example as before:

1
2
3
4
5
6
# config/services.yaml
services:
    App\Mailer: ~

    App\DecoratingMailer:
        decorates: App\Mailer

The automatic configuration of the decorated service is done when the following conditions are met:

  1. The decorating service is autowired;
  2. The constructor of the decorating service has only one argument of the type of the decorated service.
Published in #Living on the edge