Skip to content

Commit 49f9575

Browse files
authored
Merge pull request #34 from sensiolabs/issue-10-di
split the service container book chapter
2 parents f9fe733 + 1d46929 commit 49f9575

File tree

9 files changed

+750
-730
lines changed

9 files changed

+750
-730
lines changed

service_container.rst

-730
Large diffs are not rendered by default.

service_container/index.rst

+7
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,10 @@ Service Container
66

77
scopes
88
compiler_passes
9+
import
10+
expression_language
11+
request
12+
optional_dependencies
13+
third_party
14+
tags
15+
debug
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
.. index::
2+
single: DependencyInjection; Debug
3+
single: Service Container; Debug
4+
5+
How to Debug the Service Container & List Services
6+
==================================================
7+
8+
You can find out what services are registered with the container using the
9+
console. To show all services and the class for each service, run:
10+
11+
.. code-block:: bash
12+
13+
$ php app/console debug:container
14+
15+
.. versionadded:: 2.6
16+
Prior to Symfony 2.6, this command was called ``container:debug``.
17+
18+
By default, only public services are shown, but you can also view private services:
19+
20+
.. code-block:: bash
21+
22+
$ php app/console debug:container --show-private
23+
24+
.. note::
25+
26+
If a private service is only used as an argument to just *one* other service,
27+
it won't be displayed by the ``debug:container`` command, even when using
28+
the ``--show-private`` option. See :ref:`Inline Private Services <inlined-private-services>`
29+
for more details.
30+
31+
You can get more detailed information about a particular service by specifying
32+
its id:
33+
34+
.. code-block:: bash
35+
36+
$ php app/console debug:container app.mailer
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
.. index::
2+
single: DependencyInjection; ExpressionLanguage
3+
single: DependencyInjection; Expressions
4+
single: Service Container; ExpressionLanguage
5+
single: Service Container; Expressions
6+
7+
How to Inject Values Based on Complex Expressions
8+
=================================================
9+
10+
The service container also supports an "expression" that allows you to inject
11+
very specific values into a service.
12+
13+
For example, suppose you have a third service (not shown here), called ``mailer_configuration``,
14+
which has a ``getMailerMethod()`` method on it, which will return a string
15+
like ``sendmail`` based on some configuration. Remember that the first argument
16+
to the ``my_mailer`` service is the simple string ``sendmail``:
17+
18+
.. include:: includes/_service_container_my_mailer.rst.inc
19+
20+
But instead of hardcoding this, how could we get this value from the ``getMailerMethod()``
21+
of the new ``mailer_configuration`` service? One way is to use an expression:
22+
23+
.. configuration-block::
24+
25+
.. code-block:: yaml
26+
27+
# app/config/config.yml
28+
services:
29+
my_mailer:
30+
class: AppBundle\Mailer
31+
arguments: ["@=service('mailer_configuration').getMailerMethod()"]
32+
33+
.. code-block:: xml
34+
35+
<!-- app/config/config.xml -->
36+
<?xml version="1.0" encoding="UTF-8" ?>
37+
<container xmlns="http://symfony.com/schema/dic/services"
38+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
39+
xsi:schemaLocation="http://symfony.com/schema/dic/services
40+
http://symfony.com/schema/dic/services/services-1.0.xsd"
41+
>
42+
43+
<services>
44+
<service id="my_mailer" class="AppBundle\Mailer">
45+
<argument type="expression">service('mailer_configuration').getMailerMethod()</argument>
46+
</service>
47+
</services>
48+
</container>
49+
50+
.. code-block:: php
51+
52+
// app/config/config.php
53+
use Symfony\Component\DependencyInjection\Definition;
54+
use Symfony\Component\ExpressionLanguage\Expression;
55+
56+
$container->setDefinition('my_mailer', new Definition(
57+
'AppBundle\Mailer',
58+
array(new Expression('service("mailer_configuration").getMailerMethod()'))
59+
));
60+
61+
To learn more about the expression language syntax, see :doc:`/components/expression_language/syntax`.
62+
63+
In this context, you have access to 2 functions:
64+
65+
``service``
66+
Returns a given service (see the example above).
67+
``parameter``
68+
Returns a specific parameter value (syntax is just like ``service``).
69+
70+
You also have access to the :class:`Symfony\\Component\\DependencyInjection\\ContainerBuilder`
71+
via a ``container`` variable. Here's another example:
72+
73+
.. configuration-block::
74+
75+
.. code-block:: yaml
76+
77+
services:
78+
my_mailer:
79+
class: AppBundle\Mailer
80+
arguments: ["@=container.hasParameter('some_param') ? parameter('some_param') : 'default_value'"]
81+
82+
.. code-block:: xml
83+
84+
<?xml version="1.0" encoding="UTF-8" ?>
85+
<container xmlns="http://symfony.com/schema/dic/services"
86+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
87+
xsi:schemaLocation="http://symfony.com/schema/dic/services
88+
http://symfony.com/schema/dic/services/services-1.0.xsd"
89+
>
90+
91+
<services>
92+
<service id="my_mailer" class="AppBundle\Mailer">
93+
<argument type="expression">container.hasParameter('some_param') ? parameter('some_param') : 'default_value'</argument>
94+
</service>
95+
</services>
96+
</container>
97+
98+
.. code-block:: php
99+
100+
use Symfony\Component\DependencyInjection\Definition;
101+
use Symfony\Component\ExpressionLanguage\Expression;
102+
103+
$container->setDefinition('my_mailer', new Definition(
104+
'AppBundle\Mailer',
105+
array(new Expression(
106+
"container.hasParameter('some_param') ? parameter('some_param') : 'default_value'"
107+
))
108+
));
109+
110+
Expressions can be used in ``arguments``, ``properties``, as arguments with
111+
``configurator`` and as arguments to ``calls`` (method calls).
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
.. index::
2+
single: DependencyInjection; Importing Resources
3+
single: Service Container; Importing Resources
4+
5+
How to Import Configuration Files/Resources
6+
===========================================
7+
8+
.. tip::
9+
10+
In this section, service configuration files are referred to as *resources*.
11+
This is to highlight the fact that, while most configuration resources
12+
will be files (e.g. YAML, XML, PHP), Symfony is so flexible that configuration
13+
could be loaded from anywhere (e.g. a database or even via an external
14+
web service).
15+
16+
The service container is built using a single configuration resource
17+
(``app/config/config.yml`` by default). All other service configuration
18+
(including the core Symfony and third-party bundle configuration) must
19+
be imported from inside this file in one way or another. This gives you absolute
20+
flexibility over the services in your application.
21+
22+
External service configuration can be imported in two different ways. The first
23+
method, commonly used to import other resources, is via the ``imports``
24+
directive. The second method, using dependency injection extensions, is used by
25+
third-party bundles to load the configuration. Read on to learn more about both
26+
methods.
27+
28+
.. index::
29+
single: Service Container; Imports
30+
31+
.. _service-container-imports-directive:
32+
33+
Importing Configuration with ``imports``
34+
----------------------------------------
35+
36+
So far, you've placed your ``app.mailer`` service container definition directly
37+
in the services configuration file (e.g. ``app/config/services.yml``). If your
38+
application ends up having many services, this file becomes huge and hard to
39+
maintain. To avoid this, you can split your service configuration into multiple
40+
service files:
41+
42+
.. configuration-block::
43+
44+
.. code-block:: yaml
45+
46+
# app/config/services/mailer.yml
47+
parameters:
48+
app.mailer.transport: sendmail
49+
50+
services:
51+
app.mailer:
52+
class: AppBundle\Mailer
53+
arguments: ['%app.mailer.transport%']
54+
55+
.. code-block:: xml
56+
57+
<!-- app/config/services/mailer.xml -->
58+
<?xml version="1.0" encoding="UTF-8" ?>
59+
<container xmlns="http://symfony.com/schema/dic/services"
60+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
61+
xsi:schemaLocation="http://symfony.com/schema/dic/services
62+
http://symfony.com/schema/dic/services/services-1.0.xsd">
63+
64+
<parameters>
65+
<parameter key="app.mailer.transport">sendmail</parameter>
66+
</parameters>
67+
68+
<services>
69+
<service id="app.mailer" class="AppBundle\Mailer">
70+
<argument>%app.mailer.transport%</argument>
71+
</service>
72+
</services>
73+
</container>
74+
75+
.. code-block:: php
76+
77+
// app/config/services/mailer.php
78+
use Symfony\Component\DependencyInjection\Definition;
79+
80+
$container->setParameter('app.mailer.transport', 'sendmail');
81+
82+
$container->setDefinition('app.mailer', new Definition(
83+
'AppBundle\Mailer',
84+
array('%app.mailer.transport%')
85+
));
86+
87+
The definition itself hasn't changed, only its location. To make the service
88+
container load the definitions in this resource file, use the ``imports`` key
89+
in any already loaded resource (e.g. ``app/config/services.yml`` or
90+
``app/config/config.yml``):
91+
92+
.. configuration-block::
93+
94+
.. code-block:: yaml
95+
96+
# app/config/services.yml
97+
imports:
98+
- { resource: services/mailer.yml }
99+
100+
.. code-block:: xml
101+
102+
<!-- app/config/services.xml -->
103+
<?xml version="1.0" encoding="UTF-8" ?>
104+
<container xmlns="http://symfony.com/schema/dic/services"
105+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
106+
xsi:schemaLocation="http://symfony.com/schema/dic/services
107+
http://symfony.com/schema/dic/services/services-1.0.xsd">
108+
109+
<imports>
110+
<import resource="services/mailer.xml"/>
111+
</imports>
112+
</container>
113+
114+
.. code-block:: php
115+
116+
// app/config/services.php
117+
$loader->import('services/mailer.php');
118+
119+
The ``resource`` location, for files, is either a relative path from the
120+
current file or an absolute path.
121+
122+
.. include:: /components/dependency_injection/_imports-parameters-note.rst.inc
123+
124+
.. index::
125+
single: Service Container; Extension configuration
126+
127+
.. _service-container-extension-configuration:
128+
129+
Importing Configuration via Container Extensions
130+
------------------------------------------------
131+
132+
Third-party bundle container configuration, including Symfony core services,
133+
are usually loaded using another method that's more flexible and easy to
134+
configure in your application.
135+
136+
Internally, each bundle defines its services like you've seen so far. However,
137+
these files aren't imported using the ``import`` directive. These bundles use a
138+
*dependency injection extension* to load the files. The extension also allows
139+
bundles to provide configuration to dynamically load some services.
140+
141+
Take the FrameworkBundle - the core Symfony Framework bundle - as an
142+
example. The presence of the following code in your application configuration
143+
invokes the service container extension inside the FrameworkBundle:
144+
145+
.. configuration-block::
146+
147+
.. code-block:: yaml
148+
149+
# app/config/config.yml
150+
framework:
151+
secret: xxxxxxxxxx
152+
form: true
153+
# ...
154+
155+
.. code-block:: xml
156+
157+
<!-- app/config/config.xml -->
158+
<?xml version="1.0" encoding="UTF-8" ?>
159+
<container xmlns="http://symfony.com/schema/dic/services"
160+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
161+
xmlns:framework="http://symfony.com/schema/dic/symfony"
162+
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd
163+
http://symfony.com/schema/dic/symfony http://symfony.com/schema/dic/symfony/symfony-1.0.xsd"
164+
>
165+
166+
<framework:config secret="xxxxxxxxxx">
167+
<framework:form />
168+
169+
<!-- ... -->
170+
</framework>
171+
</container>
172+
173+
.. code-block:: php
174+
175+
// app/config/config.php
176+
$container->loadFromExtension('framework', array(
177+
'secret' => 'xxxxxxxxxx',
178+
'form' => array(),
179+
180+
// ...
181+
));
182+
183+
When the resources are parsed, the container looks for an extension that
184+
can handle the ``framework`` directive. The extension in question, which lives
185+
in the FrameworkBundle, is invoked and the service configuration for the
186+
FrameworkBundle is loaded.
187+
188+
The settings under the ``framework`` directive (e.g. ``form: true``) indicate
189+
that the extension should load all services related to the Form component. If
190+
form was disabled, these services wouldn't be loaded and Form integration would
191+
not be available.
192+
193+
When installing or configuring a bundle, see the bundle's documentation for
194+
how the services for the bundle should be installed and configured. The options
195+
available for the core bundles can be found inside the :doc:`Reference Guide </reference/index>`.
196+
197+
.. seealso::
198+
199+
If you want to use dependency injection extensions in your own shared
200+
bundles and provide user friendly configuration, take a look at the
201+
":doc:`/cookbook/bundles/extension`" cookbook recipe.

0 commit comments

Comments
 (0)