8000 Added docs about ArgumentValueResolvers by linaori · Pull Request #6438 · symfony/symfony-docs · GitHub
[go: up one dir, main page]

Skip to content

Added docs 8000 about ArgumentValueResolvers #6438

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Prev Previous commit
Next Next commit
Tried to make the default value resolving more clear
  • Loading branch information
Iltar van der Berg committed Apr 29, 2016
commit e3d1b48acf7dde3d167f6d1627f1264b1dca2224
58 changes: 40 additions & 18 deletions
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,13 @@ Extending Action Argument Resolving
===================================

.. versionadded:: 3.1
The ``ArgumentResolver`` and value resolvers are added in Symfony 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 by adding a ``Request`` argument to your controller. This is done
via the :class:`Symfony\\Component\\HttpKernel\\Controller\\ArgumentResolver`.
By creating and registering custom argument value resolvers, you can extend
object via an argument in your controller. This argument has to be typehinted
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extra empty line

Functionality Shipped With The HttpKernel
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

with

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't it be something like this then: Functionality Shipped with the HttpKernel? It looks odd to have with but The

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right.

Expand Down Expand Up @@ -74,7 +75,7 @@ This interface specifies that you have to implement two methods::
given argument. ``resolve()`` will only be executed when this returns ``true``.
``resolve()``
This method will resolve the actual value for the argument. Once the value
is resolved, you should `yield`_ the value to the ``ArgumentResolver``.
is resolved, you must `yield`_ the value to the ``ArgumentResolver``.

Both methods get the ``Request`` object, which is the current request, and an
:class:`Symfony\\Component\\HttpKernel\\ControllerMetadata\\ArgumentMetadata`.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would add "instance" in this sentence: "Both methods get [...] and an ArgumentMetadata instance"

Expand Down Expand Up @@ -131,24 +132,15 @@ retrieved from the token storage::
}

In order to get the actual ``User`` object in your argument, the given value
should fulfill the following requirements:
must fulfill the following requirements:

* The argument type (of the method signature) must be typehinted as ``User``;
* The security token must be present;
* The value should be an instance of the ``User``.
* An argument must be typehinted as ``User`` in your action method signature;
* 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()``.

.. tip::

You can leverage the ``DefaultValueResolver`` by making your resolver
accept only mandatory arguments. Given your signature is `User $user = null`,
the above example will not hit ``resolve()`` as one of the conditions
does not match. Eventually when the ``DefaultValueResolver`` is asked
to resolve this, it will simply add the default value from the method
signature, which results in ``null``.

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 ``kernel.argument_resolver``
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

controller.argument_value_resolver

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did a quick check on this string, I seem to have mistaken it more often, but found 0 other usages luckily

and adding a priority.
Expand Down Expand Up @@ -206,3 +198,33 @@ and adding a priority.
$container->setDefinition('app.value_resolver.user', $definition);

.. _`yield`: http://php.net/manual/en/language.generators.syntax.php

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`.

When you take the ``UserValueResolver`` from the previous example, you can
Copy link
Contributor
@HeahDude HeahDude Apr 18, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, thanks, it's definitely more clear. But the problem I was pointing (if there was one) still exists.

Currently, the "previous example" requires a user (no default null in the signature), so the DefaultValueResolver is not called while the UserValueResolver does not support the resolving if the token storage returns null (or not an instance of User. Hence if I'm not wrong the controller call is broken. Is that what you mean by "there is no logic in case of failure to comply to the requirements"?.

I think you should either make the user optional in the signature of the example, or remove the test of the returned value from the TokenStorage in supports method and throw a proper exception in resolve() if not an instance of User.

What do you think ?

Question off topic, coming up while writing this: why supports method takes an "s" and not resolve?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Regarding the name: "A supports B", hence I named it like that, is this incorrect?

Hence if I'm not wrong the controller call is broken. Is that what you mean by "there is no logic in case of failure to comply to the requirements"?.

I think you should either make the user optional in the signature of the example, or remove the test of the returned value from the TokenStorage in supports method and throw a proper exception in resolve() if not an instance of User.

If nothing can be resolved, the ArgumentResolver will throw an except that nothing could resolve that argument.

What I could do is grab the UserInterface implementation I got a PR for, would that make it more clear?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok sorry, I missed the ArgumentResolver exception. Maybe it could be enough to explicit it somewhere in this PR?

For the naming I used the same for formatters' interface in symfony/symfony#18450 but I was just wondering why this convention of an "s" for supports(), maybe because it's passive (contrary to an action of supporting)?

see there is no logic in case of failure to comply to the requirements. Default
values in are defined in the signature and are available in the ``ArgumentMetadata``.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in too much? Because the sentence sounds weird: Default values IN are defined in the signature...

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::
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would link the yield reference here too

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no "yield" that I can use though, the only word here referring to it is "yields"


namespace Symfony\Component\HttpKernel\Controller\ArgumentResolver;

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use statements are missing

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();
}
}
0