From 63cf9bf3b05518c712646727bb3569850ec5a198 Mon Sep 17 00:00:00 2001 From: soyuka Date: Wed, 17 Jun 2026 16:50:16 +0200 Subject: [PATCH 1/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 f7feddc373c..e1ca3a70eed 100644 --- a/src/Symfony/Bundle/DependencyInjection/ApiPlatformExtension.php +++ b/src/Symfony/Bundle/DependencyInjection/ApiPlatformExtension.php @@ -708,13 +708,19 @@ 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; + } + $itemNormalizer = $container->getDefinition('api_platform.jsonapi.normalizer.item'); $itemNormalizer->replaceArgument(7, [JsonApiItemNormalizer::ALLOW_CLIENT_GENERATED_ID => $config['jsonapi']['allow_client_generated_id'] ?? false]); - $itemNormalizer->addArgument($config['jsonapi']['use_iri_as_id']); + $itemNormalizer->addArgument($useIriAsId); $itemDenormalizer = $container->getDefinition('api_platform.jsonapi.denormalizer.item'); $itemDenormalizer->replaceArgument(7, [JsonApiItemNormalizer::ALLOW_CLIENT_GENERATED_ID => $config['jsonapi']['allow_client_generated_id'] ?? false]); - $itemDenormalizer->addArgument($config['jsonapi']['use_iri_as_id']); + $itemDenormalizer->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 0c9e3c07dec..27f5cfbd2be 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() ->booleanNode('allow_client_generated_id') ->defaultFalse() 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 914d4bc77e7..c139336e1b9 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 376fd93a473225c16984359e048bbefec31a5211 Mon Sep 17 00:00:00 2001 From: soyuka Date: Wed, 17 Jun 2026 21:43:33 +0200 Subject: [PATCH 2/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, From 30db4971a7da55862d9747af181618083e865319 Mon Sep 17 00:00:00 2001 From: soyuka Date: Mon, 22 Jun 2026 10:44:21 +0200 Subject: [PATCH 3/3] test(symfony): set jsonapi.use_iri_as_id explicitly in shared test config The 4.4 deprecation for an unset "api_platform.jsonapi.use_iri_as_id" fires throughout the functional suite, failing the "no deprecations" and "Symfony dev" CI jobs (run with max[self]=0). Set it to true in config_common.yml to preserve the current default behavior and silence the self-inflicted deprecation. The intentional deprecation assertions live in JsonApiUseIriAsIdDeprecationTest (#[Group('legacy')]). --- tests/Fixtures/app/config/config_common.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/Fixtures/app/config/config_common.yml b/tests/Fixtures/app/config/config_common.yml index d03cbd48b35..b046bc20e2f 100644 --- a/tests/Fixtures/app/config/config_common.yml +++ b/tests/Fixtures/app/config/config_common.yml @@ -61,6 +61,8 @@ api_platform: jsonapi: ['application/vnd.api+json'] html: ['text/html'] xml: ['application/xml', 'text/xml'] + jsonapi: + use_iri_as_id: true graphql: enabled: true nesting_separator: __