Skip to content

[#3022] Adding service container expression language details #3232

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Nov 29, 2013
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions book/includes/_service_container_my_mailer.rst.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
.. configuration-block::

.. code-block:: yaml

# app/config/config.yml
services:
my_mailer:
class: Acme\HelloBundle\Mailer
arguments: [sendmail]

.. code-block:: xml

<!-- app/config/config.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
http://symfony.com/schema/dic/services/services-1.0.xsd"
>

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer

<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
        http://symfony.com/schema/dic/services/services-1.0.xsd"
>

<services>
<service id="my_mailer" class="Acme\HelloBundle\Mailer">
<argument>sendmail</argument>
</service>
</services>
</container>

.. code-block:: php

// app/config/config.php
use Symfony\Component\DependencyInjection\Definition;

$container->setDefinition('my_mailer', new Definition(
'Acme\HelloBundle\Mailer',
array('sendmail')
));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

always add a new line at the end

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm, no. This can cause problems when including :)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't think so. Why should this cause problems?

142 changes: 108 additions & 34 deletions book/service_container.rst
Original file line number Diff line number Diff line change
Expand Up @@ -103,40 +103,7 @@ for you. In order for this to work, you must *teach* the container how to
create the ``Mailer`` service. This is done via configuration, which can
be specified in YAML, XML or PHP:

.. configuration-block::

.. code-block:: yaml

# app/config/config.yml
services:
my_mailer:
class: Acme\HelloBundle\Mailer
arguments: [sendmail]

.. code-block:: xml

<!-- app/config/config.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 http://symfony.com/schema/dic/services/services-1.0.xsd">

<services>
<service id="my_mailer" class="Acme\HelloBundle\Mailer">
<argument>sendmail</argument>
</service>
</services>
</container>

.. code-block:: php

// app/config/config.php
use Symfony\Component\DependencyInjection\Definition;

$container->setDefinition('my_mailer', new Definition(
'Acme\HelloBundle\Mailer',
array('sendmail')
));
.. include includes/_service_container_my_mailer.rst.inc

.. note::

Expand Down Expand Up @@ -660,6 +627,113 @@ service needs the ``my_mailer`` service in order to function. When you define
this dependency in the service container, the container takes care of all
the work of instantiating the classes.

Using the Expression Language
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

missing versionadded directive

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah, good catch :)

.. versionadded:: 2.4
The Expression Language functionality was introduced in Symfony 2.4.

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

For example, suppose you have a third service (not shown here), called ``mailer_configuration``,
which has a ``getMailerMethod()`` method on it, which will return a string
like ``sendmail`` based on some configuration. Remember that the first argument
to the ``my_mailer`` service is the simple string ``sendmail``:

.. include includes/_service_container_my_mailer.rst.inc
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why did you include the config again, instead of adding a reference in case they forgot?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think seeing the 2 examples side-by-side will be much more clear


But instead of hardcoding this, how could we get this value from the ``getMailerMethod()``
of the new ``mailer_configuration`` service? One way is to use an expression:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

one way? You mean, "the only way" (besides using parameters, which is already explained)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The other way would be to inject mailer_configuration and then fetch the value. And depending on what you're doing in the mailer (what you need exactly), this might make sense.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it also depends whether your configuration is mutable at runtime or no (getting it with an expression will not allow you to get an updated setting, while you can when injecting the configuration if you fetch the value each time you need it)


.. configuration-block::

.. code-block:: yaml

# app/config/config.yml
services:
my_mailer:
class: Acme\HelloBundle\Mailer
arguments: ["@=service('mailer_configuration').getMailerMethod()"]

.. code-block:: xml

<!-- app/config/config.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
http://symfony.com/schema/dic/services/services-1.0.xsd"
>

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see my comment in the example above

<services>
<service id="my_mailer" class="Acme\HelloBundle\Mailer">
<argument type="expression">service('mailer_configuration').getMailerMethod()</argument>
</service>
</services>
</container>

.. code-block:: php

// app/config/config.php
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\ExpressionLanguage\Expression;

$container->setDefinition('my_mailer', new Definition(
'Acme\HelloBundle\Mailer',
array(new Expression('service("mailer_configuration").getMailerMethod()'))
));

To learn more about the expression language syntax, see :doc:`/components/expression_language/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 :class:`Symfony\\Component\\DependencyInjection\\ContainerBuilder`
via a ``container`` variable. Here's another example:

.. configuration-block::

.. code-block:: yaml

services:
my_mailer:
class: Acme\HelloBundle\Mailer
arguments: ["@=container.hasParameter('some_param') ? parameter('some_param') : 'default_value'"]

.. code-block:: 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
http://symfony.com/schema/dic/services/services-1.0.xsd"
>

<services>
<service id="my_mailer" class="Acme\HelloBundle\Mailer">
<argument type="expression">@=container.hasParameter('some_param') ? parameter('some_param') : 'default_value'</argument>
</service>
</services>
</container>

.. code-block:: php

use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\ExpressionLanguage\Expression;

$container->setDefinition('my_mailer', new Definition(
'Acme\HelloBundle\Mailer',
array(new Expression(
"@=container.hasParameter('some_param') ? parameter('some_param') : 'default_value'"
))
));

Expressions can be used in ``parameters``, ``arguments``, ``properties``,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

expressions cannot be used in parameters (see symfony/symfony#9658 )

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would really be nice if they could be! AS I said in the issue it works just as advertised if I remove the expression from the parameters array in dumped container.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@wouterj good catch - it almost looks like it's supported in YamlFileLoader, but not actually :). Fixed at sha: 4738c75

as arguments with ``configurator`` and as arguments to ``calls`` (method calls).

Optional Dependencies: Setter Injection
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Expand Down