Skip to content

Commit

Permalink
fix(OpenApiType): Use anyOf instead of oneOf for conflicting types
Browse files Browse the repository at this point in the history
Signed-off-by: provokateurin <[email protected]>
  • Loading branch information
provokateurin committed Apr 10, 2024
1 parent 6bfd37f commit 4b13023
Show file tree
Hide file tree
Showing 5 changed files with 574 additions and 2 deletions.
19 changes: 17 additions & 2 deletions src/OpenApiType.php
Original file line number Diff line number Diff line change
Expand Up @@ -282,10 +282,25 @@ enum: $values,
return $type;
}

if ($isIntersection) {
return new OpenApiType(
nullable: $nullable,
allOf: $items,
);
}

$itemTypes = array_map(static fn (OpenApiType $item) => $item->type, $items);

if (!empty(array_filter($itemTypes, static fn (?string $type) => $type === null)) || count($itemTypes) !== count(array_unique($itemTypes))) {
return new OpenApiType(
nullable: $nullable,
anyOf: $items,
);
}

return new OpenApiType(
nullable: $nullable,
oneOf: $isUnion ? $items : null,
allOf: $isIntersection ? $items : null,
oneOf: $items,
);
}

Expand Down
2 changes: 2 additions & 0 deletions tests/appinfo/routes.php
Original file line number Diff line number Diff line change
Expand Up @@ -69,5 +69,7 @@
['name' => 'Settings#empty304', 'url' => '/api/{apiVersion}/304', 'verb' => 'POST', 'requirements' => ['apiVersion' => '(v2)']],
['name' => 'Settings#passwordConfirmationAnnotation', 'url' => '/api/{apiVersion}/passwordConfirmationAnnotation', 'verb' => 'POST', 'requirements' => ['apiVersion' => '(v2)']],
['name' => 'Settings#passwordConfirmationAttribute', 'url' => '/api/{apiVersion}/passwordConfirmationAttribute', 'verb' => 'POST', 'requirements' => ['apiVersion' => '(v2)']],
['name' => 'Settings#oneOf', 'url' => '/api/{apiVersion}/oneOf', 'verb' => 'POST', 'requirements' => ['apiVersion' => '(v2)']],
['name' => 'Settings#anyOf', 'url' => '/api/{apiVersion}/anyOf', 'verb' => 'POST', 'requirements' => ['apiVersion' => '(v2)']],
],
];
25 changes: 25 additions & 0 deletions tests/lib/Controller/SettingsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -486,4 +486,29 @@ public function passwordConfirmationAnnotation(): DataResponse {
public function passwordConfirmationAttribute(): DataResponse {
return new DataResponse();
}

/**
* Route with oneOf
*
* @return DataResponse<Http::STATUS_OK, string|int|double|bool, array{}>
*
* 200: OK
*/
#[PasswordConfirmationRequired]
public function oneOf(): DataResponse {
return new DataResponse();
}

/**
* Route with anyOf
*
* @return DataResponse<Http::STATUS_OK, array{test: string}|array{test: string, abc: int}, array{}>|DataResponse<Http::STATUS_CREATED, array{foobar: string}|array{disco: string, abc: int}|array{test: string, abc: int}, array{}>
*
* 200: OK
* 201: CREATED
*/
#[PasswordConfirmationRequired]
public function anyOf(): DataResponse {
return new DataResponse();
}
}
265 changes: 265 additions & 0 deletions tests/openapi-administration.json
Original file line number Diff line number Diff line change
Expand Up @@ -2573,6 +2573,271 @@
}
}
},
"/ocs/v2.php/apps/notifications/api/{apiVersion}/oneOf": {
"post": {
"operationId": "settings-one-of",
"summary": "Route with oneOf",
"description": "This endpoint requires admin access\nThis endpoint requires password confirmation",
"tags": [
"settings"
],
"security": [
{
"bearer_auth": []
},
{
"basic_auth": []
}
],
"parameters": [
{
"name": "apiVersion",
"in": "path",
"required": true,
"schema": {
"type": "string",
"enum": [
"v2"
],
"default": "v2"
}
},
{
"name": "OCS-APIRequest",
"in": "header",
"description": "Required to be true for the API request to pass",
"required": true,
"schema": {
"type": "boolean",
"default": true
}
}
],
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"ocs"
],
"properties": {
"ocs": {
"type": "object",
"required": [
"meta",
"data"
],
"properties": {
"meta": {
"$ref": "#/components/schemas/OCSMeta"
},
"data": {
"oneOf": [
{
"type": "string"
},
{
"type": "integer",
"format": "int64"
},
{
"type": "number",
"format": "double"
},
{
"type": "boolean"
}
]
}
}
}
}
}
}
}
}
}
}
},
"/ocs/v2.php/apps/notifications/api/{apiVersion}/anyOf": {
"post": {
"operationId": "settings-any-of",
"summary": "Route with anyOf",
"description": "This endpoint requires admin access\nThis endpoint requires password confirmation",
"tags": [
"settings"
],
"security": [
{
"bearer_auth": []
},
{
"basic_auth": []
}
],
"parameters": [
{
"name": "apiVersion",
"in": "path",
"required": true,
"schema": {
"type": "string",
"enum": [
"v2"
],
"default": "v2"
}
},
{
"name": "OCS-APIRequest",
"in": "header",
"description": "Required to be true for the API request to pass",
"required": true,
"schema": {
"type": "boolean",
"default": true
}
}
],
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"ocs"
],
"properties": {
"ocs": {
"type": "object",
"required": [
"meta",
"data"
],
"properties": {
"meta": {
"$ref": "#/components/schemas/OCSMeta"
},
"data": {
"anyOf": [
{
"type": "object",
"required": [
"test"
],
"properties": {
"test": {
"type": "string"
}
}
},
{
"type": "object",
"required": [
"test",
"abc"
],
"properties": {
"test": {
"type": "string"
},
"abc": {
"type": "integer",
"format": "int64"
}
}
}
]
}
}
}
}
}
}
}
},
"201": {
"description": "CREATED",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"ocs"
],
"properties": {
"ocs": {
"type": "object",
"required": [
"meta",
"data"
],
"properties": {
"meta": {
"$ref": "#/components/schemas/OCSMeta"
},
"data": {
"anyOf": [
{
"type": "object",
"required": [
"foobar"
],
"properties": {
"foobar": {
"type": "string"
}
}
},
{
"type": "object",
"required": [
"disco",
"abc"
],
"properties": {
"disco": {
"type": "string"
},
"abc": {
"type": "integer",
"format": "int64"
}
}
},
{
"type": "object",
"required": [
"test",
"abc"
],
"properties": {
"test": {
"type": "string"
},
"abc": {
"type": "integer",
"format": "int64"
}
}
}
]
}
}
}
}
}
}
}
}
}
}
},
"/ocs/v2.php/tests/attribute-ocs/{param}": {
"get": {
"operationId": "routing-attributeocs-route",
Expand Down
Loading

0 comments on commit 4b13023

Please sign in to comment.