diff --git a/cookbook/service_container/scopes.rst b/cookbook/service_container/scopes.rst
index aee6710636f..48e760ca1c6 100644
--- a/cookbook/service_container/scopes.rst
+++ b/cookbook/service_container/scopes.rst
@@ -21,13 +21,15 @@ scopes:
- ``prototype``: A new instance is created each time you request the service.
-The FrameworkBundle also defines a third scope: ``request``. This scope is
-tied to the request, meaning a new instance is created for each subrequest
-and is unavailable outside the request (for instance in the CLI).
+The
+:class:`Symfony\\Component\\HttpKernel\\DependencyInjection\\ContainerAwareHttpKernel`
+also defines a third scope: ``request``. This scope is tied to the request,
+meaning a new instance is created for each subrequest and is unavailable
+outside the request (for instance in the CLI).
Scopes add a constraint on the dependencies of a service: a service cannot
depend on services from a narrower scope. For example, if you create a generic
-``my_foo`` service, but try to inject the ``request`` component, you'll receive
+``my_foo`` service, but try to inject the ``request`` service, you will receive
a :class:`Symfony\\Component\\DependencyInjection\\Exception\\ScopeWideningInjectionException`
when compiling the container. Read the sidebar below for more details.
@@ -69,10 +71,71 @@ when compiling the container. Read the sidebar below for more details.
A service can of course depend on a service from a wider scope without
any issue.
-Setting the Scope in the Definition
------------------------------------
+Using a Service from a narrower Scope
+-------------------------------------
+
+If your service has a dependency on a scoped service (like the ``request``),
+you have three ways to deal with it:
+
+* Use setter injection if the dependency is "synchronized"; this is the
+ recommended way and the best solution for the ``request`` instance as it is
+ synchronized with the ``request`` scope (see
+ :ref:`using-synchronized-service`).
+
+* Put your service in the same scope as the dependency (or a narrower one). If
+ you depend on the ``request`` service, this means putting your new service
+ in the ``request`` scope (see :ref:`changing-service-scope`);
+
+* Pass the entire container to your service and retrieve your dependency from
+ the container each time you need it to be sure you have the right instance
+ -- your service can live in the default ``container`` scope (see
+ :ref:`passing-container`);
+
+Each scenario is detailed in the following sections.
+
+.. _using-synchronized-service:
+
+Using a synchronized Service
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-The scope of a service is set in the definition of the service:
+Injecting the container or setting your service to a narrower scope have
+drawbacks. For synchronized services (like the ``request``), using setter
+injection is the best option as it has no drawbacks and everything works
+without any special code in your service or in your definition::
+
+ // src/Acme/HelloBundle/Mail/Mailer.php
+ namespace Acme\HelloBundle\Mail;
+
+ use Symfony\Component\HttpFoundation\Request;
+
+ class Mailer
+ {
+ protected $request;
+
+ public function setRequest(Request $request = null)
+ {
+ $this->request = $request;
+ }
+
+ public function sendEmail()
+ {
+ if (null === $this->request) {
+ // throw an error?
+ }
+
+ // ... do something using the request here
+ }
+ }
+
+Whenever the ``request`` is entered or leaved, the service container will
+automatically call the ``setRequest()`` method with the current ``request``
+instance.
+
+You might have noticed that the ``setRequest()`` method accepts ``null`` as a
+valid value for the ``request`` argument. That's because when leaving the
+``request`` scope, the ``request`` instance can be ``null`` (for the master
+request for instance). Of course, you should take care of this possibility in
+your code. This should also be taken into account when declaring your service:
.. configuration-block::
@@ -82,42 +145,117 @@ The scope of a service is set in the definition of the service:
services:
greeting_card_manager:
class: Acme\HelloBundle\Mail\GreetingCardManager
- scope: request
+ calls:
+ - [setRequest, ['@?request']]
.. code-block:: xml
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies: