diff --git a/src/Annotations/AbstractAnnotation.php b/src/Annotations/AbstractAnnotation.php index f3e7154e0..37e4a7eb2 100644 --- a/src/Annotations/AbstractAnnotation.php +++ b/src/Annotations/AbstractAnnotation.php @@ -367,11 +367,8 @@ public function jsonSerialize() } if (property_exists($this, 'nullable') && $this->nullable === true) { $ref = ['oneOf' => [$ref]]; - if ($this->_context->version == OpenApi::VERSION_3_1_0) { - $ref['oneOf'][] = ['type' => 'null']; - } else { - $ref['nullable'] = $data->nullable; - } + $ref['nullable'] = $data->nullable; + unset($data->nullable); // preserve other properties @@ -387,42 +384,6 @@ public function jsonSerialize() $data = (object) $ref; } - if ($this->_context->version === OpenApi::VERSION_3_1_0) { - if (isset($data->nullable)) { - if (true === $data->nullable) { - if (isset($data->oneOf)) { - $data->oneOf[] = ['type' => 'null']; - } elseif (isset($data->anyOf)) { - $data->anyOf[] = ['type' => 'null']; - } elseif (isset($data->allOf)) { - $data->allOf[] = ['type' => 'null']; - } else { - $data->type = (array) $data->type; - $data->type[] = 'null'; - } - } - unset($data->nullable); - } - - if (isset($data->minimum) && isset($data->exclusiveMinimum)) { - if (true === $data->exclusiveMinimum) { - $data->exclusiveMinimum = $data->minimum; - unset($data->minimum); - } elseif (false === $data->exclusiveMinimum) { - unset($data->exclusiveMinimum); - } - } - - if (isset($data->maximum) && isset($data->exclusiveMaximum)) { - if (true === $data->exclusiveMaximum) { - $data->exclusiveMaximum = $data->maximum; - unset($data->maximum); - } elseif (false === $data->exclusiveMaximum) { - unset($data->exclusiveMaximum); - } - } - } - return $data; } diff --git a/src/Generator.php b/src/Generator.php index 8d5e3a2f4..1ffd22c74 100644 --- a/src/Generator.php +++ b/src/Generator.php @@ -269,6 +269,7 @@ public function getProcessors(): array new Processors\MergeXmlContent(), new Processors\OperationId(), new Processors\CleanUnmerged(), + new Processors\OpenApi31Processor(), ]; } diff --git a/src/Processors/OpenApi31Processor.php b/src/Processors/OpenApi31Processor.php new file mode 100644 index 000000000..186a3b928 --- /dev/null +++ b/src/Processors/OpenApi31Processor.php @@ -0,0 +1,102 @@ +openapi->openapi !== OA\OpenApi::VERSION_3_1_0) { + return; + } + + /** @var OA\Schema[] $annotations */ + $annotations = $analysis->getAnnotationsOfType(OA\Schema::class); + + foreach ($annotations as $annotation) { + $this->processReference($annotation); + $this->processNullable($annotation); + $this->processExclusiveMinimum($annotation); + $this->processExclusiveMaximum($annotation); + } + } + + private function processReference(OA\Schema $annotation): void + { + if (Generator::isDefault($annotation->ref)) { + return; + } + + + } + + private function processNullable(OA\Schema $annotation): void + { + $nullable = $annotation->nullable; + $annotation->nullable = Generator::UNDEFINED; // Unregister nullable property + + if (true !== $nullable) { + return; + } + + if (!Generator::isDefault($annotation->ref)) { + if (!Generator::isDefault($annotation->oneOf)) { + return; + } + + $annotation->oneOf = [new OA\Schema(['ref' => $annotation->ref]), new OA\Schema(['type' => 'null'])]; + $annotation->ref = Generator::UNDEFINED; + + return; + } + + if (is_array($annotation->oneOf)) { + $annotation->oneOf[] = new OA\Schema(['type' => 'null']); + } elseif (is_array($annotation->anyOf)) { + $annotation->anyOf[] = new OA\Schema(['type' => 'null']); + } elseif (is_array($annotation->allOf)) { + $annotation->allOf[] = new OA\Schema(['type' => 'null']); + } elseif (!Generator::isDefault($annotation->type)) { + $annotation->type = (array) $annotation->type; + $annotation->type[] = 'null'; + } + } + + private function processExclusiveMinimum(OA\Schema $annotation): void + { + if (Generator::isDefault($annotation->minimum) || Generator::isDefault($annotation->exclusiveMinimum)) { + return; + } + + if (true === $annotation->exclusiveMinimum) { + $annotation->exclusiveMinimum = $annotation->minimum; + $annotation->minimum = Generator::UNDEFINED; + } elseif (false === $annotation->exclusiveMinimum) { + $annotation->exclusiveMinimum = Generator::UNDEFINED; + } + } + + private function processExclusiveMaximum(OA\Schema $annotation): void + { + if (Generator::isDefault($annotation->maximum) || Generator::isDefault($annotation->exclusiveMaximum)) { + return; + } + + if (true === $annotation->exclusiveMaximum) { + $annotation->exclusiveMaximum = $annotation->maximum; + $annotation->maximum = Generator::UNDEFINED; + } elseif (false === $annotation->exclusiveMaximum) { + $annotation->exclusiveMaximum = Generator::UNDEFINED; + } + } +} diff --git a/tests/Fixtures/Scratch/NullRef31.php b/tests/Fixtures/Scratch/NullRef31.php index 2e6558b7d..5f658d375 100644 --- a/tests/Fixtures/Scratch/NullRef31.php +++ b/tests/Fixtures/Scratch/NullRef31.php @@ -45,7 +45,8 @@ public function refonly() description: 'Ref plus response', content: new OAT\JsonContent( ref: '#/components/schemas/repository', - description: 'The repository', + description: 'Will either respond with something or null', + example: 'Some example about the content', nullable: true ) ), diff --git a/tests/Fixtures/Scratch/NullRef31.yaml b/tests/Fixtures/Scratch/NullRef31.yaml index 4e62d4bb9..916b44ae9 100644 --- a/tests/Fixtures/Scratch/NullRef31.yaml +++ b/tests/Fixtures/Scratch/NullRef31.yaml @@ -23,11 +23,12 @@ paths: description: 'Ref plus response' content: application/json: + example: 'Some example about the content' schema: oneOf: - - { $ref: '#/components/schemas/repository', description: 'The repository' } + - { $ref: '#/components/schemas/repository' } - { type: 'null' } - description: 'The repository' + description: 'Will either respond with something or null' components: schemas: repository: { }