44How to Work with Scopes
55=======================
66
7- This entry is all about scopes, a somewhat advanced topic related to the
7+ This article is all about scopes, a somewhat advanced topic related to the
88:doc: `/book/service_container `. If you've ever gotten an error mentioning
9- "scopes" when creating services, then this entry is for you.
9+ "scopes" when creating services, then this article is for you.
1010
1111.. note ::
1212
@@ -25,10 +25,11 @@ The scope of a service controls how long an instance of a service is used
2525by the container. The DependencyInjection component provides two generic
2626scopes:
2727
28- - ``container `` (the default one): The same instance is used each time you
29- request it from this container.
28+ ``container `` (the default one):
29+ The same instance is used each time you ask for it from this container.
3030
31- - ``prototype ``: A new instance is created each time you request the service.
31+ ``prototype ``:
32+ A new instance is created each time you ask for the service.
3233
3334The
3435:class: `Symfony\\ Component\\ HttpKernel\\ DependencyInjection\\ ContainerAwareHttpKernel `
@@ -40,9 +41,9 @@ An Example: Client Scope
4041~~~~~~~~~~~~~~~~~~~~~~~~
4142
4243Other than the ``request `` service (which has a simple solution, see the
43- above note), no services in the default Symfony2 container belong to any
44+ above note), no services in the default Symfony container belong to any
4445scope other than ``container `` and ``prototype ``. But for the purposes of
45- this entry , imagine there is another scope ``client `` and a service ``client_configuration ``
46+ this article , imagine there is another scope ``client `` and a service ``client_configuration ``
4647that belongs to it. This is not a common situation, but the idea is that
4748you may enter and exit multiple ``client `` scopes during a request, and each
4849has its own ``client_configuration `` service.
@@ -71,7 +72,7 @@ when compiling the container. Read the sidebar below for more details.
7172 called *ConfigurationA * here) is passed to it. Life is good!
7273
7374 * Your application now needs to do something with another client, and
74- you've architected your application in such a way that you handle this
75+ you've designed your application in such a way that you handle this
7576 by entering a new ``client_configuration `` scope and setting a new
7677 ``client_configuration `` service into the container. Call this
7778 *ConfigurationB *.
@@ -96,16 +97,13 @@ when compiling the container. Read the sidebar below for more details.
9697Using a Service from a Narrower Scope
9798-------------------------------------
9899
99- There are several solutions to the scope problem:
100+ There are two solutions to the scope problem:
100101
101- * A) Use setter injection if the dependency is ``synchronized `` (see
102- :ref: `using-synchronized-service `);
103-
104- * B) Put your service in the same scope as the dependency (or a narrower one). If
102+ * A) Put your service in the same scope as the dependency (or a narrower one). If
105103 you depend on the ``client_configuration `` service, this means putting your
106104 new service in the ``client `` scope (see :ref: `changing-service-scope `);
107105
108- * C ) Pass the entire container to your service and retrieve your dependency from
106+ * B ) Pass the entire container to your service and retrieve your dependency from
109107 the container each time you need it to be sure you have the right instance
110108 -- your service can live in the default ``container `` scope (see
111109 :ref: `passing-container `).
@@ -114,151 +112,15 @@ Each scenario is detailed in the following sections.
114112
115113.. _using-synchronized-service :
116114
117- A) Using a Synchronized Service
118- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
119-
120- .. versionadded :: 2.3
121- Synchronized services were introduced in Symfony 2.3.
122-
123- Both injecting the container and setting your service to a narrower scope have
124- drawbacks. Assume first that the ``client_configuration `` service has been
125- marked as ``synchronized ``:
126-
127- .. configuration-block ::
128-
129- .. code-block :: yaml
130-
131- # app/config/config.yml
132- services :
133- client_configuration :
134- class : AppBundle\Client\ClientConfiguration
135- scope : client
136- synchronized : true
137- synthetic : true
138- # ...
139-
140- .. code-block :: xml
141-
142- <!-- app/config/config.xml -->
143- <?xml version =" 1.0" encoding =" UTF-8" ?>
144- <container xmlns =" http://symfony.com/schema/dic/services"
145- xmlns : xsi =" http://www.w3.org/2001/XMLSchema-instance"
146- xsi : schemaLocation =" http://symfony.com/schema/dic/services
147- http://symfony.com/schema/dic/services/services-1.0.xsd"
148- >
149-
150- <services >
151- <service
152- id =" client_configuration"
153- scope =" client"
154- synchronized =" true"
155- synthetic =" true"
156- class =" AppBundle\Client\ClientConfiguration"
157- />
158- </services >
159- </container >
160-
161- .. code-block :: php
162-
163- // app/config/config.php
164- use Symfony\Component\DependencyInjection\Definition;
165-
166- $definition = new Definition(
167- 'AppBundle\Client\ClientConfiguration',
168- array()
169- );
170- $definition->setScope('client');
171- $definition->setSynchronized(true);
172- $definition->setSynthetic(true);
173- $container->setDefinition('client_configuration', $definition);
174-
175- Now, if you inject this service using setter injection, there are no drawbacks
176- and everything works without any special code in your service or in your definition::
177-
178- // src/AppBundle/Mail/Mailer.php
179- namespace AppBundle\Mail;
180-
181- use AppBundle\Client\ClientConfiguration;
182-
183- class Mailer
184- {
185- protected $clientConfiguration;
186-
187- public function setClientConfiguration(ClientConfiguration $clientConfiguration = null)
188- {
189- $this->clientConfiguration = $clientConfiguration;
190- }
191-
192- public function sendEmail()
193- {
194- if (null === $this->clientConfiguration) {
195- // throw an error?
196- }
197-
198- // ... do something using the client configuration here
199- }
200- }
201-
202- Whenever the ``client `` scope is active, the service container will
203- automatically call the ``setClientConfiguration() `` method when the
204- ``client_configuration `` service is set in the container.
205-
206- You might have noticed that the ``setClientConfiguration() `` method accepts
207- ``null `` as a valid value for the ``client_configuration `` argument. That's
208- because when leaving the ``client `` scope, the ``client_configuration `` instance
209- can be ``null ``. Of course, you should take care of this possibility in
210- your code. This should also be taken into account when declaring your service:
211-
212- .. configuration-block ::
213-
214- .. code-block :: yaml
215-
216- # app/config/services.yml
217- services :
218- my_mailer :
219- class : AppBundle\Mail\Mailer
220- calls :
221- - [setClientConfiguration, ["@?client_configuration="]]
222-
223- .. code-block :: xml
224-
225- <!-- app/config/services.xml -->
226- <services >
227- <service id =" my_mailer"
228- class =" AppBundle\Mail\Mailer"
229- >
230- <call method =" setClientConfiguration" >
231- <argument
232- type =" service"
233- id =" client_configuration"
234- on-invalid =" null"
235- strict =" false"
236- />
237- </call >
238- </service >
239- </services >
240-
241- .. code-block :: php
242-
243- // app/config/services.php
244- use Symfony\Component\DependencyInjection\Definition;
245- use Symfony\Component\DependencyInjection\ContainerInterface;
115+ .. note ::
246116
247- $definition = $container->setDefinition(
248- 'my_mailer',
249- new Definition('AppBundle\Mail\Mailer')
250- )
251- ->addMethodCall('setClientConfiguration', array(
252- new Reference(
253- 'client_configuration',
254- ContainerInterface::NULL_ON_INVALID_REFERENCE,
255- false
256- )
257- ));
117+ Prior to Symfony 2.7, there was another alternative based on ``synchronized ``
118+ services. However, these kind of services have been deprecated starting from
119+ Symfony 2.7.
258120
259121.. _changing-service-scope :
260122
261- B ) Changing the Scope of your Service
123+ A ) Changing the Scope of your Service
262124~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
263125
264126Changing the scope of a service should be done in its definition. This example
@@ -302,7 +164,7 @@ argument is the ``ClientConfiguration`` object:
302164
303165 .. _passing-container :
304166
305- C ) Passing the Container as a Dependency of your Service
167+ B ) Passing the Container as a Dependency of your Service
306168~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
307169
308170Setting the scope to a narrower one is not always possible (for instance, a
@@ -338,7 +200,7 @@ into your service::
338200 in the first section (except that Symfony cannot detect that you are
339201 wrong).
340202
341- The service config for this class would look something like this:
203+ The service configuration for this class would look something like this:
342204
343205.. configuration-block ::
344206
0 commit comments