diff --git a/src/OpenApiType.php b/src/OpenApiType.php index 68849b9..6996c6e 100644 --- a/src/OpenApiType.php +++ b/src/OpenApiType.php @@ -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, ); } diff --git a/tests/appinfo/routes.php b/tests/appinfo/routes.php index 794154b..6fa6daf 100644 --- a/tests/appinfo/routes.php +++ b/tests/appinfo/routes.php @@ -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)']], ], ]; diff --git a/tests/lib/Controller/SettingsController.php b/tests/lib/Controller/SettingsController.php index 4ea8dbd..307e2c9 100644 --- a/tests/lib/Controller/SettingsController.php +++ b/tests/lib/Controller/SettingsController.php @@ -486,4 +486,30 @@ public function passwordConfirmationAnnotation(): DataResponse { public function passwordConfirmationAttribute(): DataResponse { return new DataResponse(); } + + /** + * Route with oneOf + * + * @return DataResponse + * + * 200: OK + */ + #[PasswordConfirmationRequired] + public function oneOf(): DataResponse { + return new DataResponse(); + } + + /** + * Route with anyOf + * + * @return DataResponse|DataResponse|DataResponse + * + * 200: OK + * 201: CREATED + * 202: ACCEPTED + */ + #[PasswordConfirmationRequired] + public function anyOf(): DataResponse { + return new DataResponse(); + } } diff --git a/tests/openapi-administration.json b/tests/openapi-administration.json index fa5737a..98a4c9e 100644 --- a/tests/openapi-administration.json +++ b/tests/openapi-administration.json @@ -2573,6 +2573,310 @@ } } }, + "/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" + } + } + } + ] + } + } + } + } + } + } + } + }, + "202": { + "description": "ACCEPTED", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "anyOf": [ + { + "type": "number", + "format": "float" + }, + { + "type": "number", + "format": "double" + } + ] + } + } + } + } + } + } + } + } + } + } + }, "/ocs/v2.php/tests/attribute-ocs/{param}": { "get": { "operationId": "routing-attributeocs-route", diff --git a/tests/openapi-full.json b/tests/openapi-full.json index 93e0252..5ed771a 100644 --- a/tests/openapi-full.json +++ b/tests/openapi-full.json @@ -2700,6 +2700,310 @@ } } }, + "/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" + } + } + } + ] + } + } + } + } + } + } + } + }, + "202": { + "description": "ACCEPTED", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "anyOf": [ + { + "type": "number", + "format": "float" + }, + { + "type": "number", + "format": "double" + } + ] + } + } + } + } + } + } + } + } + } + } + }, "/ocs/v2.php/tests/attribute-ocs/{param}": { "get": { "operationId": "routing-attributeocs-route",