Skip to content

Commit 1ce0cc7

Browse files
Iltar van der Berglinaori
Iltar van der Berg
authored andcommitted
Documented the ArgumentResolver along the ControllerResolver
1 parent d7724dd commit 1ce0cc7

File tree

8 files changed

+193
-110
lines changed

8 files changed

+193
-110
lines changed

components/http_kernel/introduction.rst

Lines changed: 86 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -85,11 +85,22 @@ is really simple and involves creating an
8585
:doc:`event dispatcher </components/event_dispatcher/introduction>` and a
8686
:ref:`controller resolver <component-http-kernel-resolve-controller>` (explained
8787
below). To complete your working kernel, you'll add more event listeners
88-
to the events discussed below::
88+
to the events discussed below
89+
90+
.. caution::
91+
92+
As of 3.1 the :class:`Symfony\\Component\\Httpkernel\\HttpKernel` accepts a fourth argument, which
93+
should be an instance of :class:`Symfony\\Component\\Httpkernel\\Controller\\ArgumentResolverInterface`.
94+
In 4.0 this argument will become mandatory and the :class:`Symfony\\Component\\Httpkernel\\HttpKernel`
95+
will no longer be able to fall back to the :class:`Symfony\\Component\\Httpkernel\\Controller\\ControllerResolver`.
96+
97+
.. code-block:: php
8998
9099
use Symfony\Component\HttpFoundation\Request;
91100
use Symfony\Component\HttpKernel\HttpKernel;
92101
use Symfony\Component\EventDispatcher\EventDispatcher;
102+
use Symfony\Component\HttpFoundation\RequestStack;
103+
use Symfony\Component\HttpKernel\Controller\ArgumentResolver;
93104
use Symfony\Component\HttpKernel\Controller\ControllerResolver;
94105
95106
// create the Request object
@@ -98,10 +109,12 @@ to the events discussed below::
98109
$dispatcher = new EventDispatcher();
99110
// ... add some event listeners
100111
101-
// create your controller resolver
102-
$resolver = new ControllerResolver();
112+
// create your controller and argument resolvers
113+
$controllerResolver = new ControllerResolver();
114+
$argumentResolver = new ArgumentResolver();
115+
103116
// instantiate the kernel
104-
$kernel = new HttpKernel($dispatcher, $resolver);
117+
$kernel = new HttpKernel($dispatcher, $controllerResolver, new RequestStack(), $argumentResolver);
105118
106119
// actually execute the kernel, which turns the request into a response
107120
// by dispatching events, calling a controller, and returning the response
@@ -212,7 +225,19 @@ Your job is to create a class that implements the interface and fill in its
212225
two methods: ``getController`` and ``getArguments``. In fact, one default
213226
implementation already exists, which you can use directly or learn from:
214227
:class:`Symfony\\Component\\HttpKernel\\Controller\\ControllerResolver`.
215-
This implementation is explained more in the sidebar below::
228+
This implementation is explained more in the sidebar below
229+
230+
231+
.. caution::
232+
233+
The `getArguments()` method in the :class:`Symfony\\Component\\Httpkernel\\Controller\\ControllerResolver`
234+
and respective interface :class:`Symfony\\Component\\Httpkernel\\Controller\\ControllerResolverInterface`
235+
are deprecated as of 3.1 and will be removed in 4.0. You can use the
236+
:class:`Symfony\\Component\\Httpkernel\\Controller\\ArgumentResolver` which uses the
237+
:class:`Symfony\\Component\\Httpkernel\\Controller\\ArgumentResolverInterface` instead.
238+
239+
240+
.. code-block:: php
216241
217242
namespace Symfony\Component\HttpKernel\Controller;
218243
@@ -231,7 +256,7 @@ on the controller resolver. This method is passed the ``Request`` and is respons
231256
for somehow determining and returning a PHP callable (the controller) based
232257
on the request's information.
233258

