From 43b8ade9e61600401e833cd27c46f1826b1c229e Mon Sep 17 00:00:00 2001 From: loicboursin Date: Tue, 1 Jun 2021 11:05:37 +0200 Subject: [PATCH 1/3] fix(openapi): reflect specification to OpenAPI 3.1 --- src/OpenApi/Model/Components.php | 17 +++++++++- src/OpenApi/Model/Info.php | 17 +++++++++- src/OpenApi/Model/License.php | 17 +++++++++- src/OpenApi/Model/Schema.php | 8 +++-- src/OpenApi/OpenApi.php | 26 +++++++++++++-- tests/OpenApi/Model/SchemaTest.php | 33 +++++++++++++++++++ .../Serializer/OpenApiNormalizerTest.php | 1 + 7 files changed, 112 insertions(+), 7 deletions(-) create mode 100644 tests/OpenApi/Model/SchemaTest.php diff --git a/src/OpenApi/Model/Components.php b/src/OpenApi/Model/Components.php index 1035ab1d7f0..d3a1e3cc2d1 100644 --- a/src/OpenApi/Model/Components.php +++ b/src/OpenApi/Model/Components.php @@ -26,8 +26,9 @@ final class Components private $securitySchemes; private $links; private $callbacks; + private $pathItems; - public function __construct(\ArrayObject $schemas = null, \ArrayObject $responses = null, \ArrayObject $parameters = null, \ArrayObject $examples = null, \ArrayObject $requestBodies = null, \ArrayObject $headers = null, \ArrayObject $securitySchemes = null, \ArrayObject $links = null, \ArrayObject $callbacks = null) + public function __construct(\ArrayObject $schemas = null, \ArrayObject $responses = null, \ArrayObject $parameters = null, \ArrayObject $examples = null, \ArrayObject $requestBodies = null, \ArrayObject $headers = null, \ArrayObject $securitySchemes = null, \ArrayObject $links = null, \ArrayObject $callbacks = null, \ArrayObject $pathItems = null) { $this->schemas = $schemas; $this->responses = $responses; @@ -38,6 +39,7 @@ public function __construct(\ArrayObject $schemas = null, \ArrayObject $response $this->securitySchemes = $securitySchemes; $this->links = $links; $this->callbacks = $callbacks; + $this->pathItems = $pathItems; } public function getSchemas(): ?\ArrayObject @@ -85,6 +87,11 @@ public function getCallbacks(): ?\ArrayObject return $this->callbacks; } + public function getPathItems(): ?\ArrayObject + { + return $this->pathItems; + } + public function withSchemas(\ArrayObject $schemas): self { $clone = clone $this; @@ -156,4 +163,12 @@ public function withCallbacks(\ArrayObject $callbacks): self return $clone; } + + public function withPathItems(\ArrayObject $pathItems): self + { + $clone = clone $this; + $clone->pathItems = $pathItems; + + return $clone; + } } diff --git a/src/OpenApi/Model/Info.php b/src/OpenApi/Model/Info.php index 9b16e9e8909..8901db38995 100644 --- a/src/OpenApi/Model/Info.php +++ b/src/OpenApi/Model/Info.php @@ -23,8 +23,9 @@ final class Info private $contact; private $license; private $version; + private $summary; - public function __construct(string $title, string $version, string $description = '', string $termsOfService = null, Contact $contact = null, License $license = null) + public function __construct(string $title, string $version, string $description = '', string $termsOfService = null, Contact $contact = null, License $license = null, string $summary = null) { $this->title = $title; $this->version = $version; @@ -32,6 +33,7 @@ public function __construct(string $title, string $version, string $description $this->termsOfService = $termsOfService; $this->contact = $contact; $this->license = $license; + $this->summary = $summary; } public function getTitle(): string @@ -64,6 +66,11 @@ public function getVersion(): string return $this->version; } + public function getSummary(): ?string + { + return $this->summary; + } + public function withTitle(string $title): self { $info = clone $this; @@ -111,4 +118,12 @@ public function withVersion(string $version): self return $clone; } + + public function withSummary(string $summary): self + { + $clone = clone $this; + $clone->summary = $summary; + + return $clone; + } } diff --git a/src/OpenApi/Model/License.php b/src/OpenApi/Model/License.php index 11c80bb849b..2370752352a 100644 --- a/src/OpenApi/Model/License.php +++ b/src/OpenApi/Model/License.php @@ -19,11 +19,13 @@ final class License private $name; private $url; + private $identifier; - public function __construct(string $name, string $url = null) + public function __construct(string $name, string $url = null, string $identifier = null) { $this->name = $name; $this->url = $url; + $this->identifier = $identifier; } public function getName(): string @@ -36,6 +38,11 @@ public function getUrl(): ?string return $this->url; } + public function getIdentifier(): ?string + { + return $this->identifier; + } + public function withName(string $name): self { $clone = clone $this; @@ -51,4 +58,12 @@ public function withUrl(?string $url): self return $clone; } + + public function withIdentifier(?string $identifier): self + { + $clone = clone $this; + $clone->identifier = $identifier; + + return $clone; + } } diff --git a/src/OpenApi/Model/Schema.php b/src/OpenApi/Model/Schema.php index 5b9060238f7..a224a6281ca 100644 --- a/src/OpenApi/Model/Schema.php +++ b/src/OpenApi/Model/Schema.php @@ -29,9 +29,13 @@ final class Schema extends \ArrayObject private $deprecated; private $schema; - public function __construct(bool $nullable = false, $discriminator = null, bool $readOnly = false, bool $writeOnly = false, string $xml = null, $externalDocs = null, $example = null, bool $deprecated = false) + public function __construct(bool $nullable = null, $discriminator = null, bool $readOnly = false, bool $writeOnly = false, string $xml = null, $externalDocs = null, $example = null, bool $deprecated = false) { - $this->nullable = $nullable; + if (null !== $nullable){ + //@trigger_deprecation('api-platform/core', '2.6.3', 'The nullable keyword has been removed from the Schema Object (null can be used as a type value). This behaviour will not be possible anymore in API Platform 3.0.', \E_USER_DEPRECATED); + @trigger_error('The nullable keyword has been removed from the Schema Object (null can be used as a type value). This behaviour will not be possible anymore in API Platform 3.0.', \E_USER_DEPRECATED); + $this->nullable = $nullable; + } $this->discriminator = $discriminator; $this->readOnly = $readOnly; $this->writeOnly = $writeOnly; diff --git a/src/OpenApi/OpenApi.php b/src/OpenApi/OpenApi.php index a4289f08941..bd4aaab9f86 100644 --- a/src/OpenApi/OpenApi.php +++ b/src/OpenApi/OpenApi.php @@ -23,7 +23,7 @@ final class OpenApi implements DocumentationInterface { use ExtensionTrait; - public const VERSION = '3.0.3'; + public const VERSION = '3.1.0'; private $openapi; private $info; @@ -33,8 +33,10 @@ final class OpenApi implements DocumentationInterface private $security; private $tags; private $externalDocs; + private $jsonSchemaDialect; + private $webhooks; - public function __construct(Info $info, array $servers, Paths $paths, Components $components = null, array $security = [], array $tags = [], $externalDocs = null) + public function __construct(Info $info, array $servers, Paths $paths, Components $components = null, array $security = [], array $tags = [], $externalDocs = null, string $jsonSchemaDialect = null, \ArrayObject $webhooks = null) { $this->openapi = self::VERSION; $this->info = $info; @@ -44,6 +46,8 @@ public function __construct(Info $info, array $servers, Paths $paths, Components $this->security = $security; $this->tags = $tags; $this->externalDocs = $externalDocs; + $this->jsonSchemaDialect = $jsonSchemaDialect; + $this->webhooks = $webhooks; } public function getOpenapi(): string @@ -86,6 +90,16 @@ public function getExternalDocs(): ?array return $this->externalDocs; } + public function getJsonSchemaDialect(): ?string + { + return $this->jsonSchemaDialect; + } + + public function getWebhooks(): ?\ArrayObject + { + return $this->webhooks; + } + public function withOpenapi(string $openapi): self { $clone = clone $this; @@ -149,4 +163,12 @@ public function withExternalDocs(array $externalDocs): self return $clone; } + + public function withJsonSchemaDialect(array $jsonSchemaDialect): self + { + $clone = clone $this; + $clone->jsonSchemaDialect = $jsonSchemaDialect; + + return $clone; + } } diff --git a/tests/OpenApi/Model/SchemaTest.php b/tests/OpenApi/Model/SchemaTest.php new file mode 100644 index 00000000000..0384d9e30c4 --- /dev/null +++ b/tests/OpenApi/Model/SchemaTest.php @@ -0,0 +1,33 @@ + + * + * 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\Core\Tests\OpenApi\Model; + +use ApiPlatform\Core\OpenApi\Model\Schema; +use PHPUnit\Framework\TestCase; +use Symfony\Bridge\PhpUnit\ExpectDeprecationTrait; + +class SchemaTest extends TestCase +{ + use ExpectDeprecationTrait; + + /** + * @group legacy + */ + public function testLegacySchema() + { + $this->expectDeprecation('The nullable keyword has been removed from the Schema Object (null can be used as a type value). This behaviour will not be possible anymore in API Platform 3.0.'); + + $schema = new Schema(true); + } +} diff --git a/tests/OpenApi/Serializer/OpenApiNormalizerTest.php b/tests/OpenApi/Serializer/OpenApiNormalizerTest.php index f2ea35be85f..1190e16db59 100644 --- a/tests/OpenApi/Serializer/OpenApiNormalizerTest.php +++ b/tests/OpenApi/Serializer/OpenApiNormalizerTest.php @@ -178,6 +178,7 @@ public function testNormalize() $this->assertArrayNotHasKey('extensionProperties', $openApiAsArray); // this key is null, should not be in the output $this->assertArrayNotHasKey('termsOfService', $openApiAsArray['info']); + $this->assertArrayNotHasKey('summary', $openApiAsArray['info']); $this->assertArrayNotHasKey('paths', $openApiAsArray['paths']); $this->assertArrayHasKey('/dummies/{id}', $openApiAsArray['paths']); $this->assertArrayNotHasKey('servers', $openApiAsArray['paths']['/dummies/{id}']['get']); From 5970dbb772c7a9ab20dce792f83f741d8df93b6c Mon Sep 17 00:00:00 2001 From: loicboursin Date: Tue, 1 Jun 2021 14:07:31 +0200 Subject: [PATCH 2/3] test: fix openapi version in docs.feature --- features/openapi/docs.feature | 2 +- src/OpenApi/Model/Schema.php | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/features/openapi/docs.feature b/features/openapi/docs.feature index 6a77250474e..b9dc2188b96 100644 --- a/features/openapi/docs.feature +++ b/features/openapi/docs.feature @@ -10,7 +10,7 @@ Feature: Documentation support And the response should be in JSON And the header "Content-Type" should be equal to "application/json; charset=utf-8" # Context - And the JSON node "openapi" should be equal to "3.0.3" + And the JSON node "openapi" should be equal to "3.1.0" # Root properties And the JSON node "info.title" should be equal to "My Dummy API" And the JSON node "info.description" should contain "This is a test API." diff --git a/src/OpenApi/Model/Schema.php b/src/OpenApi/Model/Schema.php index a224a6281ca..66c629bfc01 100644 --- a/src/OpenApi/Model/Schema.php +++ b/src/OpenApi/Model/Schema.php @@ -31,8 +31,7 @@ final class Schema extends \ArrayObject public function __construct(bool $nullable = null, $discriminator = null, bool $readOnly = false, bool $writeOnly = false, string $xml = null, $externalDocs = null, $example = null, bool $deprecated = false) { - if (null !== $nullable){ - //@trigger_deprecation('api-platform/core', '2.6.3', 'The nullable keyword has been removed from the Schema Object (null can be used as a type value). This behaviour will not be possible anymore in API Platform 3.0.', \E_USER_DEPRECATED); + if (null !== $nullable) { @trigger_error('The nullable keyword has been removed from the Schema Object (null can be used as a type value). This behaviour will not be possible anymore in API Platform 3.0.', \E_USER_DEPRECATED); $this->nullable = $nullable; } From 7bba546ab5a3d6f4f8b1bc52b30fe5d0452e79f4 Mon Sep 17 00:00:00 2001 From: loicboursin Date: Tue, 8 Jun 2021 14:14:33 +0200 Subject: [PATCH 3/3] test: add symfony/intl dev dependency to test bic constraint --- composer.json | 1 + .../ValidatorPropertyMetadataFactoryTest.php | 24 ++++++++++++------- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/composer.json b/composer.json index 0f2fa18a40b..8e56f49226e 100644 --- a/composer.json +++ b/composer.json @@ -71,6 +71,7 @@ "symfony/form": "^3.4 || ^4.4 || ^5.1", "symfony/framework-bundle": "^4.4 || ^5.1", "symfony/http-client": "^4.4 || ^5.1", + "symfony/intl": "^3.4 || ^4.4 || ^5.1", "symfony/mercure-bundle": "*", "symfony/messenger": "^4.4 || ^5.1", "symfony/phpunit-bridge": "^5.1.7", diff --git a/tests/Bridge/Symfony/Validator/Metadata/Property/ValidatorPropertyMetadataFactoryTest.php b/tests/Bridge/Symfony/Validator/Metadata/Property/ValidatorPropertyMetadataFactoryTest.php index da18b63e49f..d57bf34841e 100644 --- a/tests/Bridge/Symfony/Validator/Metadata/Property/ValidatorPropertyMetadataFactoryTest.php +++ b/tests/Bridge/Symfony/Validator/Metadata/Property/ValidatorPropertyMetadataFactoryTest.php @@ -273,12 +273,14 @@ public function testCreateWithPropertyLengthRestriction(): void $decoratedPropertyMetadataFactory = $this->prophesize(PropertyMetadataFactoryInterface::class); $property = 'dummy'; $decoratedPropertyMetadataFactory->create(DummyValidatedEntity::class, $property, [])->willReturn( - new PropertyMetadata(new Type(Type::BUILTIN_TYPE_STRING)) - )->shouldBeCalled(); + new PropertyMetadata(new Type(Type::BUILTIN_TYPE_STRING)) + )->shouldBeCalled(); $lengthRestrictions = new PropertySchemaLengthRestriction(); $validatorPropertyMetadataFactory = new ValidatorPropertyMetadataFactory( - $validatorMetadataFactory->reveal(), $decoratedPropertyMetadataFactory->reveal(), [$lengthRestrictions] + $validatorMetadataFactory->reveal(), + $decoratedPropertyMetadataFactory->reveal(), + [$lengthRestrictions] ); $schema = $validatorPropertyMetadataFactory->create(DummyValidatedEntity::class, $property)->getSchema(); @@ -299,11 +301,12 @@ public function testCreateWithPropertyRegexRestriction(): void $decoratedPropertyMetadataFactory = $this->prophesize(PropertyMetadataFactoryInterface::class); $decoratedPropertyMetadataFactory->create(DummyValidatedEntity::class, 'dummy', [])->willReturn( - new PropertyMetadata() - )->shouldBeCalled(); + new PropertyMetadata() + )->shouldBeCalled(); $validationPropertyMetadataFactory = new ValidatorPropertyMetadataFactory( - $validatorMetadataFactory->reveal(), $decoratedPropertyMetadataFactory->reveal(), + $validatorMetadataFactory->reveal(), + $decoratedPropertyMetadataFactory->reveal(), [new PropertySchemaRegexRestriction()] ); @@ -534,7 +537,8 @@ public function testCreateWithPropertyChoiceRestriction(PropertyMetadata $proper )->shouldBeCalled(); $validationPropertyMetadataFactory = new ValidatorPropertyMetadataFactory( - $validatorMetadataFactory->reveal(), $decoratedPropertyMetadataFactory->reveal(), + $validatorMetadataFactory->reveal(), + $decoratedPropertyMetadataFactory->reveal(), [new PropertySchemaChoiceRestriction()] ); @@ -573,7 +577,8 @@ public function testCreateWithPropertyCountRestriction(string $property, array $ )->shouldBeCalled(); $validationPropertyMetadataFactory = new ValidatorPropertyMetadataFactory( - $validatorMetadataFactory->reveal(), $decoratedPropertyMetadataFactory->reveal(), + $validatorMetadataFactory->reveal(), + $decoratedPropertyMetadataFactory->reveal(), [new PropertySchemaCountRestriction()] ); @@ -671,7 +676,8 @@ public function testCreateWithPropertyNumericRestriction(PropertyMetadata $prope )->shouldBeCalled(); $validationPropertyMetadataFactory = new ValidatorPropertyMetadataFactory( - $validatorMetadataFactory->reveal(), $decoratedPropertyMetadataFactory->reveal(), + $validatorMetadataFactory->reveal(), + $decoratedPropertyMetadataFactory->reveal(), [ new PropertySchemaGreaterThanOrEqualRestriction(), new PropertySchemaGreaterThanRestriction(),