Skip to content

feat(OpenApiType): Suggest creating aliases for enums #209

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion generate-spec.php
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@
}
}
foreach (array_keys($definitions) as $name) {
$schemas[Helpers::cleanSchemaName($name)] = OpenApiType::resolve('Response definitions: ' . $name, $definitions, $definitions[$name])->toArray();
$schemas[Helpers::cleanSchemaName($name)] = OpenApiType::resolve('Response definitions: ' . $name, $definitions, $definitions[$name], true)->toArray();
}
} else {
Logger::debug('Response definitions', 'No response definitions were loaded');
Expand Down
13 changes: 11 additions & 2 deletions src/OpenApiType.php
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ enum: [0, 1],
return $values !== [] ? $values : new stdClass();
}

public static function resolve(string $context, array $definitions, ParamTagValueNode|NodeAbstract|TypeNode $node): OpenApiType {
public static function resolve(string $context, array $definitions, ParamTagValueNode|NodeAbstract|TypeNode $node, ?bool $isResponseDefinition = false): OpenApiType {
if ($node instanceof ParamTagValueNode) {
$type = self::resolve($context, $definitions, $node->type);
$type->description = $node->description;
Expand Down Expand Up @@ -276,6 +276,10 @@ public static function resolve(string $context, array $definitions, ParamTagValu
);
}

if (!$isResponseDefinition) {
Logger::warning($context, 'Consider using a Response definition for this enum to improve readability and reusability.');
}

return new OpenApiType(
context: $context,
type: 'string',
Expand All @@ -298,6 +302,10 @@ enum: $values,
);
}

if (!$isResponseDefinition) {
Logger::warning($context, 'Consider using a Response definition for this enum to improve readability and reusability.');
}

return new OpenApiType(
context: $context,
type: 'integer',
Expand Down Expand Up @@ -420,7 +428,8 @@ private static function mergeEnums(string $context, array $types): array {

return array_merge($nonEnums, array_map(static fn (string $type): \OpenAPIExtractor\OpenApiType => new OpenApiType(
context: $context,
type: $type, enum: $enums[$type],
type: $type,
enum: $enums[$type],
), array_keys($enums)));
}

Expand Down
2 changes: 2 additions & 0 deletions tests/appinfo/routes.php
Original file line number Diff line number Diff line change
Expand Up @@ -76,5 +76,7 @@
['name' => 'Settings#whitespace', 'url' => '/api/{apiVersion}/whitespace', 'verb' => 'POST', 'requirements' => ['apiVersion' => '(v2)']],
['name' => 'Settings#withCorsAnnotation', 'url' => '/api/{apiVersion}/cors/annotation', 'verb' => 'POST', 'requirements' => ['apiVersion' => '(v2)']],
['name' => 'Settings#withCorsAttribute', 'url' => '/api/{apiVersion}/cors/attribute', 'verb' => 'POST', 'requirements' => ['apiVersion' => '(v2)']],
['name' => 'Settings#enumNotAliased', 'url' => '/api/{apiVersion}/enum/not-aliased', 'verb' => 'POST', 'requirements' => ['apiVersion' => '(v2)']],
['name' => 'Settings#enumAliased', 'url' => '/api/{apiVersion}/enum/aliased', 'verb' => 'POST', 'requirements' => ['apiVersion' => '(v2)']],
],
];
30 changes: 30 additions & 0 deletions tests/lib/Controller/SettingsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
* @psalm-import-type NotificationsPushDevice from ResponseDefinitions
* @psalm-import-type NotificationsNotification from ResponseDefinitions
* @psalm-import-type NotificationsCollection from ResponseDefinitions
* @psalm-import-type NotificationsEnumString from ResponseDefinitions
* @psalm-import-type NotificationsEnumInt from ResponseDefinitions
*/
class SettingsController extends OCSController {
/**
Expand Down Expand Up @@ -596,4 +598,32 @@ public function withCorsAnnotation(): DataResponse {
public function withCorsAttribute(): DataResponse {
return new DataResponse();
}

/**
* Not aliased enum
*
* @param 'a'|'b' $string A string enum without alias
* @param 0|1 $int An int enum without alias
*
* @return DataResponse<Http::STATUS_OK, list<empty>, array{}>
*
* 200: OK
*/
public function enumNotAliased(string $string, int $int): DataResponse {
return new DataResponse();
}

/**
* Aliased enum
*
* @param NotificationsEnumString $string A string enum with alias
* @param NotificationsEnumInt $int An int enum with alias
*
* @return DataResponse<Http::STATUS_OK, list<empty>, array{}>
*
* 200: OK
*/
public function enumAliased(string $string, int $int): DataResponse {
return new DataResponse();
}
}
4 changes: 4 additions & 0 deletions tests/lib/ResponseDefinitions.php
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@
* publicKey: string,
* signature: string,
* }
*
* @psalm-type NotificationsEnumString = 'a'|'b'
*
* @psalm-type NotificationsEnumInt = 0|1
*/
class ResponseDefinitions {
}
216 changes: 216 additions & 0 deletions tests/openapi-administration.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,21 @@
}
}
},
"EnumInt": {
"type": "integer",
"format": "int64",
"enum": [
0,
1
]
},
"EnumString": {
"type": "string",
"enum": [
"a",
"b"
]
},
"OCSMeta": {
"type": "object",
"required": [
Expand Down Expand Up @@ -4638,6 +4653,207 @@
}
}
},
"/ocs/v2.php/apps/notifications/api/{apiVersion}/enum/not-aliased": {
"post": {
"operationId": "settings-enum-not-aliased",
"summary": "Not aliased enum",
"description": "This endpoint requires admin access",
"tags": [
"settings"
],
"security": [
{
"bearer_auth": []
},
{
"basic_auth": []
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"string",
"int"
],
"properties": {
"string": {
"type": "string",
"enum": [
"a",
"b"
],
"description": "A string enum without alias"
},
"int": {
"type": "integer",
"format": "int64",
"enum": [
0,
1
],
"description": "An int enum without alias"
}
}
}
}
}
},
"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": {}
}
}
}
}
}
}
}
}
}
},
"/ocs/v2.php/apps/notifications/api/{apiVersion}/enum/aliased": {
"post": {
"operationId": "settings-enum-aliased",
"summary": "Aliased enum",
"description": "This endpoint requires admin access",
"tags": [
"settings"
],
"security": [
{
"bearer_auth": []
},
{
"basic_auth": []
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"string",
"int"
],
"properties": {
"string": {
"$ref": "#/components/schemas/EnumString",
"description": "A string enum with alias"
},
"int": {
"$ref": "#/components/schemas/EnumInt",
"description": "An int enum with alias"
}
}
}
}
}
},
"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": {}
}
}
}
}
}
}
}
}
}
},
"/ocs/v2.php/tests/attribute-ocs/{param}": {
"get": {
"operationId": "routing-attributeocs-route",
Expand Down
Loading
Loading