From edcf4da3bd1bb17bb2647650807601b6c1cedf2e Mon Sep 17 00:00:00 2001 From: soyuka Date: Tue, 2 Feb 2021 15:48:59 +0100 Subject: [PATCH] Fix openapi sort #3996 --- src/OpenApi/Serializer/OpenApiNormalizer.php | 5 +++++ .../Serializer/OpenApiNormalizerTest.php | 22 ++++++++++++++++++- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/OpenApi/Serializer/OpenApiNormalizer.php b/src/OpenApi/Serializer/OpenApiNormalizer.php index 381b2599574..7445f6a75c0 100644 --- a/src/OpenApi/Serializer/OpenApiNormalizer.php +++ b/src/OpenApi/Serializer/OpenApiNormalizer.php @@ -54,9 +54,14 @@ private function recursiveClean($data): array continue; } + if ('schemas' === $key) { + ksort($value); + } + // Side effect of using getPaths(): Paths which itself contains the array if ('paths' === $key) { $value = $data['paths'] = $data['paths']['paths']; + ksort($value); unset($data['paths']['paths']); } diff --git a/tests/OpenApi/Serializer/OpenApiNormalizerTest.php b/tests/OpenApi/Serializer/OpenApiNormalizerTest.php index 8ba832a5007..84bae5bdb59 100644 --- a/tests/OpenApi/Serializer/OpenApiNormalizerTest.php +++ b/tests/OpenApi/Serializer/OpenApiNormalizerTest.php @@ -53,10 +53,11 @@ class OpenApiNormalizerTest extends TestCase public function testNormalize() { $resourceNameCollectionFactoryProphecy = $this->prophesize(ResourceNameCollectionFactoryInterface::class); - $resourceNameCollectionFactoryProphecy->create()->shouldBeCalled()->willReturn(new ResourceNameCollection([Dummy::class])); + $resourceNameCollectionFactoryProphecy->create()->shouldBeCalled()->willReturn(new ResourceNameCollection([Dummy::class, 'Zorro'])); $defaultContext = ['base_url' => '/app_dev.php/']; $propertyNameCollectionFactoryProphecy = $this->prophesize(PropertyNameCollectionFactoryInterface::class); $propertyNameCollectionFactoryProphecy->create(Dummy::class, Argument::any())->shouldBeCalled()->willReturn(new PropertyNameCollection(['id', 'name', 'description', 'dummyDate'])); + $propertyNameCollectionFactoryProphecy->create('Zorro', Argument::any())->shouldBeCalled()->willReturn(new PropertyNameCollection(['id'])); $dummyMetadata = new ResourceMetadata( 'Dummy', @@ -74,11 +75,25 @@ public function testNormalize() [] ); + $zorroMetadata = new ResourceMetadata( + 'Zorro', + 'This is zorro.', + 'http://schema.example.com/Zorro', + [ + 'get' => ['method' => 'GET'] + self::OPERATION_FORMATS, + ], + [ + 'get' => ['method' => 'GET'] + self::OPERATION_FORMATS, + ], + [] + ); + $subresourceOperationFactoryProphecy = $this->prophesize(SubresourceOperationFactoryInterface::class); $subresourceOperationFactoryProphecy->create(Argument::any(), Argument::any(), Argument::any())->willReturn([]); $resourceMetadataFactoryProphecy = $this->prophesize(ResourceMetadataFactoryInterface::class); $resourceMetadataFactoryProphecy->create(Dummy::class)->shouldBeCalled()->willReturn($dummyMetadata); + $resourceMetadataFactoryProphecy->create('Zorro')->shouldBeCalled()->willReturn($zorroMetadata); $propertyMetadataFactoryProphecy = $this->prophesize(PropertyMetadataFactoryInterface::class); $propertyMetadataFactoryProphecy->create(Dummy::class, 'id', Argument::any())->shouldBeCalled()->willReturn(new PropertyMetadata(new Type(Type::BUILTIN_TYPE_INT), 'This is an id.', true, false, null, null, null, true, null, null, null, null, null, null, null, ['minLength' => 3, 'maxLength' => 20, 'pattern' => '^dummyPattern$'])); @@ -86,6 +101,8 @@ public function testNormalize() $propertyMetadataFactoryProphecy->create(Dummy::class, 'description', Argument::any())->shouldBeCalled()->willReturn(new PropertyMetadata(new Type(Type::BUILTIN_TYPE_STRING), 'This is an initializable but not writable property.', true, false, true, true, false, false, null, null, [], null, true)); $propertyMetadataFactoryProphecy->create(Dummy::class, 'dummyDate', Argument::any())->shouldBeCalled()->willReturn(new PropertyMetadata(new Type(Type::BUILTIN_TYPE_OBJECT, true, \DateTime::class), 'This is a \DateTimeInterface object.', true, true, true, true, false, false, null, null, [])); + $propertyMetadataFactoryProphecy->create('Zorro', 'id', Argument::any())->shouldBeCalled()->willReturn(new PropertyMetadata(new Type(Type::BUILTIN_TYPE_INT), 'This is an id.', true, false, null, null, null, true)); + $operationPathResolver = new CustomOperationPathResolver(new OperationPathResolver(new UnderscorePathSegmentNameGenerator())); $filterLocatorProphecy = $this->prophesize(ContainerInterface::class); $resourceMetadataFactory = $resourceMetadataFactoryProphecy->reveal(); @@ -165,5 +182,8 @@ public function testNormalize() // Security can be disabled per-operation using an empty array $this->assertEquals([], $openApiAsArray['paths']['/dummies']['post']['security']); $this->assertEquals(['url' => '/test'], $openApiAsArray['paths']['/dummies']['post']['servers']); + + // Make sure things are sorted + $this->assertEquals(array_keys($openApiAsArray['paths']), ['/dummies', '/dummies/{id}', '/zorros', '/zorros/{id}']); } }