From 43afa126ded1fa26a3f38858b660429693847320 Mon Sep 17 00:00:00 2001 From: soyuka Date: Mon, 21 Nov 2022 18:00:38 +0100 Subject: [PATCH] fix(metadata): route prefix in the operation name --- src/Metadata/Operations.php | 5 ++ ...nNameResourceMetadataCollectionFactory.php | 8 ++- ...erationNameResourceMetadataFactoryTest.php | 56 +++++++++++++++++++ 3 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 tests/Metadata/Resource/Factory/OperationNameResourceMetadataFactoryTest.php diff --git a/src/Metadata/Operations.php b/src/Metadata/Operations.php index 5565bc99bd0..0c7212f29aa 100644 --- a/src/Metadata/Operations.php +++ b/src/Metadata/Operations.php @@ -26,6 +26,11 @@ public function __construct(array $operations = []) // When we use an int-indexed array in the constructor, compute priorities if (\is_int($operationName)) { $operation = $operation->withPriority($operationName); + $operationName = (string) $operationName; + } + + if ($operation->getName()) { + $operationName = $operation->getName(); } $this->operations[] = [$operationName, $operation]; diff --git a/src/Metadata/Resource/Factory/OperationNameResourceMetadataCollectionFactory.php b/src/Metadata/Resource/Factory/OperationNameResourceMetadataCollectionFactory.php index d8e2e314433..120c8a1c822 100644 --- a/src/Metadata/Resource/Factory/OperationNameResourceMetadataCollectionFactory.php +++ b/src/Metadata/Resource/Factory/OperationNameResourceMetadataCollectionFactory.php @@ -52,7 +52,8 @@ public function create(string $resourceClass): ResourceMetadataCollection continue; } - $newOperationName = sprintf('_api_%s_%s%s', $operation->getUriTemplate() ?: $operation->getShortName(), strtolower($operation->getMethod() ?? HttpOperation::METHOD_GET), $operation instanceof CollectionOperationInterface ? '_collection' : ''); + $path = ($operation->getRoutePrefix() ?? '').($operation->getUriTemplate() ?? ''); + $newOperationName = sprintf('_api_%s_%s%s', $path ?: ($operation->getShortName() ?? $this->getDefaultShortname($resourceClass)), strtolower($operation->getMethod() ?? HttpOperation::METHOD_GET), $operation instanceof CollectionOperationInterface ? '_collection' : ''); $operations->remove($operationName)->add($newOperationName, $operation->withName($newOperationName)); } @@ -61,4 +62,9 @@ public function create(string $resourceClass): ResourceMetadataCollection return $resourceMetadataCollection; } + + private function getDefaultShortname(string $resourceClass): string + { + return (false !== $pos = strrpos($resourceClass, '\\')) ? substr($resourceClass, $pos + 1) : $resourceClass; + } } diff --git a/tests/Metadata/Resource/Factory/OperationNameResourceMetadataFactoryTest.php b/tests/Metadata/Resource/Factory/OperationNameResourceMetadataFactoryTest.php new file mode 100644 index 00000000000..0671bcf4715 --- /dev/null +++ b/tests/Metadata/Resource/Factory/OperationNameResourceMetadataFactoryTest.php @@ -0,0 +1,56 @@ + + * + * 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\Metadata\Resource\Factory; + +use ApiPlatform\Metadata\ApiResource; +use ApiPlatform\Metadata\Get; +use ApiPlatform\Metadata\Operation; +use ApiPlatform\Metadata\Resource\Factory\OperationNameResourceMetadataCollectionFactory; +use ApiPlatform\Metadata\Resource\Factory\ResourceMetadataCollectionFactoryInterface; +use ApiPlatform\Metadata\Resource\ResourceMetadataCollection; +use PHPUnit\Framework\TestCase; +use Prophecy\PhpUnit\ProphecyTrait; + +class OperationNameResourceMetadataFactoryTest extends TestCase +{ + use ProphecyTrait; + + /** + * @dataProvider operationProvider + */ + public function testGeneratesName(Operation $operation, string $expectedOperationName): void + { + $decorated = $this->prophesize(ResourceMetadataCollectionFactoryInterface::class); + $decorated->create('a')->willReturn(new ResourceMetadataCollection('a', [ + new ApiResource(operations: [$operation]), + ])); + + $operationNameResourceMetadataFactory = new OperationNameResourceMetadataCollectionFactory($decorated->reveal()); + $result = $operationNameResourceMetadataFactory->create('a'); + + $this->assertEquals($operation->withName($expectedOperationName), $result->getOperation($expectedOperationName)); + } + +public function operationProvider(): array +{ + return [ + [new Get(), '_api_a_get'], + [new Get(shortName: 'Foo'), '_api_Foo_get'], + [new Get(name: 'test'), 'test'], + [new Get(routePrefix: 'foo'), '_api_foo_get'], + [new Get(uriTemplate: '/foo'), '_api_/foo_get'], + [new Get(routePrefix: '/admin', uriTemplate: '/foo'), '_api_/admin/foo_get'], + ]; +} +}