-
-
Notifications
You must be signed in to change notification settings - Fork 895
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
feat: add payload controller value resolver #3263
Conversation
I like it! |
from #3268 , we do <?php
use ApiPlatform\Core\Validator\ValidatorInterface;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
use Sensio\Bundle\FrameworkExtraBundle\Request\ParamConverter\ParamConverterInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Serializer\SerializerInterface;
class ApiInputConverter implements ParamConverterInterface
{
private $serializer;
private $validator;
public function __construct(SerializerInterface $serializer, ValidatorInterface $validator)
{
$this->serializer = $serializer;
$this->validator = $validator;
}
public function apply(Request $request, ParamConverter $configuration)
{
$attribute = $configuration->getName();
if ($request->attributes->has($attribute)) {
return false;
}
$input = $this->serializer->deserialize($request->getContent(), $configuration->getClass(), $request->getRequestFormat());
$this->validator->validate($input);
$request->attributes->set($attribute, $input);
return true;
}
public function supports(ParamConverter $configuration)
{
$options = $configuration->getOptions();
if ($options['api_input_dto'] ?? false) {
if (null === $configuration->getClass()) {
throw new \LogicException('Parameter "'.$configuration->getName().'" must have a class type hint set to deserialize.');
}
return true;
}
return false;
}
} |
Do we really need the dependency to SensioExtraFramework? Symfony has some native Param Converter without this dependency for instance. |
AFAIK it's simply matter of setting a request attribute with deserialized/validated payload. Then we can map it to controller arguments, if needed. To use different attributes names, i think implementing |
Right, I forgot about |
66edd3e
to
aa40414
Compare
099fd09
to
9f3741b
Compare
PR reworked. I'd like to add some functional tests. Does it make sense to use Behat for that? I mean: what this PR introduces is more of a technical improvement than a real user feature. |
9f3741b
to
e366ae9
Compare
Added some integration tests. |
e366ae9
to
1ed48dd
Compare
src/Bridge/Symfony/Bundle/ArgumentResolver/PayloadArgumentResolver.php
Outdated
Show resolved
Hide resolved
return null; | ||
} | ||
|
||
$context = $this->serializationContextBuilder->createFromRequest($request, false, $attributes); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do you use the context builder? The current class should be available directly in the attributes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mmh indeed, resource_class
is available in $attributes
directly, but I'm not sure about input
: the context builder seems to have some custom logic to retrieve it from operation configuration.
1ed48dd
to
c370800
Compare
src/Bridge/Symfony/Bundle/ArgumentResolver/PayloadArgumentResolver.php
Outdated
Show resolved
Hide resolved
c370800
to
31678f6
Compare
src/Bridge/Symfony/Bundle/ArgumentResolver/PayloadArgumentResolver.php
Outdated
Show resolved
Hide resolved
src/Bridge/Symfony/Bundle/Resources/config/argument_resolver.xml
Outdated
Show resolved
Hide resolved
tests/Bridge/Symfony/Bundle/ArgumentResolver/PayloadArgumentResolverTest.php
Outdated
Show resolved
Hide resolved
/** | ||
* @dataProvider provideIntegrationCases | ||
*/ | ||
public function testIntegration(Request $request, callable $controller, array $expectedArguments): void |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't we add the integration tests in another file? If possible we prefer to use Behat for this kind of tests too (but maybe it would be harder to test it and these tests seem OK to maintain).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If possible we prefer to use Behat
I think it would be much harder to have reliable Behat tests and would require more work to write and maintain. Not worth it IMO.
Shouldn't we add the integration tests in another file
IMO it's fine to keep it here: all tests in this file cover the same subject. But if you prefer, I can extract it to it own file.
31678f6
to
f555c83
Compare
f555c83
to
10c64a8
Compare
@julienfalque LGTM. Could you provide a documentation? |
10c64a8
to
96b854b
Compare
Thank you @julienfalque. |
Thank you @alanpoulain @dunglas. Sorry I didn't update the documentation, I totally forgot about your request. |
When creating a custom controller, the argument which is passed the deserialized payload of the request must be named
$data
. This can be very frustrating, especially when you don't know this requirement and you don't understand why your controller is not working properly.This PR introduces a controller value resolver that allows to use any argument name, as long as its type declaration matches the resource class.