diff --git a/src/Annotations/AbstractAnnotation.php b/src/Annotations/AbstractAnnotation.php index c53aec05b..9a377fddb 100644 --- a/src/Annotations/AbstractAnnotation.php +++ b/src/Annotations/AbstractAnnotation.php @@ -308,7 +308,7 @@ public function jsonSerialize(): \stdClass if (is_numeric($key) === false && is_array($item)) { $object->{$key} = $item; } else { - $key = $item->{$keyField}; + $key = $item->{$keyField} ?? Generator::UNDEFINED; if (!Generator::isDefault($key) && empty($object->{$key})) { $object->{$key} = $item instanceof \JsonSerializable ? $item->jsonSerialize() : $item; unset($object->{$key}->{$keyField}); @@ -506,7 +506,7 @@ public function validate(?Analysis $analysis = null, string $version = OpenApi:: if (is_array($item) && !is_numeric($key)) { $this->_context->logger->warning($this->identity() . '->' . $property . ' is an object literal, use nested ' . AbstractAnnotation::shorten($annotationClass) . '() annotation(s) in ' . $this->_context); $keys[$key] = $item; - } elseif (Generator::isDefault($item->{$keyField})) { + } elseif (Generator::isDefault($item->{$keyField} ?? Generator::UNDEFINED)) { $this->_context->logger->error($item->identity() . ' is missing key-field: "' . $keyField . '" in ' . $item->_context); } elseif (isset($keys[$item->{$keyField}])) { $this->_context->logger->error('Multiple ' . $item->identity([]) . ' with the same ' . $keyField . '="' . $item->{$keyField} . "\":\n " . $item->_context . "\n " . $keys[$item->{$keyField}]->_context); diff --git a/src/Processors/AugmentParameters.php b/src/Processors/AugmentParameters.php index 7e2788b54..e13586dac 100644 --- a/src/Processors/AugmentParameters.php +++ b/src/Processors/AugmentParameters.php @@ -113,14 +113,14 @@ protected function augmentSharedParameters(Analysis $analysis): void $keys = []; $parametersWithoutKey = []; foreach ($analysis->openapi->components->parameters as $parameter) { - if (!Generator::isDefault($parameter->parameter)) { + if (!Generator::isDefault($parameter->parameter) && $parameter->parameter !== null) { $keys[$parameter->parameter] = $parameter; } else { $parametersWithoutKey[] = $parameter; } } foreach ($parametersWithoutKey as $parameter) { - if (!Generator::isDefault($parameter->name) && empty($keys[$parameter->name])) { + if (!Generator::isDefault($parameter->name) && $parameter->name !== null && empty($keys[$parameter->name])) { $parameter->parameter = $parameter->name; $keys[$parameter->parameter] = $parameter; } diff --git a/src/Processors/AugmentTags.php b/src/Processors/AugmentTags.php index e88b05129..e9b256648 100644 --- a/src/Processors/AugmentTags.php +++ b/src/Processors/AugmentTags.php @@ -61,7 +61,9 @@ public function __invoke(Analysis $analysis): void $declaredTags = []; if (!Generator::isDefault($analysis->openapi->tags)) { foreach ($analysis->openapi->tags as $tag) { - $declaredTags[$tag->name] = $tag; + if (!empty($tag->name)) { + $declaredTags[$tag->name] = $tag; + } } } if ($declaredTags) { diff --git a/tests/Annotations/AbstractAnnotationTest.php b/tests/Annotations/AbstractAnnotationTest.php index 884dfbcc5..52c1e38c6 100644 --- a/tests/Annotations/AbstractAnnotationTest.php +++ b/tests/Annotations/AbstractAnnotationTest.php @@ -156,6 +156,38 @@ public function testIdentity(OA\AbstractAnnotation $annotation, ?array $identity { $this->assertSame($expected, $annotation->identity($identityArgs)); } + + public function testNullKeyFieldSerialize(): void + { + $response = new OA\Response([ + 'response' => 200, + 'description' => 'Success', + 'headers' => [ + new OA\Header(['header' => null, '_context' => $this->getContext()]), + new OA\Header(['header' => 'X-Token', '_context' => $this->getContext()]), + ], + '_context' => $this->getContext(), + ]); + + $json = $response->jsonSerialize(); + $this->assertObjectHasProperty('headers', $json); + $this->assertObjectHasProperty('X-Token', $json->headers); + } + + public function testNullKeyFieldValidate(): void + { + $response = new OA\Response([ + 'response' => 200, + 'description' => 'Success', + 'headers' => [ + new OA\Header(['header' => null, '_context' => $this->getContext()]), + ], + '_context' => $this->getContext(), + ]); + + $this->assertOpenApiLogEntryContains('is missing key-field: "header"'); + $response->validate(); + } } class SubSchema extends OA\Schema