234-
The second method, :method:`Symfony\\Component\\HttpKernel\\Controller\\ControllerResolverInterface::getArguments`,
259+
The second method, :method:`Symfony\\Component\\HttpKernel\\Controller\\ArgumentResolverInterface::getArguments`,
235260
will be called after another event - ``kernel.controller`` - is dispatched.
236261

237262
.. sidebar:: Resolving the Controller in the Symfony Framework
@@ -310,11 +335,11 @@ on the event object that's passed to listeners on this event.
310335
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
311336

312337
Next, ``HttpKernel::handle`` calls
313-
:method:`Symfony\\Component\\HttpKernel\\Controller\\ControllerResolverInterface::getArguments`.
338+
:method:`Symfony\\Component\\HttpKernel\\Controller\\ArgumentResolverInterface::getArguments`.
314339
Remember that the controller returned in ``getController`` is a callable.
315340
The purpose of ``getArguments`` is to return the array of arguments that
316341
should be passed to that controller. Exactly how this is done is completely
317-
up to your design, though the built-in :class:`Symfony\\Component\\HttpKernel\\Controller\\ControllerResolver`
342+
up to your design, though the built-in :class:`Symfony\\Component\\HttpKernel\\Controller\\ArgumentResolver`
318343
is a good example.
319344

320345
.. image:: /images/components/http_kernel/07-controller-arguments.png
@@ -326,7 +351,7 @@ of arguments that should be passed when executing that callable.
326351
.. sidebar:: Getting the Controller Arguments in the Symfony Framework
327352

328353
Now that you know exactly what the controller callable (usually a method
329-
inside a controller object) is, the ``ControllerResolver`` uses `reflection`_
354+
inside a controller object) is, the ``ArgumentResolver`` uses `reflection`_
330355
on the callable to return an array of the *names* of each of the arguments.
331356
It then iterates over each of these arguments and uses the following tricks
332357
to determine which value should be passed for each argument:
@@ -339,7 +364,18 @@ of arguments that should be passed when executing that callable.
339364

340365
b) If the argument in the controller is type-hinted with Symfony's
341366
:class:`Symfony\\Component\\HttpFoundation\\Request` object, then the
342-
``Request`` is passed in as the value.
367+
``Request`` is passed in as the value. If you have a custom class extending
368+
the ``Request``, this is also accepted.
369+
370+
c) If the function or method argument is `variadic`_ and the ``Request``
371+
``attributes`` bag contains and array for that argument, they will all be
372+
available through the `variadic`_ argument.
373+
374+
This functionality is provided by resolvers implementing the
375+
:class:`Symfony\\Component\\HttpKernel\\Controller\\ArgumentValueResolverInterface`.
376+
There are four implementations which provide the default behavior of Symfony but
377+
customization is the key here. By implementing the ``ArgumentValueResolverInterface``
378+
yourself and passing this to the ``ArgumentResolver``, you can extend this functionality.
343379

344380
.. _component-http-kernel-calling-controller:
345381

@@ -612,47 +648,52 @@ A full Working Example
612648
----------------------
613649

614650
When using the HttpKernel component, you're free to attach any listeners
615-
to the core events and use any controller resolver that implements the
616-
:class:`Symfony\\Component\\HttpKernel\\Controller\\ControllerResolverInterface`.
617-
However, the HttpKernel component comes with some built-in listeners and
618-
a built-in ControllerResolver that can be used to create a working example::
651+
to the core events, use any controller resolver that implements the
652+
:class:`Symfony\\Component\\HttpKernel\\Controller\\ControllerResolverInterface` and
653+
use any argument resolver that implements the
654+
:class:`Symfony\\Component\\HttpKernel\\Controller\\ArgumentResolverInterface`.
655+
However, the HttpKernel component comes with some built-in listeners, and everything
656+
else that can be used to create a working example::
619657

