4
4
How to Work with Scopes
5
5
=======================
6
6
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
8
8
: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.
10
10
11
11
.. note ::
12
12
@@ -25,10 +25,11 @@ The scope of a service controls how long an instance of a service is used
25
25
by the container. The DependencyInjection component provides two generic
26
26
scopes:
27
27
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.
30
30
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.
32
33
33
34
The
34
35
:class: `Symfony\\ Component\\ HttpKernel\\ DependencyInjection\\ ContainerAwareHttpKernel `
@@ -40,9 +41,9 @@ An Example: Client Scope
40
41
~~~~~~~~~~~~~~~~~~~~~~~~
41
42
42
43
Other 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
44
45
scope 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 ``
46
47
that belongs to it. This is not a common situation, but the idea is that
47
48
you may enter and exit multiple ``client `` scopes during a request, and each
48
49
has its own ``client_configuration `` service.
@@ -71,7 +72,7 @@ when compiling the container. Read the sidebar below for more details.
71
72
called *ConfigurationA * here) is passed to it. Life is good!
72
73
73
74
* 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
75
76
by entering a new ``client_configuration `` scope and setting a new
76
77
``client_configuration `` service into the container. Call this
77
78
*ConfigurationB *.
@@ -96,16 +97,13 @@ when compiling the container. Read the sidebar below for more details.
96
97
Using a Service from a Narrower Scope
97
98
-------------------------------------
98
99
99
- There are several solutions to the scope problem:
100
+ There are two solutions to the scope problem:
100
101
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
105
103
you depend on the ``client_configuration `` service, this means putting your
106
104
new service in the ``client `` scope (see :ref: `changing-service-scope `);
107
105
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
109
107
the container each time you need it to be sure you have the right instance
110
108
-- your service can live in the default ``container `` scope (see
111
109
:ref: `passing-container `).
@@ -114,151 +112,15 @@ Each scenario is detailed in the following sections.
114
112
115
113
.. _using-synchronized-service :
116
114
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 ::
246
116
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.
258
120
259
121
.. _changing-service-scope :
260
122
261
- B ) Changing the Scope of your Service
123
+ A ) Changing the Scope of your Service
262
124
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
263
125
264
126
Changing the scope of a service should be done in its definition. This example
@@ -302,7 +164,7 @@ argument is the ``ClientConfiguration`` object:
302
164
303
165
.. _passing-container :
304
166
305
- C ) Passing the Container as a Dependency of your Service
167
+ B ) Passing the Container as a Dependency of your Service
306
168
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
307
169
308
170
Setting the scope to a narrower one is not always possible (for instance, a
@@ -338,7 +200,7 @@ into your service::
338
200
in the first section (except that Symfony cannot detect that you are
339
201
wrong).
340
202
341
- The service config for this class would look something like this:
203
+ The service configuration for this class would look something like this:
342
204
343
205
.. configuration-block ::
344
206
0 commit comments