@@ -12,9 +12,10 @@ This entry is all about scopes, a somewhat advanced topic related to the
1212
1313 If you are trying to inject the ``request `` service, the simple solution
1414 is to inject the ``request_stack `` service instead and access the current
15- Request by calling the ``getCurrentRequest() `` method. The rest of this
16- entry talks about scopes in a theoretical and more advanced way. If you're
17- dealing with scopes for the ``request `` service, simply inject ``request_stack ``.
15+ Request by calling the ``getCurrentRequest() `` method (see :ref: `book-container-request-stack `).
16+ The rest of this entry talks about scopes in a theoretical and more advanced
17+ way. If you're dealing with scopes for the ``request `` service, simply
18+ inject ``request_stack ``.
1819
1920Understanding Scopes
2021--------------------
@@ -34,8 +35,8 @@ also defines a third scope: ``request``. This scope is tied to the request,
3435meaning a new instance is created for each subrequest and is unavailable
3536outside the request (for instance in the CLI).
3637
37- The Example: client Scope
38- ~~~~~~~~~~~~~~~~~~~~~~~~~
38+ An Example: client Scope
39+ ~~~~~~~~~~~~~~~~~~~~~~~~
3940
4041Other than the ``request `` service (which has a simple solution, see the
4142above note), no services in the default Symfony2 container belong to any
@@ -64,14 +65,14 @@ when compiling the container. Read the sidebar below for more details.
6465 from it, such as what the "sender" address should be. You add it as a
6566 constructor argument. Let's look at why this presents a problem:
6667
67- * When requesting ``my_mailer ``, an instance of ``my_mailer `` (let's call
68- it *MailerA *) is created and the ``client_configuration `` service (let's
69- call it *ConfigurationA *) is passed to it. Life is good!
68+ * When requesting ``my_mailer ``, an instance of ``my_mailer `` (called
69+ *MailerA * here ) is created and the ``client_configuration `` service (
70+ called *ConfigurationA * here ) is passed to it. Life is good!
7071
7172 * Your application now needs to do something with another client, and
7273 you've architected your application in such a way that you handle this
7374 by entering a new ``client_configuration `` scope and setting a new
74- ``client_configuration `` service into the container. Let's call this
75+ ``client_configuration `` service into the container. Call this
7576 *ConfigurationB *.
7677
7778 * Somewhere in your application, you once again ask for the ``my_mailer ``
@@ -96,14 +97,14 @@ Using a Service from a narrower Scope
9697
9798There are several solutions to the scope problem:
9899
99- * Use setter injection if the dependency is "synchronized"; (see
100+ * A) Use setter injection if the dependency is "synchronized"; (see
100101 :ref: `using-synchronized-service `).
101102
102- * Put your service in the same scope as the dependency (or a narrower one). If
103+ * B) Put your service in the same scope as the dependency (or a narrower one). If
103104 you depend on the ``client_configuration `` service, this means putting your
104105 new service in the ``client `` scope (see :ref: `changing-service-scope `);
105106
106- * Pass the entire container to your service and retrieve your dependency from
107+ * C) Pass the entire container to your service and retrieve your dependency from
107108 the container each time you need it to be sure you have the right instance
108109 -- your service can live in the default ``container `` scope (see
109110 :ref: `passing-container `);
@@ -112,15 +113,15 @@ Each scenario is detailed in the following sections.
112113
113114.. _using-synchronized-service :
114115
115- Using a synchronized Service
116- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
116+ A) Using a synchronized Service
117+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
117118
118119.. versionadded :: 2.3
119120 Synchronized services are new in Symfony 2.3.
120121
121- Injecting the container or setting your service to a narrower scope have
122+ Both injecting the container and setting your service to a narrower scope have
122123drawbacks. Assume first that the ``client_configuration `` service has been
123- marked as " synchronized" :
124+ marked as `` synchronized `` :
124125
125126.. configuration-block ::
126127
@@ -132,17 +133,25 @@ marked as "synchronized":
132133 class : Acme\HelloBundle\Client\ClientConfiguration
133134 scope : client
134135 synchronized : true
136+ # ...
135137
136138 .. code-block :: xml
137139
138140 <!-- app/config/config.xml -->
139141 <?xml version =" 1.0" encoding =" UTF-8" ?>
140142 <container xmlns =" http://symfony.com/schema/dic/services"
141143 xmlns : xsi =" http://www.w3.org/2001/XMLSchema-instance"
142- xsi : schemaLocation =" http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd" >
144+ xsi : schemaLocation =" http://symfony.com/schema/dic/services
145+ http://symfony.com/schema/dic/services/services-1.0.xsd"
146+ >
143147
144148 <services >
145- <service id =" client_configuration" scope =" client" synchronized =" true" class =" Acme\HelloBundle\Client\ClientConfiguration" />
149+ <service
150+ id =" client_configuration"
151+ scope =" client"
152+ synchronized =" true"
153+ class =" Acme\HelloBundle\Client\ClientConfiguration"
154+ />
146155 </services >
147156 </container >
148157
@@ -151,13 +160,13 @@ marked as "synchronized":
151160 // app/config/config.php
152161 use Symfony\Component\DependencyInjection\Definition;
153162
154- $defn = new Definition(
163+ $definition = new Definition(
155164 'Acme\HelloBundle\Client\ClientConfiguration',
156165 array()
157166 );
158- $defn ->setScope('client');
159- $defn ->setSynchronized(true);
160- $container->setDefinition('client_configuration', $defn );
167+ $definition ->setScope('client');
168+ $definition ->setSynchronized(true);
169+ $container->setDefinition('client_configuration', $definition );
161170
162171 Now, if you inject this service using setter injection, there are no drawbacks
163172and everything works without any special code in your service or in your definition::
@@ -202,20 +211,25 @@ your code. This should also be taken into account when declaring your service:
202211
203212 # src/Acme/HelloBundle/Resources/config/services.yml
204213 services :
205- greeting_card_manager :
206- class : Acme\HelloBundle\Mail\GreetingCardManager
214+ my_mailer :
215+ class : Acme\HelloBundle\Mail\Mailer
207216 calls :
208217 - [setClientConfiguration, ['@?client_configuration=']]
209218
210219 .. code-block :: xml
211220
212221 <!-- src/Acme/HelloBundle/Resources/config/services.xml -->
213222 <services >
214- <service id =" greeting_card_manager "
215- class =" Acme\HelloBundle\Mail\GreetingCardManager "
223+ <service id =" my_mailer "
224+ class =" Acme\HelloBundle\Mail\Mailer "
216225 >
217226 <call method =" setClientConfiguration" >
218- <argument type =" service" id =" client_configuration" on-invalid =" null" strict =" false" />
227+ <argument
228+ type =" service"
229+ id =" client_configuration"
230+ on-invalid =" null"
231+ strict =" false"
232+ />
219233 </call >
220234 </service >
221235 </services >
@@ -227,37 +241,43 @@ your code. This should also be taken into account when declaring your service:
227241 use Symfony\Component\DependencyInjection\ContainerInterface;
228242
229243 $definition = $container->setDefinition(
230- 'greeting_card_manager ',
231- new Definition('Acme\HelloBundle\Mail\GreetingCardManager ')
244+ 'my_mailer ',
245+ new Definition('Acme\HelloBundle\Mail\Mailer ')
232246 )
233247 ->addMethodCall('setClientConfiguration', array(
234- new Reference('client_configuration', ContainerInterface::NULL_ON_INVALID_REFERENCE, false)
248+ new Reference(
249+ 'client_configuration',
250+ ContainerInterface::NULL_ON_INVALID_REFERENCE,
251+ false
252+ )
235253 ));
236254
237255 .. _changing-service-scope :
238256
239- Changing the Scope of your Service
240- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
257+ B) Changing the Scope of your Service
258+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
241259
242- Changing the scope of a service should be done in its definition:
260+ Changing the scope of a service should be done in its definition. This example
261+ assumes that the ``Mailer `` class has a ``__construct `` function whose first
262+ argument is the ``ClientConfiguration `` object:
243263
244264.. configuration-block ::
245265
246266 .. code-block :: yaml
247267
248268 # src/Acme/HelloBundle/Resources/config/services.yml
249269 services :
250- greeting_card_manager :
251- class : Acme\HelloBundle\Mail\GreetingCardManager
270+ my_mailer :
271+ class : Acme\HelloBundle\Mail\Mailer
252272 scope : client
253273 arguments : [@client_configuration]
254274
255275 .. code-block :: xml
256276
257277 <!-- src/Acme/HelloBundle/Resources/config/services.xml -->
258278 <services >
259- <service id =" greeting_card_manager "
260- class =" Acme\HelloBundle\Mail\GreetingCardManager "
279+ <service id =" my_mailer "
280+ class =" Acme\HelloBundle\Mail\Mailer "
261281 scope =" client"
262282 />
263283 <argument type =" service" id =" client_configuration" />
@@ -269,17 +289,17 @@ Changing the scope of a service should be done in its definition:
269289 use Symfony\Component\DependencyInjection\Definition;
270290
271291 $definition = $container->setDefinition(
272- 'greeting_card_manager ',
292+ 'my_mailer ',
273293 new Definition(
274- 'Acme\HelloBundle\Mail\GreetingCardManager ',
294+ 'Acme\HelloBundle\Mail\Mailer ',
275295 array(new Reference('client_configuration'),
276296 ))
277297 )->setScope('client');
278298
279299 .. _passing-container :
280300
281- Passing the Container as a Dependency of your Service
282- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
301+ C) Passing the Container as a Dependency of your Service
302+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
283303
284304Setting the scope to a narrower one is not always possible (for instance, a
285305twig extension must be in the ``container `` scope as the Twig environment
0 commit comments