620-
use Symfony\Component\HttpFoundation\Request;
621-
use Symfony\Component\HttpFoundation\RequestStack;
622-
use Symfony\Component\HttpFoundation\Response;
623-
use Symfony\Component\HttpKernel\HttpKernel;
624-
use Symfony\Component\EventDispatcher\EventDispatcher;
625-
use Symfony\Component\HttpKernel\Controller\ControllerResolver;
626-
use Symfony\Component\HttpKernel\EventListener\RouterListener;
627-
use Symfony\Component\Routing\RouteCollection;
628-
use Symfony\Component\Routing\Route;
629-
use Symfony\Component\Routing\Matcher\UrlMatcher;
630-
use Symfony\Component\Routing\RequestContext;
631-
632-
$routes = new RouteCollection();
633-
$routes->add('hello', new Route('/hello/{name}', array(
634-
'_controller' => function (Request $request) {
635-
return new Response(
636-
sprintf("Hello %s", $request->get('name'))
637-
);
638-
}
639-
)
640-
));
658+
use Symfony\Component\EventDispatcher\EventDispatcher;
659+
use Symfony\Component\HttpFoundation\Request;
660+
use Symfony\Component\HttpFoundation\RequestStack;
661+
use Symfony\Component\HttpFoundation\Response;
662+
use Symfony\Component\HttpKernel\Controller\ArgumentResolver;
663+
use Symfony\Component\HttpKernel\Controller\ControllerResolver;
664+
use Symfony\Component\HttpKernel\EventListener\RouterListener;
665+
use Symfony\Component\HttpKernel\HttpKernel;
666+
use Symfony\Component\Routing\Matcher\UrlMatcher;
667+
use Symfony\Component\Routing\RequestContext;
668+
use Symfony\Component\Routing\Route;
669+
use Symfony\Component\Routing\RouteCollection;
641670

642-
$request = Request::createFromGlobals();
671+
$routes = new RouteCollection();
672+
$routes->add('hello', new Route('/hello/{name}', array(
673+
'_controller' => function (Request $request) {
674+
return new Response(
675+
sprintf("Hello %s", $request->get('name'))
676+
);
677+
})
678+
));
643679

644-
$matcher = new UrlMatcher($routes, new RequestContext());
680+
$request = Request::createFromGlobals();
645681

646-
$dispatcher = new EventDispatcher();
647-
$dispatcher->addSubscriber(new RouterListener($matcher, new RequestStack()));
682+
$matcher = new UrlMatcher($routes, new RequestContext());
648683

649-
$resolver = new ControllerResolver();
650-
$kernel = new HttpKernel($dispatcher, $resolver);
684+
$dispatcher = new EventDispatcher();
685+
$dispatcher->addSubscriber(new RouterListener($matcher, new RequestStack()));
651686

652-
$response = $kernel->handle($request);
653-
$response->send();
687+
$controllerResolver = new ControllerResolver();
688+
$argumentResolver = new ArgumentResolver();
689+
690+
$kernel = new HttpKernel($dispatcher, $controllerResolver, new RequestStack(), $argumentResolver);
691+
692+
$response = $kernel->handle($request);
693+
$response->send();
694+
695+
$kernel->terminate($request, $response);
654696

655-
$kernel->terminate($request, $response);
656697

657698
.. _http-kernel-sub-requests:
658699

@@ -716,3 +757,4 @@ look like this::
716757
.. _`@ParamConverter`: https://symfony.com/doc/current/bundles/SensioFrameworkExtraBundle/annotations/converters.html
717758
.. _`@Template`: https://symfony.com/doc/current/bundles/SensioFrameworkExtraBundle/annotations/view.html
718759
.. _`EmailSenderListener`: https://github.com/symfony/swiftmailer-bundle/blob/master/EventListener/EmailSenderListener.php
760+
.. _variadic: http://php.net/manual/en/functions.arguments.php

components/serializer.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,7 @@ You are now able to serialize only attributes in the groups you want::
296296
$serializer = new Serializer(array($normalizer));
297297

