-
-
Notifications
You must be signed in to change notification settings - Fork 5.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[#6438] Fix class names and shorten article after merging
- Loading branch information
Showing
1 changed file
with
47 additions
and
65 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,33 +7,34 @@ Extending Action Argument Resolving | |
.. versionadded:: 3.1 | ||
The ``ArgumentResolver`` and value resolvers were introduced in Symfony 3.1. | ||
|
||
In the book, you've learned that you can get the :class:`Symfony\\Component\\HttpFoundation\\Request` | ||
object via an argument in your controller. This argument has to be type-hinted | ||
by the ``Request`` class in order to be recognized. This is done via the | ||
In the book, you've learned that you can get the | ||
:class:`Symfony\\Component\\HttpFoundation\\Request` object via an argument in | ||
your controller. This argument has to be type-hinted by the ``Request`` class | ||
in order to be recognized. This is done via the | ||
:class:`Symfony\\Component\\HttpKernel\\Controller\\ArgumentResolver`. By | ||
creating and registering custom argument value resolvers, you can extend | ||
this functionality. | ||
creating and registering custom argument value resolvers, you can extend this | ||
functionality. | ||
|
||
Functionality Shipped with the HttpKernel | ||
----------------------------------------- | ||
|
||
Symfony ships with four value resolvers in the HttpKernel component: | ||
|
||
:class:`Symfony\\Component\\HttpKernel\\Controller\\ArgumentValueResolver\\ArgumentFromAttributeResolver` | ||
:class:`Symfony\\Component\\HttpKernel\\Controller\\ArgumentResolver\\RequestAttributeValueResolver` | ||
Attempts to find a request attribute that matches the name of the argument. | ||
|
||
:class:`Symfony\\Component\\HttpKernel\\Controller\\ArgumentValueResolver\\RequestValueResolver` | ||
Injects the current ``Request`` if type-hinted with ``Request``, or a | ||
sub-class thereof. | ||
:class:`Symfony\\Component\\HttpKernel\\Controller\\ArgumentResolver\\RequestValueResolver` | ||
Injects the current ``Request`` if type-hinted with ``Request`` or a class | ||
extending ``Request``. | ||
|
||
:class:`Symfony\\Component\\HttpKernel\\Controller\\ArgumentValueResolver\\DefaultValueResolver` | ||
:class:`Symfony\\Component\\HttpKernel\\Controller\\ArgumentResolver\\DefaultValueResolver` | ||
Will set the default value of the argument if present and the argument | ||
is optional. | ||
|
||
:class:`Symfony\\Component\\HttpKernel\\Controller\\ArgumentValueResolver\\VariadicValueResolver` | ||
Verifies in the request if your data is an array and will add all of | ||
them to the argument list. When the action is called, the last (variadic) | ||
argument will contain all the values of this array. | ||
:class:`Symfony\\Component\\HttpKernel\\Controller\\ArgumentResolver\\VariadicValueResolver` | ||
Verifies if the request data is an array and will add all of them to the | ||
argument list. When the action is called, the last (variadic) argument will | ||
contain all the values of this array. | ||
|
||
.. note:: | ||
|
||
|
@@ -43,9 +44,10 @@ Symfony ships with four value resolvers in the HttpKernel component: | |
Adding a Custom Value Resolver | ||
------------------------------ | ||
|
||
Adding a new value resolver requires one class and one service defintion. | ||
In the next example, you'll create a value resolver to inject the ``User`` | ||
object from the security system. Given you write the following action:: | ||
Adding a new value resolver requires creatign one class and one service | ||
This comment has been minimized.
Sorry, something went wrong. |
||
definition. In the next example, you'll create a value resolver to inject the | ||
``User`` object from the security system. Given you write the following | ||
controller:: | ||
|
||
namespace AppBundle\Controller; | ||
|
||
|
@@ -56,12 +58,13 @@ object from the security system. Given you write the following action:: | |
{ | ||
public function indexAction(User $user) | ||
{ | ||
return new Response('<html><body>Hello '.$user->getUsername().'!</body></html>'); | ||
return new Response('Hello '.$user->getUsername().'!'); | ||
} | ||
} | ||
|
||
Somehow you will have to get the ``User`` object and inject it into the controller. | ||
This can be done by implementing the :class:`Symfony\\Component\\HttpKernel\\Controller\\ArgumentValueResolverInterface`. | ||
This can be done by implementing the | ||
:class:`Symfony\\Component\\HttpKernel\\Controller\\ArgumentValueResolverInterface`. | ||
This interface specifies that you have to implement two methods: | ||
|
||
``supports()`` | ||
|
@@ -80,7 +83,8 @@ Now that you know what to do, you can implement this interface. To get the | |
current ``User``, you need the current security token. This token can be | ||
retrieved from the token storage:: | ||
|
||
namespace AppBundle\ArgumentValueResolver; | ||
// src/AppBundle/ArgumentResolver/UserValueResolver.php | ||
namespace AppBundle\ArgumentResolver; | ||
|
||
use AppBundle\Entity\User; | ||
use Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface; | ||
|
@@ -123,31 +127,22 @@ must fulfill the following requirements: | |
* A security token must be present; | ||
* The value must be an instance of the ``User``. | ||
|
||
When all those requirements are met and true is returned, the ``ArgumentResolver`` | ||
calls ``resolve()`` with the same values as it called ``supports()``. | ||
When all those requirements are met and ``true`` is returned, the | ||
``ArgumentResolver`` calls ``resolve()`` with the same values as it called | ||
``supports()``. | ||
|
||
That's it! Now all you have to do is add the configuration for the service | ||
container. This can be done by tagging the service with ``controller.argument_resolver`` | ||
and adding a priority. | ||
|
||
.. note:: | ||
|
||
While adding a priority is optional, it's recommended to add one to | ||
make sure the expected value is injected. The ``ArgumentFromAttributeResolver`` | ||
has a priority of 100. As this one is responsible for fetching attributes | ||
from the ``Request``, it's also recommended to trigger your custom value | ||
resolver with a lower priority. This makes sure the argument resolvers | ||
are not triggered in (e.g.) subrequests if you pass your user along: | ||
``{{ render(controller('AppBundle:User:index', {'user', app.user})) }}``. | ||
|
||
.. configuration-block:: | ||
|
||
.. code-block:: yaml | ||
# app/config/services.yml | ||
services: | ||
app.value_resolver.user: | ||
class: AppBundle\ArgumentValueResolver\UserValueResolver | ||
class: AppBundle\ArgumentResolver\UserValueResolver | ||
arguments: | ||
- '@security.token_storage' | ||
tags: | ||
|
@@ -162,7 +157,9 @@ and adding a priority. | |
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"> | ||
<services> | ||
<service id="app.value_resolver.user" class="AppBundle\ArgumentValueResolver\UserValueResolver"> | ||
<service id="app.value_resolver.user" | ||
class="AppBundle\ArgumentResolver\UserValueResolver" | ||
> | ||
<argument type="service" id="security.token_storage"> | ||
<tag name="controller.argument_value_resolver" priority="50" /> | ||
</service> | ||
|
@@ -176,44 +173,29 @@ and adding a priority. | |
use Symfony\Component\DependencyInjection\Definition; | ||
$defintion = new Definition( | ||
'AppBundle\ArgumentValueResolver\UserValueResolver', | ||
'AppBundle\ArgumentResolver\UserValueResolver', | ||
array(new Reference('security.token_storage')) | ||
); | ||
$definition->addTag('controller.argument_value_resolver', array('priority' => 50)); | ||
$container->setDefinition('app.value_resolver.user', $definition); | ||
Creating an Optional User Resolver | ||
---------------------------------- | ||
|
||
When you want your user to be optional, e.g. when your page is behind a | ||
firewall that also allows anonymous authentication, you might not always | ||
have a security user. To get this to work, you only have to change your | ||
method signature to `UserInterface $user = null`. | ||
While adding a priority is optional, it's recommended to add one to make sure | ||
the expected value is injected. The ``RequestAttributeValueResolver`` has a | ||
priority of 100. As this one is responsible for fetching attributes from the | ||
``Request``, it's recommended to trigger your custom value resolver with a | ||
lower priority. This makes sure the argument resolvers are not triggered when | ||
the attribute is present. For instance, when passing the user along a | ||
subrequests. | ||
|
||
When you take the ``UserValueResolver`` from the previous example, you can | ||
see there is no logic in case of failure to comply to the requirements. Default | ||
values are defined in the signature and are available in the ``ArgumentMetadata``. | ||
When a default value is available and there are no resolvers that support | ||
the given value, the ``DefaultValueResolver`` is triggered. This Resolver | ||
takes the default value of your argument and yields it to the argument list:: | ||
.. tip:: | ||
|
||
namespace Symfony\Component\HttpKernel\Controller\ArgumentResolver; | ||
As you see in the ``UserValueResolver::supports()`` method, the user may | ||
not be available (e.g. when the controller is not behind a firewall). In | ||
these cases, the resolver will not be executed. If no argument value is | ||
resolved, an exception will be throwed. | ||
|
||
This comment has been minimized.
Sorry, something went wrong.
linaori
Contributor
|
||
use Symfony\Component\HttpFoundation\Request; | ||
use Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface; | ||
use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata; | ||
|
||
final class DefaultValueResolver implements ArgumentValueResolverInterface | ||
{ | ||
public function supports(Request $request, ArgumentMetadata $argument) | ||
{ | ||
return $argument->hasDefaultValue(); | ||
} | ||
|
||
public function resolve(Request $request, ArgumentMetadata $argument) | ||
{ | ||
yield $argument->getDefaultValue(); | ||
} | ||
} | ||
To prevent this, you can add a default value in the controller (e.g. ``User | ||
$user = null``). The ``DefaultValueResolver`` is executed as last resolver | ||
and will use the default value if no value is resolved already. | ||
|
||
.. _`yield`: http://php.net/manual/en/language.generators.syntax.php |
typo: creatign