@@ -12,9 +12,10 @@ This entry is all about scopes, a somewhat advanced topic related to the
12
12
13
13
If you are trying to inject the ``request `` service, the simple solution
14
14
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 ``.
18
19
19
20
Understanding Scopes
20
21
--------------------
@@ -34,8 +35,8 @@ also defines a third scope: ``request``. This scope is tied to the request,
34
35
meaning a new instance is created for each subrequest and is unavailable
35
36
outside the request (for instance in the CLI).
36
37
37
- The Example: client Scope
38
- ~~~~~~~~~~~~~~~~~~~~~~~~~
38
+ An Example: client Scope
39
+ ~~~~~~~~~~~~~~~~~~~~~~~~
39
40
40
41
Other than the ``request `` service (which has a simple solution, see the
41
42
above 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.
64
65
from it, such as what the "sender" address should be. You add it as a
65
66
constructor argument. Let's look at why this presents a problem:
66
67
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!
70
71
71
72
* Your application now needs to do something with another client, and
72
73
you've architected your application in such a way that you handle this
73
74
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
75
76
*ConfigurationB *.
76
77
77
78
* Somewhere in your application, you once again ask for the ``my_mailer ``
@@ -96,14 +97,14 @@ Using a Service from a narrower Scope
96
97
97
98
There are several solutions to the scope problem:
98
99
99
- * Use setter injection if the dependency is "synchronized"; (see
100
+ * A) Use setter injection if the dependency is "synchronized"; (see
100
101
:ref: `using-synchronized-service `).
101
102
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
103
104
you depend on the ``client_configuration `` service, this means putting your
104
105
new service in the ``client `` scope (see :ref: `changing-service-scope `);
105
106
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
107
108
the container each time you need it to be sure you have the right instance
108
109
-- your service can live in the default ``container `` scope (see
109
110
:ref: `passing-container `);
@@ -112,15 +113,15 @@ Each scenario is detailed in the following sections.
112
113
113
114
.. _using-synchronized-service :
114
115
115
- Using a synchronized Service
116
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
116
+ A) Using a synchronized Service
117
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
117
118
118
119
.. versionadded :: 2.3
119
120
Synchronized services are new in Symfony 2.3.
120
121
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
122
123
drawbacks. Assume first that the ``client_configuration `` service has been
123
- marked as " synchronized" :
124
+ marked as `` synchronized `` :
124
125
125
126
.. configuration-block ::
126
127
@@ -132,17 +133,25 @@ marked as "synchronized":
132
133
class : Acme\HelloBundle\Client\ClientConfiguration
133
134
scope : client
134
135
synchronized : true
136
+ # ...
135
137
136
138
.. code-block :: xml
137
139
138
140
<!-- app/config/config.xml -->
139
141
<?xml version =" 1.0" encoding =" UTF-8" ?>
140
142
<container xmlns =" http://symfony.com/schema/dic/services"
141
143
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
+ >
143
147
144
148
<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
+ />
146
155
</services >
147
156
</container >
148
157
@@ -151,13 +160,13 @@ marked as "synchronized":
151
160
// app/config/config.php
152
161
use Symfony\Component\DependencyInjection\Definition;
153
162
154
- $defn = new Definition(
163
+ $definition = new Definition(
155
164
'Acme\HelloBundle\Client\ClientConfiguration',
156
165
array()
157
166
);
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 );
161
170
162
171
Now, if you inject this service using setter injection, there are no drawbacks
163
172
and 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:
202
211
203
212
# src/Acme/HelloBundle/Resources/config/services.yml
204
213
services :
205
- greeting_card_manager :
206
- class : Acme\HelloBundle\Mail\GreetingCardManager
214
+ my_mailer :
215
+ class : Acme\HelloBundle\Mail\Mailer
207
216
calls :
208
217
- [setClientConfiguration, ['@?client_configuration=']]
209
218
210
219
.. code-block :: xml
211
220
212
221
<!-- src/Acme/HelloBundle/Resources/config/services.xml -->
213
222
<services >
214
- <service id =" greeting_card_manager "
215
- class =" Acme\HelloBundle\Mail\GreetingCardManager "
223
+ <service id =" my_mailer "
224
+ class =" Acme\HelloBundle\Mail\Mailer "
216
225
>
217
226
<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
+ />
219
233
</call >
220
234
</service >
221
235
</services >
@@ -227,37 +241,43 @@ your code. This should also be taken into account when declaring your service:
227
241
use Symfony\Component\DependencyInjection\ContainerInterface;
228
242
229
243
$definition = $container->setDefinition(
230
- 'greeting_card_manager ',
231
- new Definition('Acme\HelloBundle\Mail\GreetingCardManager ')
244
+ 'my_mailer ',
245
+ new Definition('Acme\HelloBundle\Mail\Mailer ')
232
246
)
233
247
->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
+ )
235
253
));
236
254
237
255
.. _changing-service-scope :
238
256
239
- Changing the Scope of your Service
240
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
257
+ B) Changing the Scope of your Service
258
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
241
259
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:
243
263
244
264
.. configuration-block ::
245
265
246
266
.. code-block :: yaml
247
267
248
268
# src/Acme/HelloBundle/Resources/config/services.yml
249
269
services :
250
- greeting_card_manager :
251
- class : Acme\HelloBundle\Mail\GreetingCardManager
270
+ my_mailer :
271
+ class : Acme\HelloBundle\Mail\Mailer
252
272
scope : client
253
273
arguments : [@client_configuration]
254
274
255
275
.. code-block :: xml
256
276
257
277
<!-- src/Acme/HelloBundle/Resources/config/services.xml -->
258
278
<services >
259
- <service id =" greeting_card_manager "
260
- class =" Acme\HelloBundle\Mail\GreetingCardManager "
279
+ <service id =" my_mailer "
280
+ class =" Acme\HelloBundle\Mail\Mailer "
261
281
scope =" client"
262
282
/>
263
283
<argument type =" service" id =" client_configuration" />
@@ -269,17 +289,17 @@ Changing the scope of a service should be done in its definition:
269
289
use Symfony\Component\DependencyInjection\Definition;
270
290
271
291
$definition = $container->setDefinition(
272
- 'greeting_card_manager ',
292
+ 'my_mailer ',
273
293
new Definition(
274
- 'Acme\HelloBundle\Mail\GreetingCardManager ',
294
+ 'Acme\HelloBundle\Mail\Mailer ',
275
295
array(new Reference('client_configuration'),
276
296
))
277
297
)->setScope('client');
278
298
279
299
.. _passing-container :
280
300
281
- Passing the Container as a Dependency of your Service
282
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
301
+ C) Passing the Container as a Dependency of your Service
302
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
283
303
284
304
Setting the scope to a narrower one is not always possible (for instance, a
285
305
twig extension must be in the ``container `` scope as the Twig environment
0 commit comments