diff --git a/src/JsonLd/Serializer/ItemNormalizer.php b/src/JsonLd/Serializer/ItemNormalizer.php index c668df6fd62..3b0a480a409 100644 --- a/src/JsonLd/Serializer/ItemNormalizer.php +++ b/src/JsonLd/Serializer/ItemNormalizer.php @@ -124,7 +124,8 @@ public function normalize(mixed $object, ?string $format = null, array $context unset($context['operation'], $context['operation_name']); } - if (true === ($context['output']['gen_id'] ?? true) && true === ($context['force_iri_generation'] ?? true) && $iri = $this->iriConverter->getIriFromResource($object, UrlGeneratorInterface::ABS_PATH, $context['operation'] ?? null, $context)) { + $operation = $context['operation'] ?? null; + if (true === ($context['output']['gen_id'] ?? true) && true === ($context['force_iri_generation'] ?? true) && $iri = $this->iriConverter->getIriFromResource($object, $operation?->getUrlGenerationStrategy() ?? UrlGeneratorInterface::ABS_PATH, $operation, $context)) { $context['iri'] = $iri; $metadata['@id'] = $iri; } diff --git a/src/Serializer/OperationContextTrait.php b/src/Serializer/OperationContextTrait.php index 515d2a0ded8..7cb9a51bbda 100644 --- a/src/Serializer/OperationContextTrait.php +++ b/src/Serializer/OperationContextTrait.php @@ -34,7 +34,7 @@ protected function createOperationContext(array $context, ?string $resourceClass $context['root_operation_name'] = $context['operation_name'] ?? $context['graphql_operation_name']; } - unset($context['iri'], $context['uri_variables'], $context['item_uri_template'], $context['force_resource_class']); + unset($context['iri'], $context['uri_variables'], $context['item_uri_template'], $context['force_resource_class'], $context['output']['gen_id']); // At some point we should merge the jsonld context here, there's a TODO to simplify this somewhere else if ($propertyMetadata) { diff --git a/tests/Fixtures/TestBundle/ApiResource/GenIdFalse/LevelFirst.php b/tests/Fixtures/TestBundle/ApiResource/GenIdFalse/LevelFirst.php new file mode 100644 index 00000000000..4910547d490 --- /dev/null +++ b/tests/Fixtures/TestBundle/ApiResource/GenIdFalse/LevelFirst.php @@ -0,0 +1,32 @@ + + * + * 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\Tests\Fixtures\TestBundle\ApiResource\GenIdFalse; + +use ApiPlatform\Metadata\ApiProperty; +use ApiPlatform\Metadata\ApiResource; +use ApiPlatform\Metadata\Get; +use ApiPlatform\Metadata\Operation; + +#[ApiResource(operations: [new Get(uriTemplate: '/levelfirst/{id}', provider: [self::class, 'provider'])])] +class LevelFirst +{ + public function __construct(public string $id, #[ApiProperty(genId: false)] public LevelSecond $levelSecond) + { + } + + public static function provider(Operation $operation, array $uriVariables = [], array $context = []): self + { + return new self($uriVariables['id'], new LevelSecond(new LevelThird('3', 'L3 Name'))); + } +} diff --git a/tests/Fixtures/TestBundle/ApiResource/GenIdFalse/LevelSecond.php b/tests/Fixtures/TestBundle/ApiResource/GenIdFalse/LevelSecond.php new file mode 100644 index 00000000000..93064ad1c5b --- /dev/null +++ b/tests/Fixtures/TestBundle/ApiResource/GenIdFalse/LevelSecond.php @@ -0,0 +1,24 @@ + + * + * 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\Tests\Fixtures\TestBundle\ApiResource\GenIdFalse; + +use ApiPlatform\Metadata\NotExposed; + +#[NotExposed()] +class LevelSecond +{ + public function __construct(public LevelThird $levelThird) + { + } +} diff --git a/tests/Fixtures/TestBundle/ApiResource/GenIdFalse/LevelThird.php b/tests/Fixtures/TestBundle/ApiResource/GenIdFalse/LevelThird.php new file mode 100644 index 00000000000..d8c5a35e8b3 --- /dev/null +++ b/tests/Fixtures/TestBundle/ApiResource/GenIdFalse/LevelThird.php @@ -0,0 +1,25 @@ + + * + * 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\Tests\Fixtures\TestBundle\ApiResource\GenIdFalse; + +use ApiPlatform\Metadata\ApiResource; +use ApiPlatform\Metadata\Get; + +#[ApiResource(operations: [new Get(uriTemplate: '/levelthird/{id}')])] +class LevelThird +{ + public function __construct(public string $id, public string $name) + { + } +} diff --git a/tests/Functional/JsonLdTest.php b/tests/Functional/JsonLdTest.php index 2b2e8f698bb..c1d78f81060 100644 --- a/tests/Functional/JsonLdTest.php +++ b/tests/Functional/JsonLdTest.php @@ -16,6 +16,9 @@ use ApiPlatform\Symfony\Bundle\Test\ApiTestCase; use ApiPlatform\Tests\Fixtures\TestBundle\ApiResource\GenIdFalse\AggregateRating; use ApiPlatform\Tests\Fixtures\TestBundle\ApiResource\GenIdFalse\GenIdFalse; +use ApiPlatform\Tests\Fixtures\TestBundle\ApiResource\GenIdFalse\LevelFirst; +use ApiPlatform\Tests\Fixtures\TestBundle\ApiResource\GenIdFalse\LevelSecond; +use ApiPlatform\Tests\Fixtures\TestBundle\ApiResource\GenIdFalse\LevelThird; use ApiPlatform\Tests\Fixtures\TestBundle\ApiResource\Issue6810\JsonLdContextOutput; use ApiPlatform\Tests\Fixtures\TestBundle\Entity\Issue6465\Bar; use ApiPlatform\Tests\Fixtures\TestBundle\Entity\Issue6465\Foo; @@ -34,7 +37,7 @@ class JsonLdTest extends ApiTestCase */ public static function getResources(): array { - return [Foo::class, Bar::class, JsonLdContextOutput::class, GenIdFalse::class, AggregateRating::class]; + return [Foo::class, Bar::class, JsonLdContextOutput::class, GenIdFalse::class, AggregateRating::class, LevelFirst::class, LevelSecond::class, LevelThird::class]; } /** @@ -81,6 +84,19 @@ public function testGenIdFalseOnResource(): void $this->assertArrayNotHasKey('@id', $r->toArray()['aggregateRating']); } + public function testGenIdFalseOnNestedResource(): void + { + $r = self::createClient()->request( + 'GET', + '/levelfirst/1', + ); + $this->assertJsonContains([ + 'levelSecond' => [ + 'levelThird' => '/levelthird/3', + ], + ]); + } + public function testShouldIgnoreProperty(): void { $r = self::createClient()->request(