How to Inject Values Based on Complex Expressions

The service container also supports an “expression” that allows you to inject very specific values into a service.

For example, suppose you have a service (not shown here), called App\Mail\MailerConfiguration, which has a getMailerMethod() method on it. This returns a string - like sendmail based on some configuration.

Suppose that you want to pass the result of this method as a constructor argument to another service: App\Mailer. One way to do this is with an expression:

  • YAML
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    # config/services.yaml
    services:
        # ...
    
        App\Mail\MailerConfiguration: ~
    
        App\Mailer:
            # the '@=' prefix is required when using expressions for arguments in YAML files
            arguments: ['@=service("App\\Mail\\MailerConfiguration").getMailerMethod()']
            # when using double-quoted strings, the backslash needs to be escaped twice (see https://yaml.org/spec/1.2/spec.html#id2787109)
            # arguments: ["@=service('App\\\\Mail\\\\MailerConfiguration').getMailerMethod()"]
    
  • XML
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    <!-- config/services.xml -->
    <?xml version="1.0" encoding="UTF-8" ?>
    <container xmlns="http://symfony.com/schema/dic/services"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://symfony.com/schema/dic/services
            https://symfony.com/schema/dic/services/services-1.0.xsd">
    
        <services>
            <!-- ... -->
    
            <service id="App\Mail\MailerConfiguration"></service>
    
            <service id="App\Mailer">
                <argument type="expression">service('App\\Mail\\MailerConfiguration').getMailerMethod()</argument>
            </service>
        </services>
    </container>
    
  • PHP
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    // config/services.php
    namespace Symfony\Component\DependencyInjection\Loader\Configurator;
    
    use App\Mail\MailerConfiguration;
    use App\Mailer;
    
    return function(ContainerConfigurator $configurator) {
        // ...
    
        $services->set(MailerConfiguration::class);
    
        $services->set(Mailer::class)
            ->args([expr("service('App\\Mail\\MailerConfiguration').getMailerMethod()")]);
    };
    

To learn more about the expression language syntax, see The Expression Syntax.

In this context, you have access to 2 functions:

service
Returns a given service (see the example above).
parameter
Returns a specific parameter value (syntax is just like service).

You also have access to the Container via a container variable. Here’s another example:

  • YAML
    1
    2
    3
    4
    5
    # config/services.yaml
    services:
        App\Mailer:
            # the '@=' prefix is required when using expressions for arguments in YAML files
            arguments: ["@=container.hasParameter('some_param') ? parameter('some_param') : 'default_value'"]
    
  • XML
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    <!-- config/services.xml -->
    <?xml version="1.0" encoding="UTF-8" ?>
    <container xmlns="http://symfony.com/schema/dic/services"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://symfony.com/schema/dic/services
            https://symfony.com/schema/dic/services/services-1.0.xsd">
    
        <services>
            <service id="App\Mailer">
                <argument type="expression">container.hasParameter('some_param') ? parameter('some_param') : 'default_value'</argument>
            </service>
        </services>
    </container>
    
  • PHP
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    // config/services.php
    namespace Symfony\Component\DependencyInjection\Loader\Configurator;
    
    use App\Mailer;
    
    return function(ContainerConfigurator $configurator) {
        $services = $configurator->services();
    
        $services->set(Mailer::class)
            ->args([expr("container.hasParameter('some_param') ? parameter('some_param') : 'default_value'")]);
    };
    

Expressions can be used in arguments, properties, as arguments with configurator and as arguments to calls (method calls).