From eb8f29af135170ae975fc6b47ec71ccb2c08d0ef Mon Sep 17 00:00:00 2001 From: Rob Sykes <56603160+robert-sykes@users.noreply.github.com> Date: Wed, 17 Jan 2024 14:23:50 +0000 Subject: [PATCH] Added Required to the Schema for rendering. (#3) The `Required` option does not seem to be rendering for a property. I am not sure if this is intentional or not. This PR adds the support for it to be rendered out with `required` being defaulted to true. This allows `required` properties to be marked as such. --- src/Attribute/AbstractProperty.php | 2 + src/Attribute/Property.php | 4 +- src/Attribute/PropertyArray.php | 4 +- src/Attribute/PropertyArrayObject.php | 4 +- src/Attribute/PropertyEnum.php | 4 +- src/Attribute/PropertyObject.php | 4 +- src/Generator/JsonGenerator.php | 2 +- src/Schema.php | 6 +++ .../DumpSpecificationConsoleTest.php | 50 +++++++++++++++++-- .../Attribute/PropertyArrayObjectTest.php | 1 + tests/Unit/Attribute/PropertyArrayTest.php | 1 + tests/Unit/Attribute/PropertyEnumTest.php | 1 + tests/Unit/Attribute/PropertyObjectTest.php | 3 ++ tests/Unit/Attribute/PropertyTest.php | 1 + .../AttributeDocumentationStrategyTest.php | 13 +++++ tests/Unit/SchemaTest.php | 18 +++++++ .../JsonSpecificationControllerTest.php | 29 +++++++++-- .../YamlSpecificationControllerTest.php | 18 +++++++ 18 files changed, 147 insertions(+), 18 deletions(-) diff --git a/src/Attribute/AbstractProperty.php b/src/Attribute/AbstractProperty.php index 7c0e36a..4d1038f 100644 --- a/src/Attribute/AbstractProperty.php +++ b/src/Attribute/AbstractProperty.php @@ -9,6 +9,7 @@ abstract class AbstractProperty public function __construct( public string $name, public string $description, + public bool $required, ) { } @@ -17,6 +18,7 @@ public function toArray(): array return [ 'name' => $this->name, 'description' => $this->description, + 'required' => $this->required, ]; } } diff --git a/src/Attribute/Property.php b/src/Attribute/Property.php index 87b5b63..0213900 100644 --- a/src/Attribute/Property.php +++ b/src/Attribute/Property.php @@ -17,9 +17,9 @@ public function __construct( public readonly PropertyType $type = PropertyType::STRING, public readonly ?Format $format = null, public readonly ?string $example = null, - public readonly bool $required = true, + bool $required = true, ) { - parent::__construct($name, $description); + parent::__construct($name, $description, $required); } public function toArray(): array diff --git a/src/Attribute/PropertyArray.php b/src/Attribute/PropertyArray.php index f78ffc9..3888c31 100644 --- a/src/Attribute/PropertyArray.php +++ b/src/Attribute/PropertyArray.php @@ -17,9 +17,9 @@ public function __construct( string $description = '', public readonly ?Format $format = null, public readonly ?string $example = null, - public readonly bool $required = true, + bool $required = true, ) { - parent::__construct($name, $description); + parent::__construct($name, $description, $required); } public function toArray(): array diff --git a/src/Attribute/PropertyArrayObject.php b/src/Attribute/PropertyArrayObject.php index 95b3a6c..287351c 100644 --- a/src/Attribute/PropertyArrayObject.php +++ b/src/Attribute/PropertyArrayObject.php @@ -16,9 +16,9 @@ public function __construct( string $description = '', public ?Format $format = null, public ?string $example = null, - public bool $required = true, + bool $required = true, ) { - parent::__construct($name, $description); + parent::__construct($name, $description, $required); } public function toArray(): array diff --git a/src/Attribute/PropertyEnum.php b/src/Attribute/PropertyEnum.php index 28737f0..8980e81 100644 --- a/src/Attribute/PropertyEnum.php +++ b/src/Attribute/PropertyEnum.php @@ -20,9 +20,9 @@ public function __construct( string $description = '', public ?Format $format = null, public ?string $example = null, - public bool $required = true, + bool $required = true, ) { - parent::__construct($name, $description); + parent::__construct($name, $description, $required); } public function toArray(): array diff --git a/src/Attribute/PropertyObject.php b/src/Attribute/PropertyObject.php index 1a4398e..1be5229 100644 --- a/src/Attribute/PropertyObject.php +++ b/src/Attribute/PropertyObject.php @@ -14,9 +14,9 @@ public function __construct( public readonly string $class, string $description = '', public readonly array $items = [], - public readonly bool $required = true, + bool $required = true, ) { - parent::__construct($name, $description); + parent::__construct($name, $description, $required); } public function toArray(): array diff --git a/src/Generator/JsonGenerator.php b/src/Generator/JsonGenerator.php index e1d51b1..22dc9a5 100644 --- a/src/Generator/JsonGenerator.php +++ b/src/Generator/JsonGenerator.php @@ -20,6 +20,6 @@ public function __construct( */ public function generate(): string { - return json_encode($this->generator->generate(), JSON_THROW_ON_ERROR | JSON_FORCE_OBJECT); + return json_encode($this->generator->generate(), JSON_THROW_ON_ERROR); } } diff --git a/src/Schema.php b/src/Schema.php index 9a9dc36..d40eb83 100644 --- a/src/Schema.php +++ b/src/Schema.php @@ -9,6 +9,7 @@ class Schema public function render(array $document): array { $properties = []; + $required = []; foreach ($document['properties'] as $property) { $properties[$property['name']]['type'] = PropertyTypeTranslator::translate($property['type']); @@ -24,12 +25,17 @@ public function render(array $document): array if (isset($property['example'])) { $properties[$property['name']]['example'] = $property['example']; } + + if (isset($property['required'])) { + $required[] = $property['name']; + } } $message[$document['name']] = [ 'payload' => [ 'type' => 'object', 'properties' => $properties, + 'required' => $required, ], ]; diff --git a/tests/Integration/DumpSpecificationConsoleTest.php b/tests/Integration/DumpSpecificationConsoleTest.php index c80c930..130d3d9 100644 --- a/tests/Integration/DumpSpecificationConsoleTest.php +++ b/tests/Integration/DumpSpecificationConsoleTest.php @@ -50,6 +50,11 @@ public function testExecuteClass(): void description: 'Is user a citizen' format: boolean example: 'true' + required: + - name + - email + - age + - isCitizen YAML; @@ -124,6 +129,11 @@ public function testExecuteYaml(): void description: 'Is user a citizen' format: boolean example: 'true' + required: + - name + - email + - age + - isCitizen PaymentExecuted: payload: type: object @@ -138,6 +148,9 @@ public function testExecuteYaml(): void description: 'Creation date' format: date-time example: '2023-11-23 13:41:21' + required: + - amount + - createdAt ProductCreated: payload: type: object @@ -170,6 +183,16 @@ public function testExecuteYaml(): void tags: type: string description: '' + required: + - id + - amount + - currency + - isPaid + - createdAt + - week + - payment + - products + - tags YAML; @@ -269,7 +292,13 @@ public function testExecuteJson(): void "format": "boolean", "example": "true" } - } + }, + "required": [ + "name", + "email", + "age", + "isCitizen" + ] } }, "PaymentExecuted": { @@ -288,7 +317,11 @@ public function testExecuteJson(): void "format": "date-time", "example": "2023-11-23 13:41:21" } - } + }, + "required": [ + "amount", + "createdAt" + ] } }, "ProductCreated": { @@ -332,7 +365,18 @@ public function testExecuteJson(): void "type": "string", "description": "" } - } + }, + "required": [ + "id", + "amount", + "currency", + "isPaid", + "createdAt", + "week", + "payment", + "products", + "tags" + ] } } } diff --git a/tests/Unit/Attribute/PropertyArrayObjectTest.php b/tests/Unit/Attribute/PropertyArrayObjectTest.php index c7a23eb..cceaf28 100644 --- a/tests/Unit/Attribute/PropertyArrayObjectTest.php +++ b/tests/Unit/Attribute/PropertyArrayObjectTest.php @@ -20,6 +20,7 @@ public function testToArray(): void 'type' => 'array', 'format' => null, 'example' => null, + 'required' => true, ]; $actual = $property->toArray(); diff --git a/tests/Unit/Attribute/PropertyArrayTest.php b/tests/Unit/Attribute/PropertyArrayTest.php index de5939e..2dff8a7 100644 --- a/tests/Unit/Attribute/PropertyArrayTest.php +++ b/tests/Unit/Attribute/PropertyArrayTest.php @@ -24,6 +24,7 @@ public function testToArray(): void 'itemsType' => 'string', 'format' => null, 'example' => null, + 'required' => true, ]; $actual = $property->toArray(); diff --git a/tests/Unit/Attribute/PropertyEnumTest.php b/tests/Unit/Attribute/PropertyEnumTest.php index 5b844f7..1957a91 100644 --- a/tests/Unit/Attribute/PropertyEnumTest.php +++ b/tests/Unit/Attribute/PropertyEnumTest.php @@ -23,6 +23,7 @@ public function testToArrayOnBackedEnum(): void 'enum' => [1, 2, 3, 4, 5, 6, 7], 'format' => null, 'example' => null, + 'required' => true, ]; $actual = $property->toArray(); diff --git a/tests/Unit/Attribute/PropertyObjectTest.php b/tests/Unit/Attribute/PropertyObjectTest.php index 6cb9cc0..b26003c 100644 --- a/tests/Unit/Attribute/PropertyObjectTest.php +++ b/tests/Unit/Attribute/PropertyObjectTest.php @@ -21,6 +21,7 @@ public function testToArray(): void 'description' => '', 'type' => 'object', 'items' => [], + 'required' => true, ]; $actual = $property->toArray(); @@ -47,8 +48,10 @@ class: Payment::class, 'type' => 'string', 'format' => null, 'example' => null, + 'required' => true, ] ], + 'required' => true, ]; $actual = $property->toArray(); diff --git a/tests/Unit/Attribute/PropertyTest.php b/tests/Unit/Attribute/PropertyTest.php index 227e58a..277d815 100644 --- a/tests/Unit/Attribute/PropertyTest.php +++ b/tests/Unit/Attribute/PropertyTest.php @@ -24,6 +24,7 @@ public function testToArray(): void 'type' => 'string', 'format' => null, 'example' => null, + 'required' => true, ]; $actual = $property->toArray(); diff --git a/tests/Unit/DocumentationStrategy/AttributeDocumentationStrategyTest.php b/tests/Unit/DocumentationStrategy/AttributeDocumentationStrategyTest.php index 5b3641d..8fe18ec 100644 --- a/tests/Unit/DocumentationStrategy/AttributeDocumentationStrategyTest.php +++ b/tests/Unit/DocumentationStrategy/AttributeDocumentationStrategyTest.php @@ -27,6 +27,7 @@ public function testUserSignedUp(): void 'description' => 'Name of the user', 'example' => 'John', 'format' => 'string', + 'required' => true, ], [ 'name' => 'email', @@ -34,6 +35,7 @@ public function testUserSignedUp(): void 'description' => 'Email of the user', 'format' => 'email', 'example' => 'john@example.com', + 'required' => true, ], [ 'name' => 'age', @@ -41,6 +43,7 @@ public function testUserSignedUp(): void 'description' => 'Age of the user', 'format' => 'int32', 'example' => '18', + 'required' => true, ], [ 'name' => 'isCitizen', @@ -48,6 +51,7 @@ public function testUserSignedUp(): void 'description' => 'Is user a citizen', 'format' => 'boolean', 'example' => 'true', + 'required' => true, ], ], ]; @@ -70,6 +74,7 @@ public function testProductCreated(): void 'type' => 'integer', 'format' => null, 'example' => null, + 'required' => true, ], [ 'name' => 'amount', @@ -77,6 +82,7 @@ public function testProductCreated(): void 'type' => 'number', 'format' => null, 'example' => null, + 'required' => true, ], [ 'name' => 'currency', @@ -84,6 +90,7 @@ public function testProductCreated(): void 'type' => 'string', 'format' => null, 'example' => null, + 'required' => true, ], [ 'name' => 'isPaid', @@ -91,6 +98,7 @@ public function testProductCreated(): void 'type' => 'boolean', 'format' => null, 'example' => null, + 'required' => true, ], [ 'name' => 'createdAt', @@ -98,6 +106,7 @@ public function testProductCreated(): void 'type' => 'string', 'format' => 'date-time', 'example' => null, + 'required' => true, ], [ 'name' => 'week', @@ -106,12 +115,14 @@ public function testProductCreated(): void 'enum' => [1, 2, 3, 4, 5, 6, 7], 'format' => null, 'example' => null, + 'required' => true, ], [ 'name' => 'payment', 'description' => '', 'type' => 'object', 'items' => [], + 'required' => true, ], [ 'name' => 'products', @@ -119,6 +130,7 @@ public function testProductCreated(): void 'type' => 'array', 'format' => null, 'example' => null, + 'required' => true, ], [ 'name' => 'tags', @@ -127,6 +139,7 @@ public function testProductCreated(): void 'format' => null, 'example' => null, 'itemsType' => 'string', + 'required' => true, ], ], ]; diff --git a/tests/Unit/SchemaTest.php b/tests/Unit/SchemaTest.php index c4a4580..80d1fcf 100644 --- a/tests/Unit/SchemaTest.php +++ b/tests/Unit/SchemaTest.php @@ -18,18 +18,22 @@ public function testReflection(): void [ 'name' => 'name', 'type' => 'string', + 'required' => true, ], [ 'name' => 'email', 'type' => 'string', + 'required' => true, ], [ 'name' => 'age', 'type' => 'int', + 'required' => true, ], [ 'name' => 'isCitizen', 'type' => 'bool', + 'required' => true, ], ], ]; @@ -51,6 +55,11 @@ public function testReflection(): void type: integer isCitizen: type: boolean + required: + - name + - email + - age + - isCitizen YAML; @@ -68,6 +77,7 @@ public function testAttributes(): void 'description' => 'Name of the user', 'example' => 'John', 'format' => 'string', + 'required' => true, ], [ 'name' => 'email', @@ -75,6 +85,7 @@ public function testAttributes(): void 'description' => 'Email of the user', 'format' => 'email', 'example' => 'john@example.com', + 'required' => true, ], [ 'name' => 'age', @@ -82,6 +93,7 @@ public function testAttributes(): void 'description' => 'Age of the user', 'format' => 'int', 'example' => '18', + 'required' => true, ], [ 'name' => 'isCitizen', @@ -89,6 +101,7 @@ public function testAttributes(): void 'description' => 'Is user a citizen', 'format' => 'boolean', 'example' => 'true', + 'required' => true, ], ], ]; @@ -122,6 +135,11 @@ public function testAttributes(): void description: 'Is user a citizen' format: boolean example: 'true' + required: + - name + - email + - age + - isCitizen YAML; diff --git a/tests/Unit/Symfony/Controller/JsonSpecificationControllerTest.php b/tests/Unit/Symfony/Controller/JsonSpecificationControllerTest.php index 557cb09..0151d33 100644 --- a/tests/Unit/Symfony/Controller/JsonSpecificationControllerTest.php +++ b/tests/Unit/Symfony/Controller/JsonSpecificationControllerTest.php @@ -45,7 +45,7 @@ public function test(): void "version": "1.2.3", "description": "This service is in charge of processing user signups" }, - "servers": {}, + "servers": [], "channels": { "user_signed_up": { "subscribe": { @@ -99,7 +99,13 @@ public function test(): void "format": "boolean", "example": "true" } - } + }, + "required": [ + "name", + "email", + "age", + "isCitizen" + ] } }, "PaymentExecuted": { @@ -118,7 +124,11 @@ public function test(): void "format": "date-time", "example": "2023-11-23 13:41:21" } - } + }, + "required": [ + "amount", + "createdAt" + ] } }, "ProductCreated": { @@ -162,7 +172,18 @@ public function test(): void "type": "string", "description": "" } - } + }, + "required": [ + "id", + "amount", + "currency", + "isPaid", + "createdAt", + "week", + "payment", + "products", + "tags" + ] } } } diff --git a/tests/Unit/Symfony/Controller/YamlSpecificationControllerTest.php b/tests/Unit/Symfony/Controller/YamlSpecificationControllerTest.php index 1a9db67..270cc48 100644 --- a/tests/Unit/Symfony/Controller/YamlSpecificationControllerTest.php +++ b/tests/Unit/Symfony/Controller/YamlSpecificationControllerTest.php @@ -83,6 +83,11 @@ public function test(): void description: 'Is user a citizen' format: boolean example: 'true' + required: + - name + - email + - age + - isCitizen PaymentExecuted: payload: type: object @@ -97,6 +102,9 @@ public function test(): void description: 'Creation date' format: date-time example: '2023-11-23 13:41:21' + required: + - amount + - createdAt ProductCreated: payload: type: object @@ -129,6 +137,16 @@ public function test(): void tags: type: string description: '' + required: + - id + - amount + - currency + - isPaid + - createdAt + - week + - payment + - products + - tags YAML;