From b5276577f133a3a5014cec337b16873d0029a2c8 Mon Sep 17 00:00:00 2001 From: soyuka Date: Tue, 9 Sep 2025 14:19:09 +0200 Subject: [PATCH] fix(state): transform uri variable using ReadLinkParameterProvider --- .../ReadLinkParameterProvider.php | 6 +++ .../LinkParameterProviderResource.php | 49 +++++++++++++++++++ tests/Fixtures/TestBundle/Entity/Employee.php | 8 ++- .../Parameters/LinkProviderParameterTest.php | 22 ++++++++- 4 files changed, 82 insertions(+), 3 deletions(-) create mode 100644 tests/Fixtures/TestBundle/ApiResource/LinkParameterProviderResource.php diff --git a/src/State/ParameterProvider/ReadLinkParameterProvider.php b/src/State/ParameterProvider/ReadLinkParameterProvider.php index e96c40fc46d..b8786dcc018 100644 --- a/src/State/ParameterProvider/ReadLinkParameterProvider.php +++ b/src/State/ParameterProvider/ReadLinkParameterProvider.php @@ -89,6 +89,12 @@ public function provide(Parameter $parameter, array $parameters = [], array $con $context['request']?->attributes->set($securityObjectName, $relation); + if ($parameter instanceof Link) { + $uriVariables = $operation->getUriVariables(); + $uriVariables[$parameter->getKey()] = $parameter; + $operation = $operation->withUriVariables($uriVariables); + } + return $operation; } diff --git a/tests/Fixtures/TestBundle/ApiResource/LinkParameterProviderResource.php b/tests/Fixtures/TestBundle/ApiResource/LinkParameterProviderResource.php new file mode 100644 index 00000000000..8d1f72d68e8 --- /dev/null +++ b/tests/Fixtures/TestBundle/ApiResource/LinkParameterProviderResource.php @@ -0,0 +1,49 @@ + + * + * 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; + +use ApiPlatform\Metadata\Get; +use ApiPlatform\Metadata\HttpOperation; +use ApiPlatform\Metadata\Link; +use ApiPlatform\Metadata\Operation; +use ApiPlatform\State\ParameterProvider\ReadLinkParameterProvider; +use ApiPlatform\Tests\Fixtures\TestBundle\Entity\Dummy; + +#[Get( + uriTemplate: '/link_parameter_provider_resources/{id}', + uriVariables: [ + 'id' => new Link( + provider: ReadLinkParameterProvider::class, + fromClass: Dummy::class + ), + ], + provider: [self::class, 'provide'] +)] +class LinkParameterProviderResource +{ + public string $id; + public Dummy $dummy; + + /** + * @param HttpOperation $operation + */ + public static function provide(Operation $operation, array $uriVariables = []) + { + $d = new self(); + $d->id = '1'; + $d->dummy = $operation->getUriVariables()['id']->getValue(); + + return $d; + } +} diff --git a/tests/Fixtures/TestBundle/Entity/Employee.php b/tests/Fixtures/TestBundle/Entity/Employee.php index 2a28463a3ee..66916b8d9b5 100644 --- a/tests/Fixtures/TestBundle/Entity/Employee.php +++ b/tests/Fixtures/TestBundle/Entity/Employee.php @@ -20,7 +20,7 @@ use ApiPlatform\Metadata\Post; use Doctrine\ORM\Mapping as ORM; use Symfony\Component\Serializer\Annotation\Groups; -use Symfony\Component\Validator\Constraints\IdenticalTo; +use Symfony\Component\Validator\Constraints\Expression; #[ApiResource] #[Post] @@ -49,7 +49,11 @@ toProperty: 'company', security: 'company.name == "Test" or company.name == "NotTest"', extraProperties: ['uri_template' => '/company-by-name/{name}'], - constraints: [new IdenticalTo('Test')] + constraints: [ + new Expression( + 'value.getName() == "Test"', + ), + ] ), ], )] diff --git a/tests/Functional/Parameters/LinkProviderParameterTest.php b/tests/Functional/Parameters/LinkProviderParameterTest.php index 26c5254c57b..620820ad2a6 100644 --- a/tests/Functional/Parameters/LinkProviderParameterTest.php +++ b/tests/Functional/Parameters/LinkProviderParameterTest.php @@ -14,6 +14,7 @@ namespace ApiPlatform\Tests\Functional\Parameters; use ApiPlatform\Symfony\Bundle\Test\ApiTestCase; +use ApiPlatform\Tests\Fixtures\TestBundle\ApiResource\LinkParameterProviderResource; use ApiPlatform\Tests\Fixtures\TestBundle\ApiResource\WithParameter; use ApiPlatform\Tests\Fixtures\TestBundle\Entity\Company; use ApiPlatform\Tests\Fixtures\TestBundle\Entity\Dummy; @@ -35,7 +36,7 @@ final class LinkProviderParameterTest extends ApiTestCase */ public static function getResources(): array { - return [WithParameter::class, Dummy::class, Employee::class, Company::class]; + return [WithParameter::class, Dummy::class, Employee::class, Company::class, LinkParameterProviderResource::class]; } /** @@ -162,4 +163,23 @@ public function testLinkSecurityWithConstraint(): void $response = self::createClient()->request('GET', '/companies-by-name/NotTest/employees'); self::assertEquals(422, $response->getStatusCode()); } + + public function testUriVariableHasDummy(): void + { + if ('mongodb' === $container->getParameter('kernel.environment')) { + $this->markTestSkipped(); + } + + $manager = $this->getManager(); + $dummy = new Dummy(); + $dummy->setName('hi'); + $manager->persist($dummy); + $manager->flush(); + + self::createClient()->request('GET', '/link_parameter_provider_resources/'.$dummy->getId()); + + $this->assertJsonContains([ + 'dummy' => '/dummies/1', + ]); + } }