Skip to content

Commit

Permalink
Merge pull request #105 from nextcloud/refactor/non-atomic-parameters…
Browse files Browse the repository at this point in the history
…-body
  • Loading branch information
provokateurin authored Jun 6, 2024
2 parents 90b3df0 + 826eaf2 commit 5f5f339
Show file tree
Hide file tree
Showing 4 changed files with 1,049 additions and 672 deletions.
78 changes: 49 additions & 29 deletions generate-spec
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ if (file_exists($definitionsPath)) {
}
}
foreach (array_keys($definitions) as $name) {
$schemas[Helpers::cleanSchemaName($name)] = OpenApiType::resolve("Response definitions", $definitions, $definitions[$name])->toArray($openapiVersion);
$schemas[Helpers::cleanSchemaName($name)] = OpenApiType::resolve("Response definitions", $definitions, $definitions[$name])->toArray();
}
} else {
Logger::debug("Response definitions", "No response definitions were loaded");
Expand Down Expand Up @@ -217,7 +217,7 @@ foreach ($capabilitiesFiles as $path) {
continue;
}

$schema = $type->toArray($openapiVersion);
$schema = $type->toArray();

if ($implementsPublicCapability) {
$publicCapabilities = $publicCapabilities == null ? $schema : Helpers::mergeSchemas([$publicCapabilities, $schema]);
Expand Down Expand Up @@ -596,7 +596,7 @@ foreach ($routes as $scope => $scopeRoutes) {
continue;
}

$schema = $parameter->type->toArray($openapiVersion, true);
$schema = $parameter->type->toArray(true);
$description = $parameter?->docType != null && $parameter->docType->description != "" ? Helpers::cleanDocComment($parameter->docType->description) : null;
} else {
$schema = [
Expand Down Expand Up @@ -651,7 +651,7 @@ foreach ($routes as $scope => $scopeRoutes) {
$pathParameters[] = $parameter;
}

$queryParameters = [];
$bodyParameters = [];
foreach ($route->controllerMethod->parameters as $parameter) {
$alreadyInPath = false;
foreach ($pathParameters as $pathParameter) {
Expand All @@ -661,7 +661,7 @@ foreach ($routes as $scope => $scopeRoutes) {
}
}
if (!$alreadyInPath) {
$queryParameters[] = $parameter;
$bodyParameters[] = $parameter;
}
}

Expand Down Expand Up @@ -689,19 +689,19 @@ foreach ($routes as $scope => $scopeRoutes) {
$contentTypeResponses = array_values(array_filter($statusCodeResponses, fn (ControllerMethodResponse $response) => $response->contentType == $contentType));

$hasEmpty = count(array_filter($contentTypeResponses, fn (ControllerMethodResponse $response) => $response->type == null)) > 0;
$uniqueResponses = array_values(array_intersect_key($contentTypeResponses, array_unique(array_map(fn (ControllerMethodResponse $response) => $response->type->toArray($openapiVersion), array_filter($contentTypeResponses, fn (ControllerMethodResponse $response) => $response->type != null)), SORT_REGULAR)));
$uniqueResponses = array_values(array_intersect_key($contentTypeResponses, array_unique(array_map(fn (ControllerMethodResponse $response) => $response->type->toArray(), array_filter($contentTypeResponses, fn (ControllerMethodResponse $response) => $response->type != null)), SORT_REGULAR)));
if (count($uniqueResponses) == 1) {
if ($hasEmpty) {
$mergedContentTypeResponses[$contentType] = [];
} else {
$schema = Helpers::cleanEmptyResponseArray($contentTypeResponses[0]->type->toArray($openapiVersion));
$schema = Helpers::cleanEmptyResponseArray($contentTypeResponses[0]->type->toArray());
$mergedContentTypeResponses[$contentType] = ["schema" => Helpers::wrapOCSResponse($route, $contentTypeResponses[0], $schema)];
}
} else {
$mergedContentTypeResponses[$contentType] = [
"schema" => [
[$hasEmpty ? "anyOf" : "oneOf" => array_map(function (ControllerMethodResponse $response) use ($route, $openapiVersion) {
$schema = Helpers::cleanEmptyResponseArray($response->type->toArray($openapiVersion));
[$hasEmpty ? "anyOf" : "oneOf" => array_map(function (ControllerMethodResponse $response) use ($route) {
$schema = Helpers::cleanEmptyResponseArray($response->type->toArray());
return Helpers::wrapOCSResponse($route, $response, $schema);
}, $uniqueResponses)],
],
Expand All @@ -717,7 +717,7 @@ foreach ($routes as $scope => $scopeRoutes) {
array_keys($headers),
array_map(
fn (OpenApiType $type) => [
"schema" => $type->toArray($openapiVersion),
"schema" => $type->toArray(),
],
array_values($headers),
),
Expand Down Expand Up @@ -761,25 +761,42 @@ foreach ($routes as $scope => $scopeRoutes) {
if (count($security) > 0) {
$operation["security"] = $security;
}
if (count($queryParameters) > 0 || count($pathParameters) > 0 || $route->isOCS) {
$parameters = [
...array_map(static function (ControllerMethodParameter $parameter) use ($openapiVersion) {
$out = [
"name" => $parameter->name . ($parameter->type->type === "array" ? "[]" : ""),
"in" => "query",
];
if ($parameter->docType !== null && $parameter->docType->description !== "") {
$out["description"] = Helpers::cleanDocComment($parameter->docType->description);
}
if (!$parameter->type->nullable && !$parameter->type->hasDefaultValue) {
$out["required"] = true;
}
$out["schema"] = $parameter->type->toArray($openapiVersion, true);
if (count($bodyParameters) > 0 || count($pathParameters) > 0 || $route->isOCS) {
$requiredBodyParameters = [];
$parameters = [];

return $out;
}, $queryParameters),
...$pathParameters,
];
foreach ($bodyParameters as $bodyParameter) {
$required = !$bodyParameter->type->nullable && !$bodyParameter->type->hasDefaultValue;
if ($required) {
$requiredBodyParameters[] = $bodyParameter->name;
}
}

if (count($bodyParameters) > 0) {
$required = count($requiredBodyParameters) > 0;

$schema = [
"type" => "object",
];
if ($required) {
$schema["required"] = $requiredBodyParameters;
}
$schema["properties"] = [];
foreach ($bodyParameters as $bodyParameter) {
$schema["properties"][$bodyParameter->name] = $bodyParameter->type->toArray();
}

$operation["requestBody"] = [
"required" => $required,
"content" => [
"application/json" => [
"schema" => $schema,
],
],
];
}

$parameters = array_merge($parameters, $pathParameters);
if ($route->isOCS) {
$parameters[] = [
"name" => "OCS-APIRequest",
Expand All @@ -792,7 +809,10 @@ foreach ($routes as $scope => $scopeRoutes) {
],
];
}
$operation["parameters"] = $parameters;

if (count($parameters) > 0) {
$operation["parameters"] = $parameters;
}
}
$operation["responses"] = $mergedResponses;

Expand Down
57 changes: 13 additions & 44 deletions src/OpenApiType.php
Original file line number Diff line number Diff line change
Expand Up @@ -53,62 +53,31 @@ public function __construct(
) {
}

public function toArray(string $openapiVersion, bool $isParameter = false): array|stdClass {
$asContentString = $isParameter && (
$this->type == "object" ||
$this->ref !== null ||
$this->anyOf !== null ||
$this->allOf !== null);
if ($asContentString) {
$values = [
"type" => "string",
];
if ($this->nullable) {
$values["nullable"] = true;
}
if (version_compare($openapiVersion, "3.1.0", ">=")) {
$values["contentMediaType"] = "application/json";
$values["contentSchema"] = $this->toArray($openapiVersion);
}

return $values;
}

$type = $this->type;
$defaultValue = $this->defaultValue;
$enum = $this->enum;
if ($isParameter && $type == "boolean") {
$type = "integer";
$enum = [0, 1];
if ($this->hasDefaultValue) {
$defaultValue = $defaultValue === true ? 1 : 0;
}
}

public function toArray(bool $isParameter = false): array|stdClass {
$values = [];
if ($this->ref !== null) {
$values["\$ref"] = $this->ref;
}
if ($type !== null) {
$values["type"] = $type;
if ($this->type !== null) {
$values["type"] = $this->type;
}
if ($this->format !== null) {
$values["format"] = $this->format;
}
if ($this->nullable) {
$values["nullable"] = true;
}
if ($this->hasDefaultValue && $defaultValue !== null) {
$values["default"] = $defaultValue;
if ($this->hasDefaultValue && $this->defaultValue !== null) {
$values["default"] = $this->defaultValue;
}
if ($enum !== null) {
$values["enum"] = $enum;
if ($this->enum !== null) {
$values["enum"] = $this->enum;
}
if ($this->description !== null && $this->description !== "" && !$isParameter) {
$values["description"] = $this->description;
}
if ($this->items !== null) {
$values["items"] = $this->items->toArray($openapiVersion);
$values["items"] = $this->items->toArray();
}
if ($this->minLength !== null) {
$values["minLength"] = $this->minLength;
Expand All @@ -133,24 +102,24 @@ public function toArray(string $openapiVersion, bool $isParameter = false): arra
}
if ($this->properties !== null && count($this->properties) > 0) {
$values["properties"] = array_combine(array_keys($this->properties),
array_map(static fn (OpenApiType $property) => $property->toArray($openapiVersion), array_values($this->properties)),
array_map(static fn (OpenApiType $property) => $property->toArray(), array_values($this->properties)),
);
}
if ($this->additionalProperties !== null) {
if ($this->additionalProperties instanceof OpenApiType) {
$values["additionalProperties"] = $this->additionalProperties->toArray($openapiVersion);
$values["additionalProperties"] = $this->additionalProperties->toArray();
} else {
$values["additionalProperties"] = $this->additionalProperties;
}
}
if ($this->oneOf !== null) {
$values["oneOf"] = array_map(fn (OpenApiType $type) => $type->toArray($openapiVersion), $this->oneOf);
$values["oneOf"] = array_map(fn (OpenApiType $type) => $type->toArray(), $this->oneOf);
}
if ($this->anyOf !== null) {
$values["anyOf"] = array_map(fn (OpenApiType $type) => $type->toArray($openapiVersion), $this->anyOf);
$values["anyOf"] = array_map(fn (OpenApiType $type) => $type->toArray(), $this->anyOf);
}
if ($this->allOf !== null) {
$values["allOf"] = array_map(fn (OpenApiType $type) => $type->toArray($openapiVersion), $this->allOf);
$values["allOf"] = array_map(fn (OpenApiType $type) => $type->toArray(), $this->allOf);
}

return count($values) > 0 ? $values : new stdClass();
Expand Down
Loading

0 comments on commit 5f5f339

Please sign in to comment.