From 66ce882a0ff439e0c969e9a98e7b01eb55f65a89 Mon Sep 17 00:00:00 2001 From: WouterJ Date: Sat, 11 Jun 2016 21:56:52 +0200 Subject: [PATCH] [#6438] Fix class names and shorten article after merging --- .../controller/argument_value_resolver.rst | 112 ++++++++---------- 1 file changed, 47 insertions(+), 65 deletions(-) diff --git a/cookbook/controller/argument_value_resolver.rst b/cookbook/controller/argument_value_resolver.rst index 6f495504d1f..f64c5859838 100644 --- a/cookbook/controller/argument_value_resolver.rst +++ b/cookbook/controller/argument_value_resolver.rst @@ -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 +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('Hello '.$user->getUsername().'!'); + 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,23 +127,14 @@ 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 @@ -147,7 +142,7 @@ and adding a priority. # 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"> - + @@ -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. - 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