-
-
Notifications
You must be signed in to change notification settings - Fork 935
Description
API Platform version(s) affected: 4.4.2
Description
When using the ReadLinkParameterProvider to automatically load parent DTO as an uriVariable, the serialization encounters issues while trying to generate IRI.
How to reproduce
- Create a DTO that loads another one
<?php namespace App\ApiResource; use ApiPlatform\Metadata\ApiProperty; use ApiPlatform\Metadata\ApiResource; use ApiPlatform\Metadata\Get; use ApiPlatform\Metadata\Link; use ApiPlatform\State\ParameterProvider\ReadLinkParameterProvider; #[ApiResource( operations: [ new Get( uriTemplate: '/hello/{world}', uriVariables: [ 'world' => new Link(fromClass: World::class, provider: ReadLinkParameterProvider::class), ], provider: HelloWorldProvider::class, ) ] )] final readonly class TestResource { public function __construct( #[ApiProperty(identifier: true)] public int $id, ) { } }
Call /hello/34 (where 34 is World resource identifier value) while accepting application/ld+json.
At this point, in my HelloWorldProvider, if World was found, I have a World resource into $operation->getUriVariables()['world'], but $uriVariables['world'] is still (string) 34, and I can return whatever value I want from my provider.
If I only accepts application/json, everything works fine. But if I accept application/ld+json, it goes wild and I get an error from Symfony's UrlGenerator regarding the type of one of the arguments used to generate an IRI.
When rebuilding operation's uriVariables in https://github.com/api-platform/core/blob/main/src/Symfony/Controller/MainController.php#L102 , resource class that was previously injected in operation's uriVariables bag is now passed to $uriVariables which is used for serialization context, but when times come to generate resource's IRI, the resource world cannot be used as a value for UrlGenerator.
Possible Solution
When serializing data using https://github.com/api-platform/core/blob/main/src/State/Processor/SerializeProcessor.php#L69 , $uriVariables values that are related to a Link into current Operation should be swapped with their identifier. (Ex: World resource with id 34 should be replaced with 34 instead of the whole object)
Additional Context
Call stack before exception
I found a temporary workaround by adding a __toString method to my World resource that returns it's identifier as string.
I may provide a PR solving this issue during this week.