@@ -9,57 +9,255 @@ extends the base
9
9
:class: `Symfony\\ Bundle\\ FrameworkBundle\\ Controller\\ Controller ` class. While
10
10
this works fine, controllers can also be specified as services.
11
11
12
+ .. note ::
13
+
14
+ Specifying a controller as a service takes a little bit more work. The
15
+ primary advantage is that the entire controller or any services passed to
16
+ the controller can be modified via the service container configuration.
17
+ This is especially useful when developing an open-source bundle or any
18
+ bundle that will be used in many different projects. So, even if you don't
19
+ specify your controllers as services, you'll likely see this done in some
20
+ open-source Symfony2 bundles.
21
+
22
+ Defining the Controller as a Service
23
+ ------------------------------------
24
+
25
+ A controller can be defined as a service in the same way as any other class.
26
+ For example, if you have the following simple controller::
27
+
28
+ // src/Acme/HelloBundle/Controller/HelloController.php
29
+ namespace Acme\HelloBundle\Controller;
30
+
31
+ use Symfony\Component\HttpFoundation\Response;
32
+
33
+ class HelloController
34
+ {
35
+ public function indexAction($name)
36
+ {
37
+ return new Response('<html><body>Hello '.$name.'!</body></html>');
38
+ }
39
+ }
40
+
41
+ Then you can define it as a service as follows:
42
+
43
+ .. configuration-block ::
44
+
45
+ .. code-block :: yaml
46
+
47
+ # src/Acme/HelloBundle/Resources/config/services.yml
48
+ parameters :
49
+ # ...
50
+ acme.controller.hello.class : Acme\HelloBundle\Controller\HelloController
51
+
52
+ services :
53
+ acme.hello.controller :
54
+ class : " %acme.controller.hello.class%"
55
+
56
+ .. code-block :: xml
57
+
58
+ <!-- src/Acme/HelloBundle/Resources/config/services.xml -->
59
+ <parameters >
60
+ <!-- ... -->
61
+ <parameter key =" acme.controller.hello.class" >Acme\HelloBundle\Controller\HelloController</parameter >
62
+ </parameters >
63
+
64
+ <services >
65
+ <service id =" acme.hello.controller" class =" %acme.controller.hello.class%" />
66
+ </services >
67
+
68
+ .. code-block :: php
69
+
70
+ // src/Acme/HelloBundle/Resources/config/services.php
71
+ use Symfony\Component\DependencyInjection\Definition;
72
+
73
+ // ...
74
+ $container->setParameter(
75
+ 'acme.controller.hello.class',
76
+ 'Acme\HelloBundle\Controller\HelloController'
77
+ );
78
+
79
+ $container->setDefinition('acme.hello.controller', new Definition(
80
+ '%acme.controller.hello.class%'
81
+ ));
82
+
83
+ Referring to the service
84
+ ------------------------
85
+
12
86
To refer to a controller that's defined as a service, use the single colon (:)
13
- notation. For example, suppose you've defined a service called
14
- ``my_controller `` and you want to forward to a method called ``indexAction() ``
15
- inside the service::
87
+ notation. For example, to forward to the ``indexAction() `` method of the service
88
+ defined above with the id ``acme.hello.controller ``::
89
+
90
+ $this->forward('acme.hello.controller:indexAction');
91
+
92
+ .. note ::
16
93
17
- $this->forward('my_controller:indexAction', array('foo' => $bar));
94
+ You cannot drop the ``Action `` part of the method name when using this
95
+ syntax.
18
96
19
- You need to use the same notation when defining the route `` _controller ``
20
- value:
97
+ You can also route to the service by using the same notation when defining
98
+ the route `` _controller `` value:
21
99
22
- .. code -block :: yaml
100
+ .. configuration -block ::
23
101
24
- my_controller :
25
- path : /
26
- defaults : { _controller: my_controller:indexAction }
102
+ .. code-block :: yaml
27
103
28
- To use a controller in this way, it must be defined in the service container
29
- configuration. For more information, see the :doc: `Service Container
30
- </book/service_container>` chapter.
104
+ # app/config/routing.yml
105
+ hello :
106
+ pattern : /hello
107
+ defaults : { _controller: acme.hello.controller:indexAction }
108
+
109
+ .. code-block :: xml
110
+
111
+ <!-- app/config/routing.xml -->
112
+ <route id =" hello" pattern =" /hello" >
113
+ <default key =" _controller" >acme.hello.controller:indexAction</default >
114
+ </route >
115
+
116
+ .. code-block :: php
117
+
118
+ // app/config/routing.php
119
+ $collection->add('hello', new Route('/hello', array(
120
+ '_controller' => 'acme.hello.controller:indexAction',
121
+ )));
122
+
123
+ Using Annotation Routing
124
+ ~~~~~~~~~~~~~~~~~~~~~~~~
125
+
126
+ When using annotations to configure routing using a controller defined as a
127
+ service, you need to specify the service id as follows::
128
+
129
+ use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
130
+
131
+ /**
132
+ * @Route("/hello", service="acme.hello.controller")
133
+ */
134
+ class HelloController extends Controller
135
+ {
136
+ // ...
137
+ }
138
+
139
+ This is documented in the :doc: `/bundles/SensioFrameworkExtraBundle/annotations/routing `
140
+ chapter.
141
+
142
+ Alternatives to Base Controller Methods
143
+ ---------------------------------------
31
144
32
145
When using a controller defined as a service, it will most likely not extend
33
146
the base ``Controller `` class. Instead of relying on its shortcut methods,
34
147
you'll interact directly with the services that you need. Fortunately, this is
35
148
usually pretty easy and the base ``Controller `` class itself is a great source
36
149
on how to perform many common tasks.
37
150
38
- .. note ::
151
+ For example, if you want to use templates instead of creating the ``Response ``
152
+ object directly then if you were extending from the base controller you could
153
+ use::
39
154
40
- Specifying a controller as a service takes a little bit more work. The
41
- primary advantage is that the entire controller or any services passed to
42
- the controller can be modified via the service container configuration.
43
- This is especially useful when developing an open-source bundle or any
44
- bundle that will be used in many different projects. So, even if you don't
45
- specify your controllers as services, you'll likely see this done in some
46
- open-source Symfony2 bundles.
155
+ // src/Acme/HelloBundle/Controller/HelloController.php
156
+ namespace Acme\HelloBundle\Controller;
47
157
48
- Using Annotation Routing
49
- ------------------------
158
+ use Symfony\Bundle\FrameworkBundle\Controller\Controller;
159
+ use Symfony\Component\HttpFoundation\Response;
50
160
51
- When using annotations to setup routing when using a controller defined as a
52
- service, you need to specify your service as follows::
161
+ class HelloController extends Controller
162
+ {
163
+ public function indexAction($name)
164
+ {
165
+ return $this->render(
166
+ 'AcmeHelloBundle:Hello:index.html.twig',
167
+ array('name' => $name)
168
+ );
169
+ }
170
+ }
53
171
54
- /**
55
- * @Route("/blog", service="my_bundle.annot_controller")
56
- * @Cache(expires="tomorrow")
57
- */
58
- class AnnotController extends Controller
172
+ This method actually uses the ``templating `` service::
173
+
174
+ public function render($view, array $parameters = array(), Response $response = null)
59
175
{
176
+ return $this->container->get('templating')->renderResponse($view, $parameters, $response);
60
177
}
61
178
62
- In this example, ``my_bundle.annot_controller `` should be the id of the
63
- ``AnnotController `` instance defined in the service container. This is
64
- documented in the :doc: `/bundles/SensioFrameworkExtraBundle/annotations/routing `
65
- chapter.
179
+ So in our controller as a service we can instead inject the ``templating ``
180
+ service and use it directly::
181
+
182
+ // src/Acme/HelloBundle/Controller/HelloController.php
183
+ namespace Acme\HelloBundle\Controller;
184
+
185
+ use Symfony\Component\HttpFoundation\Response;
186
+
187
+ class HelloController
188
+ {
189
+ private $templating;
190
+
191
+ public function __construct($templating)
192
+ {
193
+ $this->templating = $templating;
194
+ }
195
+
196
+ public function indexAction($name)
197
+ {
198
+ return $this->templating->renderResponse(
199
+ 'AcmeHelloBundle:Hello:index.html.twig',
200
+ array('name' => $name)
201
+ );
202
+ }
203
+ }
204
+
205
+ The service definition also needs modifying to specify the constructor
206
+ argument:
207
+
208
+ .. configuration-block ::
209
+
210
+ .. code-block :: yaml
211
+
212
+ # src/Acme/HelloBundle/Resources/config/services.yml
213
+ parameters :
214
+ # ...
215
+ acme.controller.hello.class : Acme\HelloBundle\Controller\HelloController
216
+
217
+ services :
218
+ acme.hello.controller :
219
+ class : " %acme.controller.hello.class%"
220
+ arguments : ["@templating"]
221
+
222
+ .. code-block :: xml
223
+
224
+ <!-- src/Acme/HelloBundle/Resources/config/services.xml -->
225
+ <parameters >
226
+ <!-- ... -->
227
+ <parameter key =" acme.controller.hello.class" >Acme\HelloBundle\Controller\HelloController</parameter >
228
+ </parameters >
229
+
230
+ <services >
231
+ <service id =" acme.hello.controller" class =" %acme.controller.hello.class%" >
232
+ <argument type =" service" id =" templating" />
233
+ </service >
234
+ </services >
235
+
236
+ .. code-block :: php
237
+
238
+ // src/Acme/HelloBundle/Resources/config/services.php
239
+ use Symfony\Component\DependencyInjection\Definition;
240
+ use Symfony\Component\DependencyInjection\Reference;
241
+
242
+ // ...
243
+ $container->setParameter(
244
+ 'acme.controller.hello.class',
245
+ 'Acme\HelloBundle\Controller\HelloController'
246
+ );
247
+
248
+ $container->setDefinition('acme.hello.controller', new Definition(
249
+ '%acme.controller.hello.class%',
250
+ array(new Reference('templating'))
251
+ ));
252
+
253
+ Rather than fetching the ``templating `` service from the container just the
254
+ service required is being directly injected into the controller.
255
+
256
+ .. note ::
257
+
258
+ This does not mean that you cannot extend these controllers from a base
259
+ controller. The move away from the standard base controller is because
260
+ its helper method rely on having the container available which is not
261
+ the case for controllers defined as services. However, it is worth considering
262
+ extracting common code into a service to be injected in rather than a parent
263
+ class.
0 commit comments