From a2732929498091ffdd0bdf5a9dbb28cb5ae50a67 Mon Sep 17 00:00:00 2001 From: Joel Wurtz Date: Thu, 3 Sep 2026 14:55:57 +0200 Subject: [PATCH] fix(apiplatform): resolve IRIs in every JSON format, not only JSON-LD --- CHANGELOG.md | 1 + src/Provider/ApiPlatform/IriProvider.php | 8 +++++++- tests/Bundle/ApiPlatformTest.php | 19 +++++++++++++++++++ .../Resources/App/Api/Entity/Review.php | 5 ++++- .../App/Api/Processor/ReviewProcessor.php | 17 +++++++++++++++++ 5 files changed, 48 insertions(+), 2 deletions(-) create mode 100644 tests/Bundle/Resources/App/Api/Processor/ReviewProcessor.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 38c225ac..53b4eacc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 source and target names ### Fixed +- Resolve API Platform IRIs in every JSON format, not only JSON-LD, so a relation sent as an IRI on `application/json` or `application/merge-patch+json` no longer reaches the mapper as a raw string - Use the `MapFrom` attribute reference instead of `MapTo` when resolving transformers in `MapFromListener` - Do not run a transformation on a null source value when the target is not nullable, a `TypeError` is thrown for typed properties instead of the transformation crashing on the null value - Create backed enum from scalar source value instead of assigning the raw scalar diff --git a/src/Provider/ApiPlatform/IriProvider.php b/src/Provider/ApiPlatform/IriProvider.php index a2b82baa..1fc4c63d 100644 --- a/src/Provider/ApiPlatform/IriProvider.php +++ b/src/Provider/ApiPlatform/IriProvider.php @@ -12,6 +12,12 @@ final readonly class IriProvider implements ProviderInterface { + /** + * Formats where a relation is carried as an IRI string, so not only JSON-LD: + * API Platform's default patch_formats maps application/merge-patch+json to the "json" format. + */ + private const array SUPPORTED_FORMATS = ['jsonld', 'json', 'jsonhal', 'jsonapi']; + public function __construct( private IriConverterInterface $iriConverter, private ResourceClassResolverInterface $resourceClassResolver, @@ -20,7 +26,7 @@ public function __construct( public function provide(string $targetType, mixed $source, array $context, mixed $id): ?object { - if (($context[MapperContext::NORMALIZER_FORMAT] ?? false) !== 'jsonld') { + if (!\in_array($context[MapperContext::NORMALIZER_FORMAT] ?? null, self::SUPPORTED_FORMATS, true)) { return null; } diff --git a/tests/Bundle/ApiPlatformTest.php b/tests/Bundle/ApiPlatformTest.php index 2c31d494..bb801091 100644 --- a/tests/Bundle/ApiPlatformTest.php +++ b/tests/Bundle/ApiPlatformTest.php @@ -147,6 +147,25 @@ public function testUpdateBook(): void ]); } + public function testCreateWithIriRelationInPlainJson(): void + { + $response = static::createClient()->request('POST', '/reviews', [ + 'json' => [ + 'rating' => 5, + 'body' => 'A great book.', + 'author' => 'Someone', + 'book' => '/books/1', + ], + 'headers' => [ + 'Content-Type' => 'application/json', + 'Accept' => 'application/json', + ], + ]); + + $this->assertResponseIsSuccessful(); + $this->assertSame('/books/1', $response->toArray()['book']); + } + protected function tearDown(): void { parent::tearDown(); diff --git a/tests/Bundle/Resources/App/Api/Entity/Review.php b/tests/Bundle/Resources/App/Api/Entity/Review.php index 36ffff23..ed5cf9d3 100644 --- a/tests/Bundle/Resources/App/Api/Entity/Review.php +++ b/tests/Bundle/Resources/App/Api/Entity/Review.php @@ -5,9 +5,12 @@ namespace AutoMapper\Tests\Bundle\Resources\App\Api\Entity; use ApiPlatform\Metadata\ApiResource; +use AutoMapper\Attribute\Mapper; +use AutoMapper\Tests\Bundle\Resources\App\Api\Processor\ReviewProcessor; /** A book. */ -#[ApiResource] +#[ApiResource(processor: ReviewProcessor::class)] +#[Mapper(source: 'array', target: 'array')] class Review { /** The ID of this review. */ diff --git a/tests/Bundle/Resources/App/Api/Processor/ReviewProcessor.php b/tests/Bundle/Resources/App/Api/Processor/ReviewProcessor.php new file mode 100644 index 00000000..7208251d --- /dev/null +++ b/tests/Bundle/Resources/App/Api/Processor/ReviewProcessor.php @@ -0,0 +1,17 @@ +