From 1ff2dc0663b905aaa1de9a5461f4a1d098d90d03 Mon Sep 17 00:00:00 2001 From: soyuka Date: Sun, 12 Jul 2026 18:08:40 +0200 Subject: [PATCH 1/3] refactor(serializer): drop redundant uri_variables assignment SerializerContextBuilder::createFromRequest populated uri_variables from raw request attributes, but every serialization consumer overrides it with correctly-parsed values immediately after calling it: SerializeProcessor, DeserializeProvider and Mcp\StructuredContentProcessor. No other caller reads the builder's uri_variables (PayloadArgumentResolver only reads input/resource_class; _api_normalization_context is written, never read for uri_variables). --- src/Serializer/SerializerContextBuilder.php | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/Serializer/SerializerContextBuilder.php b/src/Serializer/SerializerContextBuilder.php index 63ee797f426..b259e6015ea 100644 --- a/src/Serializer/SerializerContextBuilder.php +++ b/src/Serializer/SerializerContextBuilder.php @@ -76,15 +76,6 @@ public function createFromRequest(Request $request, bool $normalization, ?array $context['types'] = $types; } - // TODO: remove this as uri variables are available in the SerializerProcessor but correctly parsed - if ($operation->getUriVariables()) { - $context['uri_variables'] = []; - - foreach (array_keys($operation->getUriVariables()) as $parameterName) { - $context['uri_variables'][$parameterName] = $request->attributes->get($parameterName); - } - } - if (null === $context['output'] && $this->getStateOptionsClass($operation)) { $context['force_resource_class'] = $operation->getClass(); } From 1d7cd69a6d072cbd89775bf305e85e801920374f Mon Sep 17 00:00:00 2001 From: soyuka Date: Sun, 12 Jul 2026 18:08:49 +0200 Subject: [PATCH 2/3] refactor(jsonld)!: resolve reserved short names through their resources MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ContextAction served a hardcoded base @context for the "Error" and "ConstraintViolationList" short names. Exceptions are resources since 3.2: "Error" and the validation resource "ConstraintViolation" now resolve through the normal resource loop. The legacy "ConstraintViolationList" context route had no producer left — responses reference /contexts/ConstraintViolation. BREAKING CHANGE: removes the public ContextAction::RESERVED_SHORT_NAMES constant and the /contexts/ConstraintViolationList route. --- src/JsonLd/Action/ContextAction.php | 10 ---------- tests/Functional/JsonLd/ContextTest.php | 18 ++++++++++++++++++ 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/src/JsonLd/Action/ContextAction.php b/src/JsonLd/Action/ContextAction.php index 74c144ed81b..faa3b0b67f2 100644 --- a/src/JsonLd/Action/ContextAction.php +++ b/src/JsonLd/Action/ContextAction.php @@ -32,11 +32,6 @@ */ final class ContextAction { - public const RESERVED_SHORT_NAMES = [ - 'ConstraintViolationList' => true, - 'Error' => true, - ]; - public function __construct( private readonly ContextBuilderInterface $contextBuilder, private readonly ResourceNameCollectionFactoryInterface $resourceNameCollectionFactory, @@ -90,11 +85,6 @@ private function getContext(string $shortName): ?array return ['@context' => $this->contextBuilder->getEntrypointContext()]; } - // TODO: remove this, exceptions are resources since 3.2 - if (isset(self::RESERVED_SHORT_NAMES[$shortName])) { - return ['@context' => $this->contextBuilder->getBaseContext()]; - } - foreach ($this->resourceNameCollectionFactory->create() as $resourceClass) { $resourceMetadataCollection = $this->resourceMetadataCollectionFactory->create($resourceClass); diff --git a/tests/Functional/JsonLd/ContextTest.php b/tests/Functional/JsonLd/ContextTest.php index 6906f979db2..873e9d43a39 100644 --- a/tests/Functional/JsonLd/ContextTest.php +++ b/tests/Functional/JsonLd/ContextTest.php @@ -121,4 +121,22 @@ public function testResourceLevelJsonLdContextAddsNamespacePrefixes(): void $this->assertSame('http://purl.org/dc/terms/', $body['@context']['dct']); $this->assertSame('dct:title', $body['@context']['title']); } + + public function testErrorContextIsResolvedThroughItsResource(): void + { + $response = self::createClient()->request('GET', '/contexts/Error'); + $this->assertResponseIsSuccessful(); + $body = $response->toArray(); + $this->assertArrayHasKey('@context', $body); + $this->assertSame('http://www.w3.org/ns/hydra/core#', $body['@context']['hydra']); + } + + public function testConstraintViolationContextIsResolvedThroughItsResource(): void + { + $response = self::createClient()->request('GET', '/contexts/ConstraintViolation'); + $this->assertResponseIsSuccessful(); + $body = $response->toArray(); + $this->assertArrayHasKey('@context', $body); + $this->assertSame('http://www.w3.org/ns/hydra/core#', $body['@context']['hydra']); + } } From e0c21779248f2489b6499258e05e8485f1952818 Mon Sep 17 00:00:00 2001 From: soyuka Date: Sun, 19 Jul 2026 07:30:10 +0200 Subject: [PATCH 3/3] test(jsonld): drop obsolete reserved-shortname unit test testContextActionWithContexts pinned the removed RESERVED_SHORT_NAMES short-circuit (ConstraintViolationList -> getBaseContext). The loop path is already covered by testContextActionWithResourceClass / testContextActionWithThrown. --- tests/JsonLd/Action/ContextActionTest.php | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/tests/JsonLd/Action/ContextActionTest.php b/tests/JsonLd/Action/ContextActionTest.php index 52683ad81b2..62117051935 100644 --- a/tests/JsonLd/Action/ContextActionTest.php +++ b/tests/JsonLd/Action/ContextActionTest.php @@ -52,17 +52,6 @@ public function testContextActionWithEntrypoint(): void $this->assertEquals(['@context' => ['/entrypoints']], $contextAction('Entrypoint')); } - public function testContextActionWithContexts(): void - { - $contextBuilderProphecy = $this->prophesize(ContextBuilderInterface::class); - $resourceNameCollectionFactoryProphecy = $this->prophesize(ResourceNameCollectionFactoryInterface::class); - $resourceMetadataCollectionFactoryProphecy = $this->prophesize(ResourceMetadataCollectionFactoryInterface::class); - $contextBuilderProphecy->getBaseContext()->willReturn(['/contexts']); - $contextAction = new ContextAction($contextBuilderProphecy->reveal(), $resourceNameCollectionFactoryProphecy->reveal(), $resourceMetadataCollectionFactoryProphecy->reveal()); - - $this->assertEquals(['@context' => ['/contexts']], $contextAction('ConstraintViolationList')); - } - public function testContextActionWithResourceClass(): void { $contextBuilderProphecy = $this->prophesize(ContextBuilderInterface::class);