From f0aae23d10fdc84f29116d379bb149a89248c28b Mon Sep 17 00:00:00 2001 From: soyuka Date: Tue, 19 May 2026 16:37:49 +0200 Subject: [PATCH 1/3] feat(jsonld): add resource-level jsonldContext for namespace prefixes Allows defining JSON-LD namespace prefix entries (e.g. `dct: http://purl.org/dc/terms/`) directly on ApiResource/HttpOperation, which get merged into the generated `@context` output. Closes #767 --- src/JsonLd/ContextBuilder.php | 5 +++++ src/Metadata/ApiResource.php | 21 +++++++++++++++++++ src/Metadata/Delete.php | 2 ++ src/Metadata/Error.php | 2 ++ src/Metadata/ErrorResource.php | 2 ++ .../Extractor/XmlResourceExtractor.php | 1 + .../Extractor/YamlResourceExtractor.php | 1 + src/Metadata/Get.php | 2 ++ src/Metadata/GetCollection.php | 2 ++ src/Metadata/HttpOperation.php | 14 +++++++++++++ src/Metadata/McpResource.php | 2 ++ src/Metadata/McpTool.php | 2 ++ src/Metadata/NotExposed.php | 2 ++ src/Metadata/Patch.php | 2 ++ src/Metadata/Post.php | 2 ++ src/Metadata/Put.php | 2 ++ .../ApiResource/JsonLd/JsonLdContextDummy.php | 4 ++++ tests/Functional/JsonLd/ContextTest.php | 9 ++++++++ 18 files changed, 77 insertions(+) diff --git a/src/JsonLd/ContextBuilder.php b/src/JsonLd/ContextBuilder.php index 4f35aa67057..65fa1f58985 100644 --- a/src/JsonLd/ContextBuilder.php +++ b/src/JsonLd/ContextBuilder.php @@ -180,6 +180,11 @@ private function generateContextUri(?string $shortName, ?int $referenceType): st private function getResourceContextWithShortname(string $resourceClass, int $referenceType, string $shortName, ?HttpOperation $operation = null): array { $context = $this->getBaseContext($referenceType); + + if ($operation && $jsonldContext = $operation->getJsonldContext()) { + $context = array_merge($context, $jsonldContext); + } + $propertyContext = $operation ? ['normalization_groups' => $operation->getNormalizationContext()['groups'] ?? null, 'denormalization_groups' => $operation->getDenormalizationContext()['groups'] ?? null] : ['normalization_groups' => [], 'denormalization_groups' => []]; foreach ($this->propertyNameCollectionFactory->create($resourceClass) as $propertyName) { diff --git a/src/Metadata/ApiResource.php b/src/Metadata/ApiResource.php index eabfdda8fc0..32922afb1d7 100644 --- a/src/Metadata/ApiResource.php +++ b/src/Metadata/ApiResource.php @@ -326,6 +326,14 @@ public function __construct( protected ?array $denormalizationContext = null, protected ?bool $collectDenormalizationErrors = null, protected ?array $hydraContext = null, + /** + * Extra entries to merge into the JSON-LD `@context` for this resource (e.g. namespace prefix declarations). + * + * Example: `jsonldContext: ['dct' => 'http://purl.org/dc/terms/']` + * + * @see https://api-platform.com/docs/core/extending-jsonld-context/ + */ + protected ?array $jsonldContext = null, protected bool|OpenApiOperation|null $openapi = null, /** * The `validationContext` option configures the context of validation for the current ApiResource. @@ -1373,6 +1381,19 @@ public function withHydraContext(array $hydraContext): static return $self; } + public function getJsonldContext(): ?array + { + return $this->jsonldContext; + } + + public function withJsonldContext(array $jsonldContext): static + { + $self = clone $this; + $self->jsonldContext = $jsonldContext; + + return $self; + } + public function getOpenapi(): bool|OpenApiOperation|null { return $this->openapi; diff --git a/src/Metadata/Delete.php b/src/Metadata/Delete.php index b4e55ef6765..3674a5d6fe9 100644 --- a/src/Metadata/Delete.php +++ b/src/Metadata/Delete.php @@ -44,6 +44,7 @@ public function __construct( ?array $cacheHeaders = null, ?array $paginationViaCursor = null, ?array $hydraContext = null, + ?array $jsonldContext = null, bool|OpenApiOperation|Webhook|null $openapi = null, ?array $exceptionToStatus = null, ?bool $queryParameterValidationEnabled = null, @@ -129,6 +130,7 @@ public function __construct( cacheHeaders: $cacheHeaders, paginationViaCursor: $paginationViaCursor, hydraContext: $hydraContext, + jsonldContext: $jsonldContext, openapi: $openapi, exceptionToStatus: $exceptionToStatus, queryParameterValidationEnabled: $queryParameterValidationEnabled, diff --git a/src/Metadata/Error.php b/src/Metadata/Error.php index dabe1b854d5..c7c34733459 100644 --- a/src/Metadata/Error.php +++ b/src/Metadata/Error.php @@ -44,6 +44,7 @@ public function __construct( ?array $cacheHeaders = null, ?array $paginationViaCursor = null, ?array $hydraContext = null, + ?array $jsonldContext = null, bool|OpenApiOperation|Webhook|null $openapi = null, ?array $exceptionToStatus = null, ?bool $queryParameterValidationEnabled = null, @@ -123,6 +124,7 @@ public function __construct( cacheHeaders: $cacheHeaders, paginationViaCursor: $paginationViaCursor, hydraContext: $hydraContext, + jsonldContext: $jsonldContext, openapi: $openapi, exceptionToStatus: $exceptionToStatus, queryParameterValidationEnabled: $queryParameterValidationEnabled, diff --git a/src/Metadata/ErrorResource.php b/src/Metadata/ErrorResource.php index 8f1586ac038..c3700713617 100644 --- a/src/Metadata/ErrorResource.php +++ b/src/Metadata/ErrorResource.php @@ -49,6 +49,7 @@ public function __construct( ?array $denormalizationContext = null, ?bool $collectDenormalizationErrors = null, ?array $hydraContext = null, + ?array $jsonldContext = null, OpenApiOperation|bool|null $openapi = null, ?array $validationContext = null, ?array $filters = null, @@ -116,6 +117,7 @@ class: $class, denormalizationContext: $denormalizationContext, collectDenormalizationErrors: $collectDenormalizationErrors, hydraContext: $hydraContext, + jsonldContext: $jsonldContext, openapi: $openapi, validationContext: $validationContext, filters: $filters, diff --git a/src/Metadata/Extractor/XmlResourceExtractor.php b/src/Metadata/Extractor/XmlResourceExtractor.php index 6ebc1a66bf8..4d3c3206b53 100644 --- a/src/Metadata/Extractor/XmlResourceExtractor.php +++ b/src/Metadata/Extractor/XmlResourceExtractor.php @@ -93,6 +93,7 @@ private function buildExtendedBase(\SimpleXMLElement $resource): array 'schemes' => $this->buildArrayValue($resource, 'scheme'), 'cacheHeaders' => $this->buildCacheHeaders($resource), 'hydraContext' => isset($resource->hydraContext->values) ? $this->buildValues($resource->hydraContext->values) : null, + 'jsonldContext' => isset($resource->jsonldContext->values) ? $this->buildValues($resource->jsonldContext->values) : null, 'openapi' => $this->buildOpenapi($resource), 'paginationViaCursor' => $this->buildPaginationViaCursor($resource), 'exceptionToStatus' => $this->buildExceptionToStatus($resource), diff --git a/src/Metadata/Extractor/YamlResourceExtractor.php b/src/Metadata/Extractor/YamlResourceExtractor.php index e7dd40093c8..67848c56942 100644 --- a/src/Metadata/Extractor/YamlResourceExtractor.php +++ b/src/Metadata/Extractor/YamlResourceExtractor.php @@ -114,6 +114,7 @@ private function buildExtendedBase(array $resource): array 'types' => $this->buildArrayValue($resource, 'types'), 'cacheHeaders' => $this->buildArrayValue($resource, 'cacheHeaders'), 'hydraContext' => $this->buildArrayValue($resource, 'hydraContext'), + 'jsonldContext' => $this->buildArrayValue($resource, 'jsonldContext'), 'openapi' => $this->buildOpenapi($resource), 'paginationViaCursor' => $this->buildArrayValue($resource, 'paginationViaCursor'), 'exceptionToStatus' => $this->buildArrayValue($resource, 'exceptionToStatus'), diff --git a/src/Metadata/Get.php b/src/Metadata/Get.php index 4babd54eb27..4c59d7ab957 100644 --- a/src/Metadata/Get.php +++ b/src/Metadata/Get.php @@ -44,6 +44,7 @@ public function __construct( ?array $cacheHeaders = null, ?array $paginationViaCursor = null, ?array $hydraContext = null, + ?array $jsonldContext = null, bool|OpenApiOperation|Webhook|null $openapi = null, ?array $exceptionToStatus = null, ?bool $queryParameterValidationEnabled = null, @@ -128,6 +129,7 @@ public function __construct( cacheHeaders: $cacheHeaders, paginationViaCursor: $paginationViaCursor, hydraContext: $hydraContext, + jsonldContext: $jsonldContext, openapi: $openapi, exceptionToStatus: $exceptionToStatus, queryParameterValidationEnabled: $queryParameterValidationEnabled, diff --git a/src/Metadata/GetCollection.php b/src/Metadata/GetCollection.php index 27df4b9ad41..6256366bd27 100644 --- a/src/Metadata/GetCollection.php +++ b/src/Metadata/GetCollection.php @@ -44,6 +44,7 @@ public function __construct( ?array $cacheHeaders = null, ?array $paginationViaCursor = null, ?array $hydraContext = null, + ?array $jsonldContext = null, bool|OpenApiOperation|Webhook|null $openapi = null, ?array $exceptionToStatus = null, ?bool $queryParameterValidationEnabled = null, @@ -129,6 +130,7 @@ public function __construct( cacheHeaders: $cacheHeaders, paginationViaCursor: $paginationViaCursor, hydraContext: $hydraContext, + jsonldContext: $jsonldContext, openapi: $openapi, exceptionToStatus: $exceptionToStatus, queryParameterValidationEnabled: $queryParameterValidationEnabled, diff --git a/src/Metadata/HttpOperation.php b/src/Metadata/HttpOperation.php index 58d4cf98c7f..32dfa15bb7e 100644 --- a/src/Metadata/HttpOperation.php +++ b/src/Metadata/HttpOperation.php @@ -164,6 +164,7 @@ public function __construct( protected ?array $cacheHeaders = null, protected ?array $paginationViaCursor = null, protected ?array $hydraContext = null, + protected ?array $jsonldContext = null, protected bool|OpenApiOperation|Webhook|null $openapi = null, protected ?array $exceptionToStatus = null, protected ?array $links = null, @@ -629,6 +630,19 @@ public function withHydraContext(array $hydraContext): static return $self; } + public function getJsonldContext(): ?array + { + return $this->jsonldContext; + } + + public function withJsonldContext(array $jsonldContext): static + { + $self = clone $this; + $self->jsonldContext = $jsonldContext; + + return $self; + } + public function getOpenapi(): bool|OpenApiOperation|Webhook|null { return $this->openapi; diff --git a/src/Metadata/McpResource.php b/src/Metadata/McpResource.php index c36342c1e6b..5be8ab91f35 100644 --- a/src/Metadata/McpResource.php +++ b/src/Metadata/McpResource.php @@ -126,6 +126,7 @@ public function __construct( ?array $cacheHeaders = null, ?array $paginationViaCursor = null, ?array $hydraContext = null, + ?array $jsonldContext = null, bool|OpenApiOperation|Webhook|null $openapi = null, ?array $exceptionToStatus = null, ?array $links = null, @@ -209,6 +210,7 @@ public function __construct( cacheHeaders: $cacheHeaders, paginationViaCursor: $paginationViaCursor, hydraContext: $hydraContext, + jsonldContext: $jsonldContext, openapi: $openapi, exceptionToStatus: $exceptionToStatus, links: $links, diff --git a/src/Metadata/McpTool.php b/src/Metadata/McpTool.php index 465da19d76f..f46f7a297d8 100644 --- a/src/Metadata/McpTool.php +++ b/src/Metadata/McpTool.php @@ -122,6 +122,7 @@ public function __construct( ?array $cacheHeaders = null, ?array $paginationViaCursor = null, ?array $hydraContext = null, + ?array $jsonldContext = null, bool|OpenApiOperation|Webhook|null $openapi = null, ?array $exceptionToStatus = null, ?array $links = null, @@ -205,6 +206,7 @@ public function __construct( cacheHeaders: $cacheHeaders, paginationViaCursor: $paginationViaCursor, hydraContext: $hydraContext, + jsonldContext: $jsonldContext, openapi: $openapi, exceptionToStatus: $exceptionToStatus, links: $links, diff --git a/src/Metadata/NotExposed.php b/src/Metadata/NotExposed.php index e106aa23b4e..c3422bac243 100644 --- a/src/Metadata/NotExposed.php +++ b/src/Metadata/NotExposed.php @@ -56,6 +56,7 @@ public function __construct( ?array $paginationViaCursor = null, ?array $hydraContext = null, + ?array $jsonldContext = null, bool|OpenApiOperation|Webhook|null $openapi = false, ?array $exceptionToStatus = null, @@ -135,6 +136,7 @@ public function __construct( cacheHeaders: $cacheHeaders, paginationViaCursor: $paginationViaCursor, hydraContext: $hydraContext, + jsonldContext: $jsonldContext, openapi: $openapi, exceptionToStatus: $exceptionToStatus, queryParameterValidationEnabled: $queryParameterValidationEnabled, diff --git a/src/Metadata/Patch.php b/src/Metadata/Patch.php index 13d7dc442a0..e6147a18dad 100644 --- a/src/Metadata/Patch.php +++ b/src/Metadata/Patch.php @@ -44,6 +44,7 @@ public function __construct( ?array $cacheHeaders = null, ?array $paginationViaCursor = null, ?array $hydraContext = null, + ?array $jsonldContext = null, bool|OpenApiOperation|Webhook|null $openapi = null, ?array $exceptionToStatus = null, ?bool $queryParameterValidationEnabled = null, @@ -129,6 +130,7 @@ public function __construct( cacheHeaders: $cacheHeaders, paginationViaCursor: $paginationViaCursor, hydraContext: $hydraContext, + jsonldContext: $jsonldContext, openapi: $openapi, exceptionToStatus: $exceptionToStatus, queryParameterValidationEnabled: $queryParameterValidationEnabled, diff --git a/src/Metadata/Post.php b/src/Metadata/Post.php index 419512a851d..e68e4b0ec66 100644 --- a/src/Metadata/Post.php +++ b/src/Metadata/Post.php @@ -44,6 +44,7 @@ public function __construct( ?array $cacheHeaders = null, ?array $paginationViaCursor = null, ?array $hydraContext = null, + ?array $jsonldContext = null, bool|OpenApiOperation|Webhook|null $openapi = null, ?array $exceptionToStatus = null, ?bool $queryParameterValidationEnabled = null, @@ -130,6 +131,7 @@ public function __construct( cacheHeaders: $cacheHeaders, paginationViaCursor: $paginationViaCursor, hydraContext: $hydraContext, + jsonldContext: $jsonldContext, openapi: $openapi, exceptionToStatus: $exceptionToStatus, queryParameterValidationEnabled: $queryParameterValidationEnabled, diff --git a/src/Metadata/Put.php b/src/Metadata/Put.php index 3ea21ffeadd..73632c786bc 100644 --- a/src/Metadata/Put.php +++ b/src/Metadata/Put.php @@ -44,6 +44,7 @@ public function __construct( ?array $cacheHeaders = null, ?array $paginationViaCursor = null, ?array $hydraContext = null, + ?array $jsonldContext = null, bool|OpenApiOperation|Webhook|null $openapi = null, ?array $exceptionToStatus = null, ?bool $queryParameterValidationEnabled = null, @@ -130,6 +131,7 @@ public function __construct( cacheHeaders: $cacheHeaders, paginationViaCursor: $paginationViaCursor, hydraContext: $hydraContext, + jsonldContext: $jsonldContext, openapi: $openapi, exceptionToStatus: $exceptionToStatus, queryParameterValidationEnabled: $queryParameterValidationEnabled, diff --git a/tests/Fixtures/TestBundle/ApiResource/JsonLd/JsonLdContextDummy.php b/tests/Fixtures/TestBundle/ApiResource/JsonLd/JsonLdContextDummy.php index 18cd539f17a..ab545ac6936 100644 --- a/tests/Fixtures/TestBundle/ApiResource/JsonLd/JsonLdContextDummy.php +++ b/tests/Fixtures/TestBundle/ApiResource/JsonLd/JsonLdContextDummy.php @@ -20,6 +20,7 @@ shortName: 'JsonLdContextDummy', provider: [self::class, 'provide'], processor: [self::class, 'process'], + jsonldContext: ['dct' => 'http://purl.org/dc/terms/'], )] class JsonLdContextDummy { @@ -29,6 +30,9 @@ class JsonLdContextDummy #[ApiProperty(iris: ['https://schema.org/name'])] public ?string $name = null; + #[ApiProperty(iris: ['dct:title'])] + public ?string $title = null; + #[ApiProperty(iris: ['https://schema.org/alternateName'])] public ?string $alias = null; diff --git a/tests/Functional/JsonLd/ContextTest.php b/tests/Functional/JsonLd/ContextTest.php index dd768a9cf55..6906f979db2 100644 --- a/tests/Functional/JsonLd/ContextTest.php +++ b/tests/Functional/JsonLd/ContextTest.php @@ -112,4 +112,13 @@ public function testEmbeddedRelationMappingIsPlainString(): void $body = $response->toArray(); $this->assertSame('JsonLdContextDummy/embedded', $body['@context']['embedded']); } + + public function testResourceLevelJsonLdContextAddsNamespacePrefixes(): void + { + $response = self::createClient()->request('GET', '/contexts/JsonLdContextDummy'); + $this->assertResponseIsSuccessful(); + $body = $response->toArray(); + $this->assertSame('http://purl.org/dc/terms/', $body['@context']['dct']); + $this->assertSame('dct:title', $body['@context']['title']); + } } From cef23d4a30a0bbb878addffda58a4b3e6317857f Mon Sep 17 00:00:00 2001 From: soyuka Date: Wed, 17 Jun 2026 16:50:16 +0200 Subject: [PATCH 2/3] feat(symfony): deprecate jsonapi.use_iri_as_id defaulting to true The "api_platform.jsonapi.use_iri_as_id" option now defaults to null so the extension can tell an unset value from an explicit one. When unset, a 4.4 deprecation is triggered and the value is coerced to true, preserving current behavior. The default will change to false in 5.0. Set the option explicitly to true or false to silence the deprecation. --- .../ApiPlatformExtension.php | 10 +- .../DependencyInjection/Configuration.php | 5 +- .../JsonApiUseIriAsIdDeprecationTest.php | 138 ++++++++++++++++++ src/Symfony/composer.json | 1 + 4 files changed, 149 insertions(+), 5 deletions(-) create mode 100644 src/Symfony/Tests/Bundle/DependencyInjection/JsonApiUseIriAsIdDeprecationTest.php diff --git a/src/Symfony/Bundle/DependencyInjection/ApiPlatformExtension.php b/src/Symfony/Bundle/DependencyInjection/ApiPlatformExtension.php index 0164d273aa6..2f7f034a337 100644 --- a/src/Symfony/Bundle/DependencyInjection/ApiPlatformExtension.php +++ b/src/Symfony/Bundle/DependencyInjection/ApiPlatformExtension.php @@ -705,11 +705,17 @@ private function registerJsonApiConfiguration(ContainerBuilder $container, array $loader->load('jsonapi.php'); $loader->load('state/jsonapi.php'); + $useIriAsId = $config['jsonapi']['use_iri_as_id']; + if (null === $useIriAsId) { + trigger_deprecation('api-platform/core', '4.4', 'Not setting "api_platform.jsonapi.use_iri_as_id" explicitly is deprecated. Its default value will change from "true" to "false" in API Platform 5.0. Set it to "true" to keep the current behavior or to "false" to use entity identifiers as the "id" field, and silence this deprecation.'); + $useIriAsId = true; + } + $container->getDefinition('api_platform.jsonapi.normalizer.item') - ->addArgument($config['jsonapi']['use_iri_as_id']); + ->addArgument($useIriAsId); $container->getDefinition('api_platform.jsonapi.denormalizer.item') - ->addArgument($config['jsonapi']['use_iri_as_id']); + ->addArgument($useIriAsId); } private function registerJsonLdHydraConfiguration(ContainerBuilder $container, array $formats, PhpFileLoader $loader, array $config): void diff --git a/src/Symfony/Bundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/DependencyInjection/Configuration.php index 911de422fdb..77748335148 100644 --- a/src/Symfony/Bundle/DependencyInjection/Configuration.php +++ b/src/Symfony/Bundle/DependencyInjection/Configuration.php @@ -100,13 +100,12 @@ public function getConfigTreeBuilder(): TreeBuilder ->end() ->end() ->end() - // TODO 4.4: deprecate use_iri_as_id defaulting to true ->arrayNode('jsonapi') ->addDefaultsIfNotSet() ->children() ->booleanNode('use_iri_as_id') - ->defaultTrue() - ->info('Set to false to use entity identifiers instead of IRIs as the "id" field in JSON:API responses.') + ->defaultNull() + ->info('Set to false to use entity identifiers instead of IRIs as the "id" field in JSON:API responses. Defaults to true; this default will change to false in API Platform 5.0.') ->end() ->end() ->end() diff --git a/src/Symfony/Tests/Bundle/DependencyInjection/JsonApiUseIriAsIdDeprecationTest.php b/src/Symfony/Tests/Bundle/DependencyInjection/JsonApiUseIriAsIdDeprecationTest.php new file mode 100644 index 00000000000..83f34ce3c49 --- /dev/null +++ b/src/Symfony/Tests/Bundle/DependencyInjection/JsonApiUseIriAsIdDeprecationTest.php @@ -0,0 +1,138 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace ApiPlatform\Symfony\Tests\Bundle\DependencyInjection; + +use ApiPlatform\Metadata\Exception\ExceptionInterface; +use ApiPlatform\Metadata\Exception\InvalidArgumentException; +use ApiPlatform\Metadata\UrlGeneratorInterface; +use ApiPlatform\Symfony\Bundle\DependencyInjection\ApiPlatformExtension; +use ApiPlatform\Tests\Fixtures\TestBundle\TestBundle; +use Doctrine\Bundle\DoctrineBundle\DoctrineBundle; +use Doctrine\ORM\OptimisticLockException; +use PHPUnit\Framework\Attributes\Group; +use PHPUnit\Framework\Attributes\IgnoreDeprecations; +use PHPUnit\Framework\TestCase; +use Symfony\Bundle\SecurityBundle\SecurityBundle; +use Symfony\Bundle\TwigBundle\TwigBundle; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag; +use Symfony\Component\HttpFoundation\Response; + +final class JsonApiUseIriAsIdDeprecationTest extends TestCase +{ + private ContainerBuilder $container; + + protected function setUp(): void + { + $containerParameterBag = new ParameterBag([ + 'kernel.bundles' => [ + 'DoctrineBundle' => DoctrineBundle::class, + 'SecurityBundle' => SecurityBundle::class, + 'TwigBundle' => TwigBundle::class, + ], + 'kernel.bundles_metadata' => [ + 'TestBundle' => [ + 'parent' => null, + 'path' => realpath(__DIR__.'/../../../Fixtures/TestBundle'), + 'namespace' => TestBundle::class, + ], + ], + 'kernel.project_dir' => __DIR__.'/../../../Fixtures/app', + 'kernel.debug' => false, + 'kernel.environment' => 'test', + ]); + + $this->container = new ContainerBuilder($containerParameterBag); + } + + #[Group('legacy')] + #[IgnoreDeprecations] + public function testNotSettingUseIriAsIdIsDeprecatedAndResolvesToTrue(): void + { + $this->expectUserDeprecationMessage('Since api-platform/core 4.4: Not setting "api_platform.jsonapi.use_iri_as_id" explicitly is deprecated. Its default value will change from "true" to "false" in API Platform 5.0. Set it to "true" to keep the current behavior or to "false" to use entity identifiers as the "id" field, and silence this deprecation.'); + + (new ApiPlatformExtension())->load($this->buildConfig(), $this->container); + + $this->assertTrue($this->container->getDefinition('api_platform.jsonapi.normalizer.item')->getArgument(13)); + $this->assertTrue($this->container->getDefinition('api_platform.jsonapi.denormalizer.item')->getArgument(12)); + } + + public function testSettingUseIriAsIdToFalseDoesNotDeprecateAndResolvesToFalse(): void + { + (new ApiPlatformExtension())->load($this->buildConfig(['use_iri_as_id' => false]), $this->container); + + $this->assertFalse($this->container->getDefinition('api_platform.jsonapi.normalizer.item')->getArgument(13)); + $this->assertFalse($this->container->getDefinition('api_platform.jsonapi.denormalizer.item')->getArgument(12)); + } + + public function testSettingUseIriAsIdToTrueDoesNotDeprecateAndResolvesToTrue(): void + { + (new ApiPlatformExtension())->load($this->buildConfig(['use_iri_as_id' => true]), $this->container); + + $this->assertTrue($this->container->getDefinition('api_platform.jsonapi.normalizer.item')->getArgument(13)); + $this->assertTrue($this->container->getDefinition('api_platform.jsonapi.denormalizer.item')->getArgument(12)); + } + + private function buildConfig(?array $jsonapi = null): array + { + $config = ['api_platform' => [ + 'title' => 'title', + 'description' => 'description', + 'version' => 'version', + 'enable_json_streamer' => false, + 'serializer' => ['hydra_prefix' => true], + 'formats' => [ + 'json' => ['mime_types' => ['json']], + 'jsonld' => ['mime_types' => ['application/ld+json']], + 'jsonapi' => ['mime_types' => ['application/vnd.api+json']], + ], + 'doctrine_mongodb_odm' => [ + 'enabled' => true, + ], + 'defaults' => [ + 'extra_properties' => [], + 'url_generation_strategy' => UrlGeneratorInterface::ABS_URL, + ], + 'error_formats' => [ + 'jsonproblem' => ['application/problem+json'], + 'jsonld' => ['application/ld+json'], + ], + 'patch_formats' => [], + 'exception_to_status' => [ + ExceptionInterface::class => Response::HTTP_BAD_REQUEST, + InvalidArgumentException::class => Response::HTTP_BAD_REQUEST, + OptimisticLockException::class => Response::HTTP_CONFLICT, + ], + 'show_webby' => true, + 'eager_loading' => [ + 'enabled' => true, + 'max_joins' => 30, + 'force_eager' => true, + 'fetch_partial' => false, + ], + 'asset_package' => null, + 'enable_entrypoint' => true, + 'enable_docs' => true, + 'enable_swagger' => true, + 'enable_swagger_ui' => true, + 'use_symfony_listeners' => false, + ]]; + + if (null !== $jsonapi) { + $config['api_platform']['jsonapi'] = $jsonapi; + } + + return $config; + } +} diff --git a/src/Symfony/composer.json b/src/Symfony/composer.json index 820533edcb2..aa6a00a65b1 100644 --- a/src/Symfony/composer.json +++ b/src/Symfony/composer.json @@ -55,6 +55,7 @@ "api-platform/elasticsearch": "^4.3", "api-platform/graphql": "^4.3", "api-platform/hal": "^4.3", + "api-platform/json-api": "^4.3", "phpspec/prophecy-phpunit": "^2.2", "phpunit/phpunit": "^11.5 || ^12.2", "symfony/expression-language": "^6.4 || ^7.0 || ^8.0", From 228868628e0db3b766c110e1c620d107b48c42cb Mon Sep 17 00:00:00 2001 From: soyuka Date: Wed, 17 Jun 2026 21:43:33 +0200 Subject: [PATCH 3/3] test(symfony): assert null default for jsonapi.use_iri_as_id Config processing now returns null (default_null); the true coercion happens in the extension. Companion to the deprecation in this PR. --- tests/Symfony/Bundle/DependencyInjection/ConfigurationTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Symfony/Bundle/DependencyInjection/ConfigurationTest.php b/tests/Symfony/Bundle/DependencyInjection/ConfigurationTest.php index ed8e05043a1..a31121d8a19 100644 --- a/tests/Symfony/Bundle/DependencyInjection/ConfigurationTest.php +++ b/tests/Symfony/Bundle/DependencyInjection/ConfigurationTest.php @@ -251,7 +251,7 @@ private function runDefaultConfigTests(array $doctrineIntegrationsToLoad = ['orm 'format' => 'jsonld', ], 'jsonapi' => [ - 'use_iri_as_id' => true, + 'use_iri_as_id' => null, 'allow_client_generated_id' => false, ], 'enable_scalar' => true,