298298
$data = $serializer->normalize($obj, null, array('groups' => array('group1')));
299-
// $data = ['foo' => 'foo'];
299+
// $data = array('foo' => 'foo');
300300

301301
$obj2 = $serializer->denormalize(
302302
array('foo' => 'foo', 'bar' => 'bar'),

cookbook/deployment/fortrabbit.rst

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,13 @@ Before getting started, you should have done a few things on the fortrabbit side
2020
Preparing your Application
2121
--------------------------
2222

23-
You don't need to change any code to deploy a Symfony application to fortrabbit.
23+
You don't need to change any code to deploy a Symfony application to fortrabbit.
2424
But it requires some minor tweaks to its configuration.
2525

2626
Configure Logging
2727
~~~~~~~~~~~~~~~~~
2828

29-
Per default Symfony logs to a file. Modify the ``app/config/config_prod.yml`` file
29+
Per default Symfony logs to a file. Modify the ``app/config/config_prod.yml`` file
3030
to redirect it to :phpfunction:`error_log`:
3131

3232
.. configuration-block::
@@ -73,7 +73,7 @@ to redirect it to :phpfunction:`error_log`:
7373
Configuring Database Access & Session Handler
7474
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
7575

76-
You can use the fortrabbit App Secrets to attain your database credentials.
76+
You can use the fortrabbit App Secrets to attain your database credentials.
7777
Create the file ``app/config/config_prod_secrets.php`` with the following
7878
contents::
7979

@@ -98,7 +98,7 @@ contents::
9898
// check if the Memcache component is present
9999
if (isset($secrets['MEMCACHE'])) {
100100
$memcache = $secrets['MEMCACHE'];
101-
$handlers = [];
101+
$handlers = array();
102102

103103
foreach (range(1, $memcache['COUNT']) as $num) {
104104
$handlers[] = $memcache['HOST'.$num].':'.$memcache['PORT'.$num];
@@ -175,19 +175,19 @@ Configuring the Environment in the Dashboard
175175
PHP Settings
176176
~~~~~~~~~~~~
177177

178-
The PHP version and enabled extensions are configuable under the PHP settings
178+
The PHP version and enabled extensions are configuable under the PHP settings
179179
of your App within the fortrabbit Dashboard.
180180

181181
Environment Variables
182182
~~~~~~~~~~~~~~~~~~~~~
183183

184-
Set the ``SYMFONY_ENV`` environment variable to ``prod`` to make sure the right
184+
Set the ``SYMFONY_ENV`` environment variable to ``prod`` to make sure the right
185185
config files get loaded. ENV vars are configuable in fortrabbit Dashboard as well.
186186

187187
Document Root
188188
~~~~~~~~~~~~~
189189

190-
The document root is configuable for every custom domain you setup for your App.
190+
The document root is configuable for every custom domain you setup for your App.
191191
The default is ``/htdocs``, but for Symfony you probably want to change it to
192192
``/htdocs/web``. You also do so in the fortrabbit Dashboard under ``Domain`` settings.
193193

@@ -197,8 +197,8 @@ Deploying to fortrabbit
197197
It is assumed that your codebase is under version-control with Git and dependencies
198198
are managed with Composer (locally).
199199

200-
Every time you push to fortrabbit composer install runs before your code gets
201-
deployed. To finetune the deployment behavior put a `fortrabbit.yml`_. deployment
200+
Every time you push to fortrabbit composer install runs before your code gets
201+
deployed. To finetune the deployment behavior put a `fortrabbit.yml`_. deployment
202202
file (optional) in the project root.
203203

204204
Add fortrabbit as a (additional) Git remote and add your configuration changes:
@@ -221,11 +221,11 @@ Commit and push
221221
Replace ``<your-app>`` with the name of your fortrabbit App.
222222

223223
.. code-block:: bash
224-
224+
225225
Commit received, starting build of branch master
226226
227227
––––––––––––––––––––––– ∙ƒ –––––––––––––––––––––––
228-
228+
229229
B U I L D
230230
231231
Checksum:
@@ -244,7 +244,7 @@ Commit and push
244244
Installing dependencies (including require-dev) from lock file
245245
Nothing to install or update
246246
Generating autoload files
247-
247+
248248
- - -
249249
172ms
250250
@@ -271,11 +271,11 @@ Commit and push
271271
272272
.. note::
273273

274-
The first ``git push`` takes much longer as all composer dependencies get
275-
downloaded. All subsequent deploys are done within seconds.
274+
The first ``git push`` takes much longer as all composer dependencies get
275+
downloaded. All subsequent deploys are done within seconds.
276276

277-
That's it! Your application is being deployed on fortrabbit. More information
278-
about `database migrations and tunneling`_ can be found in the fortrabbit
277+
That's it! Your application is being deployed on fortrabbit. More information
278+
about `database migrations and tunneling`_ can be found in the fortrabbit
279279
documentation.
280280

281281
.. _`fortrabbit`: https://www.fortrabbit.com

create_framework/dependency_injection.rst

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,23 +9,26 @@ to it::
99
// example.com/src/Simplex/Framework.php
1010
namespace Simplex;
1111

12+
use Symfony\Component\EventDispatcher\EventDispatcher;
1213
use Symfony\Component\Routing;
14+
use Symfony\Component\HttpFoundation;
1315
use Symfony\Component\HttpKernel;
14-
use Symfony\Component\EventDispatcher\EventDispatcher;
1516

1617
class Framework extends HttpKernel\HttpKernel
1718
{
1819
public function __construct($routes)
1920
{
2021
$context = new Routing\RequestContext();
2122
$matcher = new Routing\Matcher\UrlMatcher($routes, $context);
22-
$resolver = new HttpKernel\Controller\ControllerResolver();
23+
24+
$controllerResolver = new HttpKernel\Controller\ControllerResolver();
25+
$argumentResolver = new HttpKernel\Controller\ArgumentResolver();
2326

2427
$dispatcher = new EventDispatcher();
2528
$dispatcher->addSubscriber(new HttpKernel\EventListener\RouterListener($matcher));
2629
$dispatcher->addSubscriber(new HttpKernel\EventListener\ResponseListener('UTF-8'));
2730

28-
parent::__construct($dispatcher, $resolver);
31+
parent::__construct($dispatcher, $controllerResolver, new RequestStack(), $argumentResolver);
2932
}
3033
}
3134

@@ -101,7 +104,8 @@ Create a new file to host the dependency injection container configuration::
101104
->setArguments(array($routes, new Reference('context')))
102105
;
103106
$sc->register('request_stack', 'Symfony\Component\HttpFoundation\RequestStack');
104-
$sc->register('resolver', 'Symfony\Component\HttpKernel\Controller\ControllerResolver');
107+
$sc->register('controller_resolver', 'Symfony\Component\HttpKernel\Controller\ControllerResolver');
108+
$sc->register('argument_resolver', 'Symfony\Component\HttpKernel\Controller\ArgumentResolver');
105109

106110
$sc->register('listener.router', 'Symfony\Component\HttpKernel\EventListener\RouterListener')
107111
->setArguments(array(new Reference('matcher'), new Reference('request_stack')))
@@ -118,7 +122,12 @@ Create a new file to host the dependency injection container configuration::
118122
->addMethodCall('addSubscriber', array(new Reference('listener.exception')))
119123
;
120124
$sc->register('framework', 'Simplex\Framework')
121-
->setArguments(array(new Reference('dispatcher'), new Reference('resolver')))
125+
->setArguments(array(
126+
new Reference('dispatcher'),
127+
new Reference('controller_resolver'),
128+
new Reference('request_stack'),
129+
new Reference('argument_resolver'),
130+
))
122131
;
123132

124133
return $sc;

0 commit comments

Comments
 (0)