Flag of Ukraine
SymfonyCasts stands united with the people of Ukraine

Return to symfonycasts.com

Categories

Subscribe

Subscribe via RSS or know about updates first by getting on the newsletter.

Who we are

Blog > Symfony Service Expressions: Do things you thought Impossible
Edit

Symfony Service Expressions: Do things you thought Impossible

By weaverryan and 1 other | Symfony | May 2nd 2015 |

Symfony Service Expressions: Do things you thought Impossible

Did you know you can do this with Symfony's service container?

# app/config/services.yml
services:
    app_user_manager:
        class: AppBundle\Service\UserManager
        arguments:
            - "@=service('doctrine').getRepository('AppBundle:User')"
            # ... other arguments

The @= means that you're using Symfony's Expression Language, which let's you mix dynamic logic into your normally-static service definitions.

Normally, if you want to inject a repository, you need to register it as a service first, using a factory. And while that's fine (and probably better if you're injecting the factory a lot), using the expression language is well, kinda cool.

In the compiled container, it beautifully generates with exactly the code you would've used directly::

// app/cache/appDevDebugProjectContainer.php
protected function getAppUserManagerService()
{
    return $this->services['app_user_manager'] = new AppBundle\Service\UserManager(
        $this->get('doctrine')->getRepository('AppBundle:User')
    );
}

And from an object-oriented, dependency-injection perspective, that feels good, and makes up for the slightly-wonky service expression syntax. The expression language isn't new, but I think a lot of people don't really know its power.

Passing Database Configuration as a Service Argument

How about reading configuration from the database and passing those as arguments? Normally, you'd need create a service that reads the configuration and inject the whole thing in:

services:
    # some service that can read configuration values from the database
    app_configuration_reader:
        class: AppBundle\Config\ConfigurationReader
        arguments: ["@doctrine.orm_entity_manager"]

    # some service that helps email things
    app_mailer:
        class: AppBundle\Service\Mailer:
        arguments:
            - "@mailer"
            - "@app_configuration_reader"

Suppose our app_mailer service needs some database configuration value called email_from_username, which it uses as the from address when sending emails. To accomplish this, you'd usually need inject the entire app_configuration_reader service (the service you create to read config values). But with expressions, you can inject only what you need:

    services:
        # some service that can read configuration values from the database
        app_configuration_reader:
            class: AppBundle\Config\ConfigurationReader
            arguments: ["@doctrine.orm_entity_manager"]

        # some service that helps email things
        app_mailer:
            class: AppBundle\Service\Mailer:
            arguments:
                - "@mailer"
                - "@=service('app_configuration_reader').get('email_from_username')"

And in addition to the service() function you also have a parameter function, and all the normal syntax (including if statement logic) from the Expression Language. See Using the Expression Language for a few more details about using it with services.

Now, go do something cool with this :).

userVoice