Cover of the book Symfony 5: The Fast Track

Symfony 5: The Fast Track is the best book to learn modern Symfony development, from zero to production. +300 pages in full color showing how to combine Symfony with Docker, APIs, queues & async tasks, Webpack, Single-Page Applications, etc.

Buy printed version

New in Symfony 3.4: Local service binding

Contributed by
Guilhem Niot
in #22187.

The configuration of services in Symfony applications has been greatly simplified in recent versions. Thanks to autowiring you can create and use services without having to actually configure most of them.

However, there's an exception to that: you can't autowire scalar arguments (e.g. strings and numbers). For example, if three of your services need the value of the kernel.project_dir parameter, you need to do this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
services:
    _defaults:
        autowire: true
        autoconfigure: true
        public: false

    App\Some\Service1:
        $projectDir: '%kernel.project_dir%'

    App\Some\Service2:
        $projectDir: '%kernel.project_dir%'

    App\Some\Service3:
        $projectDir: '%kernel.project_dir%'

In Symfony 3.4, to avoid repetitions like this, we introduced local service binding. First, this new feature allows to define the scalar arguments once and apply them to any service defined/created in that file. That's why the previous example looks like this in Symfony 3.4:

1
2
3
4
5
6
7
services:
    _defaults:
        autowire: true
        autoconfigure: true
        public: false
        bind:
            $projectDir: '%kernel.project_dir%'

That's all! The Service1, Service2 and Service3 don't have to be defined explicitly because autowiring is being used and you already defined the value of the $projectDir scalar argument for all the services created/defined in this file. If you prefer XML configuration, use this notation to bind parameters:

1
2
3
4
5
<services>
    <defaults autowire="true" autoconfigure="true" public="false">
        <bind key="$projectDir">%kernel.project_dir%</bind>
    </defaults>
</services>

Local binding is also useful to explicitly define the services to inject for some service arguments. This is required for example when you have multiple services related to the same class:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# when services created/defined in this file inject 'BarInterface',
# use the '@normal_bar_service' ...
services:
    _defaults:
        bind:
            BarInterface: '@normal_bar_service'

    # ... except for this particular service, which uses a different service
    Foo:
        bind:
            BarInterface: '@special_bar_service'
Help the Symfony project!

As with any Open-Source project, contributing code or documentation is the most common way to help, but we also have a wide range of sponsoring opportunities.

Comments

THIS is awesome and fixes lots of hacks we had to do when using autowiring! 👍👍
That's a really great new but what about a folder who contain 10 classes (like controllers or actions) and only 1 class need the argument?

I'm thinking about a "placeholder" injection in the way that if the class define the name of the key into the __construct or into his methods, the container can inject the value no matter what class requires it :thinking:
Great addition! Thanks.
@Javier missed % at the end of each %kernel.project_dir parameter.
@Yonel fixed now. Thanks for the heads up!
This is awesome!
Great feature, thanks a lot guys
Amazing little improvement :)
A w e s o m e!
Good job guys !
Well done, exactly the thing which I am waiting for.
Nice addition!! Good job!
This is great! Already needed this

Comments are closed.

To ensure that comments stay relevant, they are closed for old posts.