diff --git a/cookbook/controller/service.rst b/cookbook/controller/service.rst
index 3291ce3a1a2..03ae0aa1a6a 100644
--- a/cookbook/controller/service.rst
+++ b/cookbook/controller/service.rst
@@ -9,25 +9,126 @@ extends the base
:class:`Symfony\\Bundle\\FrameworkBundle\\Controller\\Controller` class. While
this works fine, controllers can also be specified as services.
+.. note::
+
+ Specifying a controller as a service takes a little bit more work. The
+ primary advantage is that the entire controller or any services passed to
+ the controller can be modified via the service container configuration.
+ This is especially useful when developing an open-source bundle or any
+ bundle that will be used in many different projects. So, even if you don't
+ specify your controllers as services, you'll likely see this done in some
+ open-source Symfony2 bundles.
+
+Defining the Controller as a Service
+------------------------------------
+
+A controller can be defined as a service in the same way as any other class.
+For example, if you have the following simple controller::
+
+ // src/Acme/HelloBundle/Controller/HelloController.php
+ namespace Acme\HelloBundle\Controller;
+
+ use Symfony\Component\HttpFoundation\Response;
+
+ class HelloController
+ {
+ public function indexAction($name)
+ {
+ return new Response('
Hello '.$name.'!');
+ }
+ }
+
+Then you can define it as a service as follows:
+
+.. configuration-block::
+
+ .. code-block:: yaml
+
+ # src/Acme/HelloBundle/Resources/config/services.yml
+ parameters:
+ # ...
+ acme.controller.hello.class: Acme\HelloBundle\Controller\HelloController
+
+ services:
+ acme.hello.controller:
+ class: "%acme.controller.hello.class%"
+
+ .. code-block:: xml
+
+
+
+
+ Acme\HelloBundle\Controller\HelloController
+
+
+
+
+
+
+ .. code-block:: php
+
+ // src/Acme/HelloBundle/Resources/config/services.php
+ use Symfony\Component\DependencyInjection\Definition;
+
+ // ...
+ $container->setParameter(
+ 'acme.controller.hello.class',
+ 'Acme\HelloBundle\Controller\HelloController'
+ );
+
+ $container->setDefinition('acme.hello.controller', new Definition(
+ '%acme.controller.hello.class%'
+ ));
+
+Referring to the service
+------------------------
+
To refer to a controller that's defined as a service, use the single colon (:)
-notation. For example, suppose you've defined a service called
-``my_controller`` and you want to forward to a method called ``indexAction()``
-inside the service::
+notation. For example, to forward to the ``indexAction()`` method of the service
+defined above with the id ``acme.hello.controller``::
+
+ $this->forward('acme.hello.controller:indexAction');
+
+.. note::
+
+ You cannot drop the ``Action`` part of the method name when using this
+ syntax.
+
+You can also route to the service by using the same notation when defining
+the route ``_controller`` value:
+
+.. configuration-block::
+
+ .. code-block:: yaml
- $this->forward('my_controller:indexAction', array('foo' => $bar));
+ # app/config/routing.yml
+ hello:
+ pattern: /hello
+ defaults: { _controller: acme.hello.controller:indexAction }
-You need to use the same notation when defining the route ``_controller``
-value:
+ .. code-block:: xml
-.. code-block:: yaml
+
+
+ acme.hello.controller:indexAction
+
- my_controller:
- pattern: /
- defaults: { _controller: my_controller:indexAction }
+ .. code-block:: php
-To use a controller in this way, it must be defined in the service container
-configuration. For more information, see the :doc:`Service Container
-` chapter.
+ // app/config/routing.php
+ $collection->add('hello', new Route('/hello', array(
+ '_controller' => 'acme.hello.controller:indexAction',
+ )));
+
+.. tip::
+
+ You can also use annotations to configure routing using a controller
+ defined as a service. See the
+ :doc:`FrameworkExtraBundle documentation`
+ for details.
+
+Alternatives to Base Controller Methods
+---------------------------------------
When using a controller defined as a service, it will most likely not extend
the base ``Controller`` class. Instead of relying on its shortcut methods,
@@ -35,31 +136,118 @@ you'll interact directly with the services that you need. Fortunately, this is
usually pretty easy and the base ``Controller`` class itself is a great source
on how to perform many common tasks.
-.. note::
+For example, if you want to use templates instead of creating the ``Response``
+object directly then if you were extending from the base controller you could
+use::
- Specifying a controller as a service takes a little bit more work. The
- primary advantage is that the entire controller or any services passed to
- the controller can be modified via the service container configuration.
- This is especially useful when developing an open-source bundle or any
- bundle that will be used in many different projects. So, even if you don't
- specify your controllers as services, you'll likely see this done in some
- open-source Symfony2 bundles.
+ // src/Acme/HelloBundle/Controller/HelloController.php
+ namespace Acme\HelloBundle\Controller;
-Using Annotation Routing
-------------------------
+ use Symfony\Bundle\FrameworkBundle\Controller\Controller;
+ use Symfony\Component\HttpFoundation\Response;
+
+ class HelloController extends Controller
+ {
+ public function indexAction($name)
+ {
+ return $this->render(
+ 'AcmeHelloBundle:Hello:index.html.twig',
+ array('name' => $name)
+ );
+ }
+ }
+
+This method actually uses the ``templating`` service::
+
+ public function render($view, array $parameters = array(), Response $response = null)
+ {
+ return $this->container->get('templating')->renderResponse($view, $parameters, $response);
+ }
-When using annotations to setup routing when using a controller defined as a
-service, you need to specify your service as follows::
+So in our controller as a service we can instead inject the ``templating``
+service and use it directly::
- /**
- * @Route("/blog", service="my_bundle.annot_controller")
- * @Cache(expires="tomorrow")
- */
- class AnnotController extends Controller
+ // src/Acme/HelloBundle/Controller/HelloController.php
+ namespace Acme\HelloBundle\Controller;
+
+ use Symfony\Component\HttpFoundation\Response;
+
+ class HelloController
{
+ private $templating;
+
+ public function __construct($templating)
+ {
+ $this->templating = $templating;
+ }
+
+ public function indexAction($name)
+ {
+ return $this->templating->renderResponse(
+ 'AcmeHelloBundle:Hello:index.html.twig',
+ array('name' => $name)
+ );
+ }
}
-In this example, ``my_bundle.annot_controller`` should be the id of the
-``AnnotController`` instance defined in the service container. This is
-documented in the :doc:`/bundles/SensioFrameworkExtraBundle/annotations/routing`
-chapter.
+The service definition also needs modifying to specify the constructor
+argument:
+
+.. configuration-block::
+
+ .. code-block:: yaml
+
+ # src/Acme/HelloBundle/Resources/config/services.yml
+ parameters:
+ # ...
+ acme.controller.hello.class: Acme\HelloBundle\Controller\HelloController
+
+ services:
+ acme.hello.controller:
+ class: "%acme.controller.hello.class%"
+ arguments: ["@templating"]
+
+ .. code-block:: xml
+
+
+
+
+ Acme\HelloBundle\Controller\HelloController
+
+
+
+
+
+
+
+
+ .. code-block:: php
+
+ // src/Acme/HelloBundle/Resources/config/services.php
+ use Symfony\Component\DependencyInjection\Definition;
+ use Symfony\Component\DependencyInjection\Reference;
+
+ // ...
+ $container->setParameter(
+ 'acme.controller.hello.class',
+ 'Acme\HelloBundle\Controller\HelloController'
+ );
+
+ $container->setDefinition('acme.hello.controller', new Definition(
+ '%acme.controller.hello.class%',
+ array(new Reference('templating'))
+ ));
+
+Rather than fetching the ``templating`` service from the container just the
+service required is being directly injected into the controller.
+
+.. note::
+
+ This does not mean that you cannot extend these controllers from a base
+ controller. The move away from the standard base controller is because
+ its helper method rely on having the container available which is not
+ the case for controllers defined as services. However, it is worth considering
+ extracting common code into a service to be injected in rather than a parent
+ class.