From 490241e16c44ef7c58a1aabdc996ca4722a38e2b Mon Sep 17 00:00:00 2001 From: Konstantin Lapkovsky Date: Fri, 17 Nov 2023 11:11:48 +0400 Subject: [PATCH 1/6] feat: add response schemas. --- src/Services/SwaggerService.php | 56 +++++++++++++++++++ .../tmp_data_search_roles_request.json | 18 +++++- .../tmp_data_get_user_request.json | 23 +++++++- .../tmp_data_post_user_request.json | 15 ++++- ..._post_user_request_with_object_params.json | 15 ++++- ...tmp_data_search_roles_closure_request.json | 18 +++++- .../tmp_data_search_roles_request.json | 18 +++++- ...ch_roles_request_invalid_content_type.json | 15 ++++- ...ata_search_roles_request_jwt_security.json | 18 +++++- ...search_roles_request_laravel_security.json | 18 +++++- .../tmp_data_search_roles_request_pdf.json | 18 +++++- ..._data_search_roles_request_plain_text.json | 18 +++++- ...search_roles_request_with_annotations.json | 18 +++++- ...earch_roles_request_without_rule_type.json | 18 +++++- .../tmp_data_search_users_empty_request.json | 50 ++++++++++++++++- .../tmp_data_search_users_request.json | 50 ++++++++++++++++- 16 files changed, 360 insertions(+), 26 deletions(-) diff --git a/src/Services/SwaggerService.php b/src/Services/SwaggerService.php index c4da9e5..a775664 100755 --- a/src/Services/SwaggerService.php +++ b/src/Services/SwaggerService.php @@ -281,6 +281,53 @@ protected function markAsDeprecated(array $annotations) $this->item['deprecated'] = Arr::get($annotations, 'deprecated', false); } + protected function saveResponseSchema(?array $content) + { + if (empty($content)) { + return; + } + + $schemaProperties = []; + $action = Str::ucfirst($this->getActionName($this->uri)); + $schemaType = 'object'; + + if (array_is_list($content)) { + $schemaType = 'array'; + $types = []; + + foreach ($content as $value) { + $type = gettype($value); + if (!in_array($type, $types)) { + $types[] = $type; + $schemaProperties['items']['allOf'][]['type'] = $type; + } + } + } else { + $properties = Arr::get( + $this->data['definitions'], + "{$this->getActionName($this->uri)}ResponseObject.properties", + [] + ); + + foreach ($content as $name => $value) { + $property = Arr::get($properties, $name, []); + + if (is_null($value)) { + $property['nullable'] = true; + } else { + $property['type'] = gettype($value); + } + + $schemaProperties[$name] = $property; + } + } + + $this->data['definitions']["{$this->method}{$action}ResponseObject"] = [ + 'type' => $schemaType, + 'properties' => $schemaProperties + ]; + } + protected function parseResponse($response) { $produceList = $this->data['paths'][$this->uri][$this->method]['produces']; @@ -325,6 +372,15 @@ protected function parseResponse($response) $produce ); } + + if ($content && str_starts_with($code, 2)) { + $this->saveResponseSchema($content); + + $action = Str::ucfirst($this->getActionName($this->uri)); + if (is_array($this->item['responses'][$code])) { + $this->item['responses'][$code]['schema']['$ref'] = "#/definitions/{$this->method}{$action}ResponseObject"; + } + } } protected function saveExample($code, $content, $produce) diff --git a/tests/fixtures/AutoDocMiddlewareTest/tmp_data_search_roles_request.json b/tests/fixtures/AutoDocMiddlewareTest/tmp_data_search_roles_request.json index d97b41b..c06e0a0 100644 --- a/tests/fixtures/AutoDocMiddlewareTest/tmp_data_search_roles_request.json +++ b/tests/fixtures/AutoDocMiddlewareTest/tmp_data_search_roles_request.json @@ -65,7 +65,8 @@ } ] } - ] + ], + "$ref": "#/definitions/getUsersrolesResponseObject" } } }, @@ -76,7 +77,20 @@ } } }, - "definitions": {}, + "definitions": { + "getUsersrolesResponseObject": { + "type": "array", + "properties": { + "items": { + "allOf": [ + { + "type": "array" + } + ] + } + } + } + }, "info": { "description": "This is automatically collected documentation", "version": "0.0.0", diff --git a/tests/fixtures/SwaggerServiceTest/tmp_data_get_user_request.json b/tests/fixtures/SwaggerServiceTest/tmp_data_get_user_request.json index b50eb24..d2585c2 100644 --- a/tests/fixtures/SwaggerServiceTest/tmp_data_get_user_request.json +++ b/tests/fixtures/SwaggerServiceTest/tmp_data_get_user_request.json @@ -60,7 +60,8 @@ "id": 2, "name": "client" } - } + }, + "$ref": "#/definitions/getUsers{id}assignRole{roleId}ResponseObject" } } }, @@ -71,7 +72,25 @@ } } }, - "definitions": {}, + "definitions": { + "getUsers{id}assignRole{roleId}ResponseObject": { + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "name": { + "type": "string" + }, + "likes_count": { + "type": "integer" + }, + "role": { + "type": "array" + } + } + } + }, "info": { "description": "This is automatically collected documentation", "version": "0.0.0", diff --git a/tests/fixtures/SwaggerServiceTest/tmp_data_post_user_request.json b/tests/fixtures/SwaggerServiceTest/tmp_data_post_user_request.json index b32fb45..62bcb7a 100644 --- a/tests/fixtures/SwaggerServiceTest/tmp_data_post_user_request.json +++ b/tests/fixtures/SwaggerServiceTest/tmp_data_post_user_request.json @@ -55,7 +55,8 @@ } ] } - ] + ], + "$ref": "#/definitions/postUsersResponseObject" } } }, @@ -97,6 +98,18 @@ "required": [ "query" ] + }, + "postUsersResponseObject": { + "type": "array", + "properties": { + "items": { + "allOf": [ + { + "type": "array" + } + ] + } + } } }, "info": { diff --git a/tests/fixtures/SwaggerServiceTest/tmp_data_post_user_request_with_object_params.json b/tests/fixtures/SwaggerServiceTest/tmp_data_post_user_request_with_object_params.json index f3ba852..0b8d5f4 100644 --- a/tests/fixtures/SwaggerServiceTest/tmp_data_post_user_request_with_object_params.json +++ b/tests/fixtures/SwaggerServiceTest/tmp_data_post_user_request_with_object_params.json @@ -53,7 +53,8 @@ } ] } - ] + ], + "$ref": "#/definitions/postUsersResponseObject" } } }, @@ -93,6 +94,18 @@ "notification_settings": "RonasIT\\Support\\Tests\\Support\\Mock\\TestNotificationSetting" }, "required": ["query"] + }, + "postUsersResponseObject": { + "type": "array", + "properties": { + "items": { + "allOf": [ + { + "type": "array" + } + ] + } + } } }, "info": { diff --git a/tests/fixtures/SwaggerServiceTest/tmp_data_search_roles_closure_request.json b/tests/fixtures/SwaggerServiceTest/tmp_data_search_roles_closure_request.json index 29ca2f1..d4076bc 100644 --- a/tests/fixtures/SwaggerServiceTest/tmp_data_search_roles_closure_request.json +++ b/tests/fixtures/SwaggerServiceTest/tmp_data_search_roles_closure_request.json @@ -43,7 +43,8 @@ } ] } - ] + ], + "$ref": "#/definitions/getUsersrolesResponseObject" } } }, @@ -52,7 +53,20 @@ } } }, - "definitions": {}, + "definitions": { + "getUsersrolesResponseObject": { + "type": "array", + "properties": { + "items": { + "allOf": [ + { + "type": "array" + } + ] + } + } + } + }, "info": { "description": "This is automatically collected documentation", "version": "0.0.0", diff --git a/tests/fixtures/SwaggerServiceTest/tmp_data_search_roles_request.json b/tests/fixtures/SwaggerServiceTest/tmp_data_search_roles_request.json index cd42ead..5ae714e 100644 --- a/tests/fixtures/SwaggerServiceTest/tmp_data_search_roles_request.json +++ b/tests/fixtures/SwaggerServiceTest/tmp_data_search_roles_request.json @@ -65,7 +65,8 @@ } ] } - ] + ], + "$ref": "#/definitions/getUsersrolesResponseObject" } } }, @@ -76,7 +77,20 @@ } } }, - "definitions": {}, + "definitions": { + "getUsersrolesResponseObject": { + "type": "array", + "properties": { + "items": { + "allOf": [ + { + "type": "array" + } + ] + } + } + } + }, "info": { "description": "This is automatically collected documentation", "version": "0.0.0", diff --git a/tests/fixtures/SwaggerServiceTest/tmp_data_search_roles_request_invalid_content_type.json b/tests/fixtures/SwaggerServiceTest/tmp_data_search_roles_request_invalid_content_type.json index f59626a..a138b5c 100644 --- a/tests/fixtures/SwaggerServiceTest/tmp_data_search_roles_request_invalid_content_type.json +++ b/tests/fixtures/SwaggerServiceTest/tmp_data_search_roles_request_invalid_content_type.json @@ -46,7 +46,20 @@ } } }, - "definitions": {}, + "definitions": { + "getUsersrolesResponseObject": { + "type": "array", + "properties": { + "items": { + "allOf": [ + { + "type": "array" + } + ] + } + } + } + }, "info": { "description": "This is automatically collected documentation", "version": "0.0.0", diff --git a/tests/fixtures/SwaggerServiceTest/tmp_data_search_roles_request_jwt_security.json b/tests/fixtures/SwaggerServiceTest/tmp_data_search_roles_request_jwt_security.json index 5060a32..f1d75de 100644 --- a/tests/fixtures/SwaggerServiceTest/tmp_data_search_roles_request_jwt_security.json +++ b/tests/fixtures/SwaggerServiceTest/tmp_data_search_roles_request_jwt_security.json @@ -65,7 +65,8 @@ } ] } - ] + ], + "$ref": "#/definitions/getUsersrolesResponseObject" } } }, @@ -76,7 +77,20 @@ } } }, - "definitions": {}, + "definitions": { + "getUsersrolesResponseObject": { + "type": "array", + "properties": { + "items": { + "allOf": [ + { + "type": "array" + } + ] + } + } + } + }, "info": { "description": "This is automatically collected documentation", "version": "0.0.0", diff --git a/tests/fixtures/SwaggerServiceTest/tmp_data_search_roles_request_laravel_security.json b/tests/fixtures/SwaggerServiceTest/tmp_data_search_roles_request_laravel_security.json index d3f3cb7..13b0d65 100644 --- a/tests/fixtures/SwaggerServiceTest/tmp_data_search_roles_request_laravel_security.json +++ b/tests/fixtures/SwaggerServiceTest/tmp_data_search_roles_request_laravel_security.json @@ -65,7 +65,8 @@ } ] } - ] + ], + "$ref": "#/definitions/getUsersrolesResponseObject" } } }, @@ -76,7 +77,20 @@ } } }, - "definitions": {}, + "definitions": { + "getUsersrolesResponseObject": { + "type": "array", + "properties": { + "items": { + "allOf": [ + { + "type": "array" + } + ] + } + } + } + }, "info": { "description": "This is automatically collected documentation", "version": "0.0.0", diff --git a/tests/fixtures/SwaggerServiceTest/tmp_data_search_roles_request_pdf.json b/tests/fixtures/SwaggerServiceTest/tmp_data_search_roles_request_pdf.json index 03e4c89..cefbafa 100644 --- a/tests/fixtures/SwaggerServiceTest/tmp_data_search_roles_request_pdf.json +++ b/tests/fixtures/SwaggerServiceTest/tmp_data_search_roles_request_pdf.json @@ -40,7 +40,8 @@ "200": { "description": "Operation successfully done", "schema": { - "example": "WwogICAgewogICAgICAgICJpZCI6IDEsCiAgICAgICAgIm5hbWUiOiAiYWRtaW4iLAogICAgICAgICJ1c2VycyI6IFsKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgImlkIjogMSwKICAgICAgICAgICAgICAgICJuYW1lIjogImFkbWluIgogICAgICAgICAgICB9CiAgICAgICAgXQogICAgfSwKICAgIHsKICAgICAgICAiaWQiOiAyLAogICAgICAgICJuYW1lIjogImNsaWVudCIsCiAgICAgICAgInVzZXJzIjogWwogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAiaWQiOiAyLAogICAgICAgICAgICAgICAgIm5hbWUiOiAiZmlyc3RfY2xpZW50IgogICAgICAgICAgICB9LAogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAiaWQiOiAzLAogICAgICAgICAgICAgICAgIm5hbWUiOiAic2Vjb25kX2NsaWVudCIKICAgICAgICAgICAgfQogICAgICAgIF0KICAgIH0KXQ==" + "example": "WwogICAgewogICAgICAgICJpZCI6IDEsCiAgICAgICAgIm5hbWUiOiAiYWRtaW4iLAogICAgICAgICJ1c2VycyI6IFsKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgImlkIjogMSwKICAgICAgICAgICAgICAgICJuYW1lIjogImFkbWluIgogICAgICAgICAgICB9CiAgICAgICAgXQogICAgfSwKICAgIHsKICAgICAgICAiaWQiOiAyLAogICAgICAgICJuYW1lIjogImNsaWVudCIsCiAgICAgICAgInVzZXJzIjogWwogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAiaWQiOiAyLAogICAgICAgICAgICAgICAgIm5hbWUiOiAiZmlyc3RfY2xpZW50IgogICAgICAgICAgICB9LAogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAiaWQiOiAzLAogICAgICAgICAgICAgICAgIm5hbWUiOiAic2Vjb25kX2NsaWVudCIKICAgICAgICAgICAgfQogICAgICAgIF0KICAgIH0KXQ==", + "$ref": "#/definitions/getUsersrolesResponseObject" } } }, @@ -51,7 +52,20 @@ } } }, - "definitions": {}, + "definitions": { + "getUsersrolesResponseObject": { + "type": "array", + "properties": { + "items": { + "allOf": [ + { + "type": "array" + } + ] + } + } + } + }, "info": { "description": "This is automatically collected documentation", "version": "0.0.0", diff --git a/tests/fixtures/SwaggerServiceTest/tmp_data_search_roles_request_plain_text.json b/tests/fixtures/SwaggerServiceTest/tmp_data_search_roles_request_plain_text.json index ebc72a6..d7f4633 100644 --- a/tests/fixtures/SwaggerServiceTest/tmp_data_search_roles_request_plain_text.json +++ b/tests/fixtures/SwaggerServiceTest/tmp_data_search_roles_request_plain_text.json @@ -41,6 +41,9 @@ "description": "Operation successfully done", "examples": { "example": "[\n {\n \"id\": 1,\n \"name\": \"admin\",\n \"users\": [\n {\n \"id\": 1,\n \"name\": \"admin\"\n }\n ]\n }\n]" + }, + "schema": { + "$ref": "#/definitions/getUsersrolesResponseObject" } } }, @@ -51,7 +54,20 @@ } } }, - "definitions": {}, + "definitions": { + "getUsersrolesResponseObject": { + "type": "array", + "properties": { + "items": { + "allOf": [ + { + "type": "array" + } + ] + } + } + } + }, "info": { "description": "This is automatically collected documentation", "version": "0.0.0", diff --git a/tests/fixtures/SwaggerServiceTest/tmp_data_search_roles_request_with_annotations.json b/tests/fixtures/SwaggerServiceTest/tmp_data_search_roles_request_with_annotations.json index 7cbad83..97cf9d7 100644 --- a/tests/fixtures/SwaggerServiceTest/tmp_data_search_roles_request_with_annotations.json +++ b/tests/fixtures/SwaggerServiceTest/tmp_data_search_roles_request_with_annotations.json @@ -53,7 +53,8 @@ } ] } - ] + ], + "$ref": "#/definitions/getUsersrolesResponseObject" } } }, @@ -64,7 +65,20 @@ } } }, - "definitions": {}, + "definitions": { + "getUsersrolesResponseObject": { + "type": "array", + "properties": { + "items": { + "allOf": [ + { + "type": "array" + } + ] + } + } + } + }, "info": { "description": "This is automatically collected documentation", "version": "0.0.0", diff --git a/tests/fixtures/SwaggerServiceTest/tmp_data_search_roles_request_without_rule_type.json b/tests/fixtures/SwaggerServiceTest/tmp_data_search_roles_request_without_rule_type.json index 4e7e533..6bfe4f1 100644 --- a/tests/fixtures/SwaggerServiceTest/tmp_data_search_roles_request_without_rule_type.json +++ b/tests/fixtures/SwaggerServiceTest/tmp_data_search_roles_request_without_rule_type.json @@ -53,7 +53,8 @@ } ] } - ] + ], + "$ref": "#/definitions/getUsersrolesResponseObject" } } }, @@ -64,7 +65,20 @@ } } }, - "definitions": {}, + "definitions": { + "getUsersrolesResponseObject": { + "type": "array", + "properties": { + "items": { + "allOf": [ + { + "type": "array" + } + ] + } + } + } + }, "info": { "description": "This is automatically collected documentation", "version": "0.0.0", diff --git a/tests/fixtures/SwaggerServiceTest/tmp_data_search_users_empty_request.json b/tests/fixtures/SwaggerServiceTest/tmp_data_search_users_empty_request.json index 3ff508f..7e0c376 100644 --- a/tests/fixtures/SwaggerServiceTest/tmp_data_search_users_empty_request.json +++ b/tests/fixtures/SwaggerServiceTest/tmp_data_search_users_empty_request.json @@ -69,7 +69,8 @@ "prev_page_url": null, "to": 1, "total": 1 - } + }, + "$ref": "#/definitions/getApiusersResponseObject" } } }, @@ -79,7 +80,52 @@ } } }, - "definitions": [], + "definitions": { + "getApiusersResponseObject": { + "type": "object", + "properties": { + "current_page": { + "type": "integer" + }, + "data": { + "type": "array" + }, + "first_page_url": { + "type": "string" + }, + "from": { + "type": "integer" + }, + "last_page": { + "type": "integer" + }, + "last_page_url": { + "type": "string" + }, + "links": { + "type": "array" + }, + "next_page_url": { + "nullable": true + }, + "path": { + "type": "string" + }, + "per_page": { + "type": "integer" + }, + "prev_page_url": { + "nullable": true + }, + "to": { + "type": "integer" + }, + "total": { + "type": "integer" + } + } + } + }, "info": { "description": "This is automatically collected documentation", diff --git a/tests/fixtures/SwaggerServiceTest/tmp_data_search_users_request.json b/tests/fixtures/SwaggerServiceTest/tmp_data_search_users_request.json index c3a6218..4f8405f 100644 --- a/tests/fixtures/SwaggerServiceTest/tmp_data_search_users_request.json +++ b/tests/fixtures/SwaggerServiceTest/tmp_data_search_users_request.json @@ -89,7 +89,8 @@ "prev_page_url": null, "to": 1, "total": 1 - } + }, + "$ref": "#/definitions/getApiusersResponseObject" } } }, @@ -101,7 +102,52 @@ } } }, - "definitions": [], + "definitions": { + "getApiusersResponseObject": { + "type": "object", + "properties": { + "current_page": { + "type": "integer" + }, + "data": { + "type": "array" + }, + "first_page_url": { + "type": "string" + }, + "from": { + "type": "integer" + }, + "last_page": { + "type": "integer" + }, + "last_page_url": { + "type": "string" + }, + "links": { + "type": "array" + }, + "next_page_url": { + "nullable": true + }, + "path": { + "type": "string" + }, + "per_page": { + "type": "integer" + }, + "prev_page_url": { + "nullable": true + }, + "to": { + "type": "integer" + }, + "total": { + "type": "integer" + } + } + } + }, "info": { "description": "This is automatically collected documentation", From ff511b78f4bd48357f12a0c2ef6e48952315ad70 Mon Sep 17 00:00:00 2001 From: Konstantin Lapkovsky Date: Fri, 17 Nov 2023 12:14:21 +0400 Subject: [PATCH 2/6] style: shorter line length. --- src/Services/SwaggerService.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Services/SwaggerService.php b/src/Services/SwaggerService.php index a775664..a434fc1 100755 --- a/src/Services/SwaggerService.php +++ b/src/Services/SwaggerService.php @@ -376,9 +376,11 @@ protected function parseResponse($response) if ($content && str_starts_with($code, 2)) { $this->saveResponseSchema($content); - $action = Str::ucfirst($this->getActionName($this->uri)); if (is_array($this->item['responses'][$code])) { - $this->item['responses'][$code]['schema']['$ref'] = "#/definitions/{$this->method}{$action}ResponseObject"; + $action = Str::ucfirst($this->getActionName($this->uri)); + $definition = "#/definitions/{$this->method}{$action}ResponseObject"; + + $this->item['responses'][$code]['schema']['$ref'] = $definition; } } } From ec7b5de3f7c852797b4af887a072ed49f20946d5 Mon Sep 17 00:00:00 2001 From: Konstantin Lapkovsky Date: Tue, 5 Dec 2023 14:56:35 +0400 Subject: [PATCH 3/6] chore: correct schema definition. --- src/Services/SwaggerService.php | 18 ++++++++---------- .../tmp_data_search_roles_request.json | 4 ++-- .../tmp_data_create_user_request.json | 9 +++++++++ .../tmp_data_get_user_request.json | 4 ++-- .../tmp_data_post_user_request.json | 4 ++-- ...a_post_user_request_with_object_params.json | 4 ++-- ..._user_request_with_early_generated_doc.json | 3 ++- .../tmp_data_search_roles_closure_request.json | 4 ++-- .../tmp_data_search_roles_request.json | 4 ++-- ...rch_roles_request_invalid_content_type.json | 2 +- ...data_search_roles_request_jwt_security.json | 4 ++-- ..._search_roles_request_laravel_security.json | 4 ++-- .../tmp_data_search_roles_request_pdf.json | 4 ++-- ...p_data_search_roles_request_plain_text.json | 4 ++-- ..._search_roles_request_with_annotations.json | 4 ++-- ...search_roles_request_without_rule_type.json | 4 ++-- .../tmp_data_search_users_empty_request.json | 4 ++-- .../tmp_data_search_users_request.json | 4 ++-- 18 files changed, 48 insertions(+), 40 deletions(-) diff --git a/src/Services/SwaggerService.php b/src/Services/SwaggerService.php index a434fc1..f295b50 100755 --- a/src/Services/SwaggerService.php +++ b/src/Services/SwaggerService.php @@ -281,7 +281,7 @@ protected function markAsDeprecated(array $annotations) $this->item['deprecated'] = Arr::get($annotations, 'deprecated', false); } - protected function saveResponseSchema(?array $content) + protected function saveResponseSchema(?array $content, int $code) { if (empty($content)) { return; @@ -305,7 +305,7 @@ protected function saveResponseSchema(?array $content) } else { $properties = Arr::get( $this->data['definitions'], - "{$this->getActionName($this->uri)}ResponseObject.properties", + "{$this->method}{$action}{$code}ResponseObject.properties", [] ); @@ -322,7 +322,7 @@ protected function saveResponseSchema(?array $content) } } - $this->data['definitions']["{$this->method}{$action}ResponseObject"] = [ + $this->data['definitions']["{$this->method}{$action}{$code}ResponseObject"] = [ 'type' => $schemaType, 'properties' => $schemaProperties ]; @@ -373,15 +373,13 @@ protected function parseResponse($response) ); } - if ($content && str_starts_with($code, 2)) { - $this->saveResponseSchema($content); + $this->saveResponseSchema($content, $code); - if (is_array($this->item['responses'][$code])) { - $action = Str::ucfirst($this->getActionName($this->uri)); - $definition = "#/definitions/{$this->method}{$action}ResponseObject"; + if (is_array($this->item['responses'][$code])) { + $action = Str::ucfirst($this->getActionName($this->uri)); + $definition = "#/definitions/{$this->method}{$action}{$code}ResponseObject"; - $this->item['responses'][$code]['schema']['$ref'] = $definition; - } + $this->item['responses'][$code]['schema']['$ref'] = $definition; } } diff --git a/tests/fixtures/AutoDocMiddlewareTest/tmp_data_search_roles_request.json b/tests/fixtures/AutoDocMiddlewareTest/tmp_data_search_roles_request.json index c06e0a0..c7e70b6 100644 --- a/tests/fixtures/AutoDocMiddlewareTest/tmp_data_search_roles_request.json +++ b/tests/fixtures/AutoDocMiddlewareTest/tmp_data_search_roles_request.json @@ -66,7 +66,7 @@ ] } ], - "$ref": "#/definitions/getUsersrolesResponseObject" + "$ref": "#/definitions/getUsersroles200ResponseObject" } } }, @@ -78,7 +78,7 @@ } }, "definitions": { - "getUsersrolesResponseObject": { + "getUsersroles200ResponseObject": { "type": "array", "properties": { "items": { diff --git a/tests/fixtures/SwaggerServiceTest/tmp_data_create_user_request.json b/tests/fixtures/SwaggerServiceTest/tmp_data_create_user_request.json index f4c8403..6b8b857 100644 --- a/tests/fixtures/SwaggerServiceTest/tmp_data_create_user_request.json +++ b/tests/fixtures/SwaggerServiceTest/tmp_data_create_user_request.json @@ -30,6 +30,7 @@ "description": "Forbidden", "schema": { + "$ref": "#/definitions/postApiusers403ResponseObject", "example": { "message": "This action is unauthorized." @@ -68,6 +69,14 @@ "first_name": "andrey", "last_name": "voronin" } + }, + "postApiusers403ResponseObject": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + } } }, "info": diff --git a/tests/fixtures/SwaggerServiceTest/tmp_data_get_user_request.json b/tests/fixtures/SwaggerServiceTest/tmp_data_get_user_request.json index d2585c2..d596add 100644 --- a/tests/fixtures/SwaggerServiceTest/tmp_data_get_user_request.json +++ b/tests/fixtures/SwaggerServiceTest/tmp_data_get_user_request.json @@ -61,7 +61,7 @@ "name": "client" } }, - "$ref": "#/definitions/getUsers{id}assignRole{roleId}ResponseObject" + "$ref": "#/definitions/getUsers{id}assignRole{roleId}200ResponseObject" } } }, @@ -73,7 +73,7 @@ } }, "definitions": { - "getUsers{id}assignRole{roleId}ResponseObject": { + "getUsers{id}assignRole{roleId}200ResponseObject": { "type": "object", "properties": { "id": { diff --git a/tests/fixtures/SwaggerServiceTest/tmp_data_post_user_request.json b/tests/fixtures/SwaggerServiceTest/tmp_data_post_user_request.json index 62bcb7a..4b06ca3 100644 --- a/tests/fixtures/SwaggerServiceTest/tmp_data_post_user_request.json +++ b/tests/fixtures/SwaggerServiceTest/tmp_data_post_user_request.json @@ -56,7 +56,7 @@ ] } ], - "$ref": "#/definitions/postUsersResponseObject" + "$ref": "#/definitions/postUsers200ResponseObject" } } }, @@ -99,7 +99,7 @@ "query" ] }, - "postUsersResponseObject": { + "postUsers200ResponseObject": { "type": "array", "properties": { "items": { diff --git a/tests/fixtures/SwaggerServiceTest/tmp_data_post_user_request_with_object_params.json b/tests/fixtures/SwaggerServiceTest/tmp_data_post_user_request_with_object_params.json index 0b8d5f4..8951d69 100644 --- a/tests/fixtures/SwaggerServiceTest/tmp_data_post_user_request_with_object_params.json +++ b/tests/fixtures/SwaggerServiceTest/tmp_data_post_user_request_with_object_params.json @@ -54,7 +54,7 @@ ] } ], - "$ref": "#/definitions/postUsersResponseObject" + "$ref": "#/definitions/postUsers200ResponseObject" } } }, @@ -95,7 +95,7 @@ }, "required": ["query"] }, - "postUsersResponseObject": { + "postUsers200ResponseObject": { "type": "array", "properties": { "items": { diff --git a/tests/fixtures/SwaggerServiceTest/tmp_data_put_user_request_with_early_generated_doc.json b/tests/fixtures/SwaggerServiceTest/tmp_data_put_user_request_with_early_generated_doc.json index 25aef98..d0b96c6 100644 --- a/tests/fixtures/SwaggerServiceTest/tmp_data_put_user_request_with_early_generated_doc.json +++ b/tests/fixtures/SwaggerServiceTest/tmp_data_put_user_request_with_early_generated_doc.json @@ -103,7 +103,8 @@ "204": { "description": "Operation successfully done", "schema": { - "example": null + "example": null, + "$ref": "#/definitions/patchUsers{id}204ResponseObject" } } }, diff --git a/tests/fixtures/SwaggerServiceTest/tmp_data_search_roles_closure_request.json b/tests/fixtures/SwaggerServiceTest/tmp_data_search_roles_closure_request.json index d4076bc..0bcfd57 100644 --- a/tests/fixtures/SwaggerServiceTest/tmp_data_search_roles_closure_request.json +++ b/tests/fixtures/SwaggerServiceTest/tmp_data_search_roles_closure_request.json @@ -44,7 +44,7 @@ ] } ], - "$ref": "#/definitions/getUsersrolesResponseObject" + "$ref": "#/definitions/getUsersroles200ResponseObject" } } }, @@ -54,7 +54,7 @@ } }, "definitions": { - "getUsersrolesResponseObject": { + "getUsersroles200ResponseObject": { "type": "array", "properties": { "items": { diff --git a/tests/fixtures/SwaggerServiceTest/tmp_data_search_roles_request.json b/tests/fixtures/SwaggerServiceTest/tmp_data_search_roles_request.json index 5ae714e..b6176e5 100644 --- a/tests/fixtures/SwaggerServiceTest/tmp_data_search_roles_request.json +++ b/tests/fixtures/SwaggerServiceTest/tmp_data_search_roles_request.json @@ -66,7 +66,7 @@ ] } ], - "$ref": "#/definitions/getUsersrolesResponseObject" + "$ref": "#/definitions/getUsersroles200ResponseObject" } } }, @@ -78,7 +78,7 @@ } }, "definitions": { - "getUsersrolesResponseObject": { + "getUsersroles200ResponseObject": { "type": "array", "properties": { "items": { diff --git a/tests/fixtures/SwaggerServiceTest/tmp_data_search_roles_request_invalid_content_type.json b/tests/fixtures/SwaggerServiceTest/tmp_data_search_roles_request_invalid_content_type.json index a138b5c..7c618ae 100644 --- a/tests/fixtures/SwaggerServiceTest/tmp_data_search_roles_request_invalid_content_type.json +++ b/tests/fixtures/SwaggerServiceTest/tmp_data_search_roles_request_invalid_content_type.json @@ -47,7 +47,7 @@ } }, "definitions": { - "getUsersrolesResponseObject": { + "getUsersroles200ResponseObject": { "type": "array", "properties": { "items": { diff --git a/tests/fixtures/SwaggerServiceTest/tmp_data_search_roles_request_jwt_security.json b/tests/fixtures/SwaggerServiceTest/tmp_data_search_roles_request_jwt_security.json index f1d75de..c50c547 100644 --- a/tests/fixtures/SwaggerServiceTest/tmp_data_search_roles_request_jwt_security.json +++ b/tests/fixtures/SwaggerServiceTest/tmp_data_search_roles_request_jwt_security.json @@ -66,7 +66,7 @@ ] } ], - "$ref": "#/definitions/getUsersrolesResponseObject" + "$ref": "#/definitions/getUsersroles200ResponseObject" } } }, @@ -78,7 +78,7 @@ } }, "definitions": { - "getUsersrolesResponseObject": { + "getUsersroles200ResponseObject": { "type": "array", "properties": { "items": { diff --git a/tests/fixtures/SwaggerServiceTest/tmp_data_search_roles_request_laravel_security.json b/tests/fixtures/SwaggerServiceTest/tmp_data_search_roles_request_laravel_security.json index 13b0d65..ffd79a9 100644 --- a/tests/fixtures/SwaggerServiceTest/tmp_data_search_roles_request_laravel_security.json +++ b/tests/fixtures/SwaggerServiceTest/tmp_data_search_roles_request_laravel_security.json @@ -66,7 +66,7 @@ ] } ], - "$ref": "#/definitions/getUsersrolesResponseObject" + "$ref": "#/definitions/getUsersroles200ResponseObject" } } }, @@ -78,7 +78,7 @@ } }, "definitions": { - "getUsersrolesResponseObject": { + "getUsersroles200ResponseObject": { "type": "array", "properties": { "items": { diff --git a/tests/fixtures/SwaggerServiceTest/tmp_data_search_roles_request_pdf.json b/tests/fixtures/SwaggerServiceTest/tmp_data_search_roles_request_pdf.json index cefbafa..b725c94 100644 --- a/tests/fixtures/SwaggerServiceTest/tmp_data_search_roles_request_pdf.json +++ b/tests/fixtures/SwaggerServiceTest/tmp_data_search_roles_request_pdf.json @@ -41,7 +41,7 @@ "description": "Operation successfully done", "schema": { "example": "WwogICAgewogICAgICAgICJpZCI6IDEsCiAgICAgICAgIm5hbWUiOiAiYWRtaW4iLAogICAgICAgICJ1c2VycyI6IFsKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgImlkIjogMSwKICAgICAgICAgICAgICAgICJuYW1lIjogImFkbWluIgogICAgICAgICAgICB9CiAgICAgICAgXQogICAgfSwKICAgIHsKICAgICAgICAiaWQiOiAyLAogICAgICAgICJuYW1lIjogImNsaWVudCIsCiAgICAgICAgInVzZXJzIjogWwogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAiaWQiOiAyLAogICAgICAgICAgICAgICAgIm5hbWUiOiAiZmlyc3RfY2xpZW50IgogICAgICAgICAgICB9LAogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAiaWQiOiAzLAogICAgICAgICAgICAgICAgIm5hbWUiOiAic2Vjb25kX2NsaWVudCIKICAgICAgICAgICAgfQogICAgICAgIF0KICAgIH0KXQ==", - "$ref": "#/definitions/getUsersrolesResponseObject" + "$ref": "#/definitions/getUsersroles200ResponseObject" } } }, @@ -53,7 +53,7 @@ } }, "definitions": { - "getUsersrolesResponseObject": { + "getUsersroles200ResponseObject": { "type": "array", "properties": { "items": { diff --git a/tests/fixtures/SwaggerServiceTest/tmp_data_search_roles_request_plain_text.json b/tests/fixtures/SwaggerServiceTest/tmp_data_search_roles_request_plain_text.json index d7f4633..1bd8547 100644 --- a/tests/fixtures/SwaggerServiceTest/tmp_data_search_roles_request_plain_text.json +++ b/tests/fixtures/SwaggerServiceTest/tmp_data_search_roles_request_plain_text.json @@ -43,7 +43,7 @@ "example": "[\n {\n \"id\": 1,\n \"name\": \"admin\",\n \"users\": [\n {\n \"id\": 1,\n \"name\": \"admin\"\n }\n ]\n }\n]" }, "schema": { - "$ref": "#/definitions/getUsersrolesResponseObject" + "$ref": "#/definitions/getUsersroles200ResponseObject" } } }, @@ -55,7 +55,7 @@ } }, "definitions": { - "getUsersrolesResponseObject": { + "getUsersroles200ResponseObject": { "type": "array", "properties": { "items": { diff --git a/tests/fixtures/SwaggerServiceTest/tmp_data_search_roles_request_with_annotations.json b/tests/fixtures/SwaggerServiceTest/tmp_data_search_roles_request_with_annotations.json index 97cf9d7..98acde9 100644 --- a/tests/fixtures/SwaggerServiceTest/tmp_data_search_roles_request_with_annotations.json +++ b/tests/fixtures/SwaggerServiceTest/tmp_data_search_roles_request_with_annotations.json @@ -54,7 +54,7 @@ ] } ], - "$ref": "#/definitions/getUsersrolesResponseObject" + "$ref": "#/definitions/getUsersroles200ResponseObject" } } }, @@ -66,7 +66,7 @@ } }, "definitions": { - "getUsersrolesResponseObject": { + "getUsersroles200ResponseObject": { "type": "array", "properties": { "items": { diff --git a/tests/fixtures/SwaggerServiceTest/tmp_data_search_roles_request_without_rule_type.json b/tests/fixtures/SwaggerServiceTest/tmp_data_search_roles_request_without_rule_type.json index 6bfe4f1..1c62bab 100644 --- a/tests/fixtures/SwaggerServiceTest/tmp_data_search_roles_request_without_rule_type.json +++ b/tests/fixtures/SwaggerServiceTest/tmp_data_search_roles_request_without_rule_type.json @@ -54,7 +54,7 @@ ] } ], - "$ref": "#/definitions/getUsersrolesResponseObject" + "$ref": "#/definitions/getUsersroles200ResponseObject" } } }, @@ -66,7 +66,7 @@ } }, "definitions": { - "getUsersrolesResponseObject": { + "getUsersroles200ResponseObject": { "type": "array", "properties": { "items": { diff --git a/tests/fixtures/SwaggerServiceTest/tmp_data_search_users_empty_request.json b/tests/fixtures/SwaggerServiceTest/tmp_data_search_users_empty_request.json index 7e0c376..6182997 100644 --- a/tests/fixtures/SwaggerServiceTest/tmp_data_search_users_empty_request.json +++ b/tests/fixtures/SwaggerServiceTest/tmp_data_search_users_empty_request.json @@ -70,7 +70,7 @@ "to": 1, "total": 1 }, - "$ref": "#/definitions/getApiusersResponseObject" + "$ref": "#/definitions/getApiusers200ResponseObject" } } }, @@ -81,7 +81,7 @@ } }, "definitions": { - "getApiusersResponseObject": { + "getApiusers200ResponseObject": { "type": "object", "properties": { "current_page": { diff --git a/tests/fixtures/SwaggerServiceTest/tmp_data_search_users_request.json b/tests/fixtures/SwaggerServiceTest/tmp_data_search_users_request.json index 4f8405f..943c46a 100644 --- a/tests/fixtures/SwaggerServiceTest/tmp_data_search_users_request.json +++ b/tests/fixtures/SwaggerServiceTest/tmp_data_search_users_request.json @@ -90,7 +90,7 @@ "to": 1, "total": 1 }, - "$ref": "#/definitions/getApiusersResponseObject" + "$ref": "#/definitions/getApiusers200ResponseObject" } } }, @@ -103,7 +103,7 @@ } }, "definitions": { - "getApiusersResponseObject": { + "getApiusers200ResponseObject": { "type": "object", "properties": { "current_page": { From ecafd32c38586bdf751ea7a694be01f822ac4b41 Mon Sep 17 00:00:00 2001 From: Konstantin Lapkovsky Date: Wed, 13 Dec 2023 19:08:31 +0400 Subject: [PATCH 4/6] style: correct code style. --- src/AutoDocServiceProvider.php | 2 +- src/Drivers/BaseDriver.php | 2 +- src/Drivers/LocalDriver.php | 2 +- src/Drivers/RemoteDriver.php | 4 +- src/Drivers/StorageDriver.php | 5 +- src/Http/Controllers/AutoDocController.php | 13 +- src/Http/Middleware/AutoDocMiddleware.php | 2 +- src/Interfaces/SwaggerDriverInterface.php | 8 +- src/Services/SwaggerService.php | 265 ++++++++++----------- src/Tests/AutoDocTestCaseTrait.php | 2 +- src/Traits/GetDependenciesTrait.php | 8 +- src/Validators/SwaggerSpecValidator.php | 7 +- 12 files changed, 153 insertions(+), 167 deletions(-) diff --git a/src/AutoDocServiceProvider.php b/src/AutoDocServiceProvider.php index ec4a276..f985f9d 100644 --- a/src/AutoDocServiceProvider.php +++ b/src/AutoDocServiceProvider.php @@ -7,7 +7,7 @@ class AutoDocServiceProvider extends ServiceProvider { - public function boot() + public function boot(): void { $this->mergeConfigFrom(__DIR__ . '/../config/auto-doc.php', 'auto-doc'); diff --git a/src/Drivers/BaseDriver.php b/src/Drivers/BaseDriver.php index ddd1879..7fd70a0 100644 --- a/src/Drivers/BaseDriver.php +++ b/src/Drivers/BaseDriver.php @@ -6,7 +6,7 @@ abstract class BaseDriver implements SwaggerDriverInterface { - protected $tempFilePath; + protected string $tempFilePath; public function __construct() { diff --git a/src/Drivers/LocalDriver.php b/src/Drivers/LocalDriver.php index c280156..128adc8 100755 --- a/src/Drivers/LocalDriver.php +++ b/src/Drivers/LocalDriver.php @@ -7,7 +7,7 @@ class LocalDriver extends BaseDriver { - protected $prodFilePath; + protected string $prodFilePath; public function __construct() { diff --git a/src/Drivers/RemoteDriver.php b/src/Drivers/RemoteDriver.php index c760546..ca92166 100755 --- a/src/Drivers/RemoteDriver.php +++ b/src/Drivers/RemoteDriver.php @@ -7,8 +7,8 @@ class RemoteDriver extends BaseDriver { - protected $key; - protected $remoteUrl; + protected string $key; + protected string $remoteUrl; public function __construct() { diff --git a/src/Drivers/StorageDriver.php b/src/Drivers/StorageDriver.php index b0b142f..0166f2f 100755 --- a/src/Drivers/StorageDriver.php +++ b/src/Drivers/StorageDriver.php @@ -3,13 +3,14 @@ namespace RonasIT\Support\AutoDoc\Drivers; use Illuminate\Contracts\Filesystem\FileNotFoundException; +use Illuminate\Contracts\Filesystem\Filesystem; use Illuminate\Support\Facades\Storage; use RonasIT\Support\AutoDoc\Exceptions\MissedProductionFilePathException; class StorageDriver extends BaseDriver { - protected $disk; - protected $prodFilePath; + protected Filesystem $disk; + protected string $prodFilePath; public function __construct() { diff --git a/src/Http/Controllers/AutoDocController.php b/src/Http/Controllers/AutoDocController.php index 6b23f48..3380787 100644 --- a/src/Http/Controllers/AutoDocController.php +++ b/src/Http/Controllers/AutoDocController.php @@ -2,15 +2,18 @@ namespace RonasIT\Support\AutoDoc\Http\Controllers; +use Illuminate\Contracts\View\View; +use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; +use Illuminate\Http\Response; use Illuminate\Routing\Controller as BaseController; use RonasIT\Support\AutoDoc\Services\SwaggerService; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; class AutoDocController extends BaseController { - protected $service; - protected $documentationViewer; + protected SwaggerService $service; + protected string $documentationViewer; public function __construct() { @@ -18,14 +21,14 @@ public function __construct() $this->documentationViewer = config('auto-doc.documentation_viewer'); } - public function documentation() + public function documentation(): JsonResponse { $documentation = $this->service->getDocFileContent(); return response()->json($documentation); } - public function index() + public function index(): View|Response { $currentEnvironment = config('app.env'); @@ -36,7 +39,7 @@ public function index() return response('Forbidden.', 403); } - public function getFile(Request $request, $file) + public function getFile(Request $request, $file): Response { $filePath = __DIR__ . "/../../../resources/assets/{$this->documentationViewer}/" . $file; diff --git a/src/Http/Middleware/AutoDocMiddleware.php b/src/Http/Middleware/AutoDocMiddleware.php index a048448..e047211 100644 --- a/src/Http/Middleware/AutoDocMiddleware.php +++ b/src/Http/Middleware/AutoDocMiddleware.php @@ -16,7 +16,7 @@ public function handle($request, Closure $next) { $response = $next($request); - if ((config('app.env') == 'testing') && !self::$skipped && !empty($request->route())) { + if ((config('app.env') === 'testing') && !self::$skipped && !empty($request->route())) { app(SwaggerService::class)->addData($request, $response); } diff --git a/src/Interfaces/SwaggerDriverInterface.php b/src/Interfaces/SwaggerDriverInterface.php index 45ba0fc..f0e1840 100644 --- a/src/Interfaces/SwaggerDriverInterface.php +++ b/src/Interfaces/SwaggerDriverInterface.php @@ -6,20 +6,18 @@ interface SwaggerDriverInterface { /** * Save temporary data - * - * @param array $data */ - public function saveTmpData($data); + public function saveTmpData(array $data): void; /** * Get temporary data */ - public function getTmpData(); + public function getTmpData(): void; /** * Save production data */ - public function saveData(); + public function saveData(): void; /** * Get production documentation diff --git a/src/Services/SwaggerService.php b/src/Services/SwaggerService.php index f295b50..c7c669a 100755 --- a/src/Services/SwaggerService.php +++ b/src/Services/SwaggerService.php @@ -31,22 +31,22 @@ class SwaggerService public const SWAGGER_VERSION = '2.0'; - protected $driver; - protected $openAPIValidator; - - protected $data; - protected $config; - protected $container; - private $uri; - private $method; /** - * @var Request + * @var SwaggerDriverInterface|mixed */ - private $request; - private $item; - private $security; - - protected $ruleToTypeMap = [ + protected $driver; + protected SwaggerSpecValidator $openAPIValidator; + + protected ?array $data; + protected array $config; + protected Container $container; + private string $uri; + private string $method; + private Request $request; + private array $item; + private string $security; + + protected array $ruleToTypeMap = [ 'array' => 'object', 'boolean' => 'boolean', 'date' => 'date', @@ -57,7 +57,7 @@ class SwaggerService 'int' => 'integer' ]; - protected $booleanAnnotations = [ + protected array $booleanAnnotations = [ 'deprecated' ]; @@ -66,10 +66,9 @@ public function __construct(Container $container) $this->openAPIValidator = app(SwaggerSpecValidator::class); $this->initConfig(); - $this->setDriver(); - if (config('app.env') == 'testing') { + if (config('app.env') === 'testing') { $this->container = $container; $this->security = $this->config['security']; @@ -84,7 +83,7 @@ public function __construct(Container $container) } } - protected function initConfig() + protected function initConfig(): void { $this->config = config('auto-doc'); @@ -107,7 +106,7 @@ protected function initConfig() } } - protected function setDriver() + protected function setDriver(): void { $driver = $this->config['driver']; $className = Arr::get($this->config, "drivers.{$driver}.class"); @@ -168,40 +167,35 @@ protected function generateSecurityDefinition(): ?array ]; } - protected function generateSecurityDefinitionObject($type): array + protected function generateSecurityDefinitionObject(string $type): array { - switch ($type) { - case 'jwt': - return [ - 'type' => 'apiKey', - 'name' => 'authorization', - 'in' => 'header' - ]; - - case 'laravel': - return [ - 'type' => 'apiKey', - 'name' => 'Cookie', - 'in' => 'header' - ]; - default: - throw new WrongSecurityConfigException(); - } + return match ($type) { + 'jwt' => [ + 'type' => 'apiKey', + 'name' => 'authorization', + 'in' => 'header' + ], + 'laravel' => [ + 'type' => 'apiKey', + 'name' => 'Cookie', + 'in' => 'header' + ], + default => throw new WrongSecurityConfigException(), + }; } - public function addData(Request $request, $response) + public function addData(Request $request, $response): void { $this->request = $request; $this->prepareItem(); - $this->parseRequest(); $this->parseResponse($response); $this->driver->saveTmpData($this->data); } - protected function prepareItem() + protected function prepareItem(): void { $this->uri = "/{$this->getUri()}"; $this->method = strtolower($this->request->getMethod()); @@ -221,7 +215,7 @@ protected function prepareItem() $this->item = &$this->data['paths'][$this->uri][$this->method]; } - protected function getUri() + protected function getUri(): string { $uri = $this->request->route()->uri(); $basePath = preg_replace("/^\//", '', $this->config['basePath']); @@ -255,7 +249,7 @@ protected function getPathParams(): array return $result; } - protected function parseRequest() + protected function parseRequest(): void { $this->saveConsume(); $this->saveTags(); @@ -276,62 +270,68 @@ protected function parseRequest() $this->saveDescription($concreteRequest, $annotations); } - protected function markAsDeprecated(array $annotations) + protected function markAsDeprecated(array $annotations): void { $this->item['deprecated'] = Arr::get($annotations, 'deprecated', false); } - protected function saveResponseSchema(?array $content, int $code) + protected function saveResponseSchema(?array $content, string $definition): void { if (empty($content)) { return; } $schemaProperties = []; - $action = Str::ucfirst($this->getActionName($this->uri)); $schemaType = 'object'; if (array_is_list($content)) { - $schemaType = 'array'; - $types = []; + $this->saveListResponseDefinition($content, $schemaProperties); - foreach ($content as $value) { - $type = gettype($value); - if (!in_array($type, $types)) { - $types[] = $type; - $schemaProperties['items']['allOf'][]['type'] = $type; - } - } + $schemaType = 'array'; } else { - $properties = Arr::get( - $this->data['definitions'], - "{$this->method}{$action}{$code}ResponseObject.properties", - [] - ); + $this->saveObjectResponseDefinitions($definition, $content, $schemaProperties); + } - foreach ($content as $name => $value) { - $property = Arr::get($properties, $name, []); + $this->data['definitions'][$definition] = [ + 'type' => $schemaType, + 'properties' => $schemaProperties + ]; + } - if (is_null($value)) { - $property['nullable'] = true; - } else { - $property['type'] = gettype($value); - } + protected function saveObjectResponseDefinitions(string $definition, array $content, array &$schemaProperties): void + { + $properties = Arr::get($this->data['definitions'], "{$definition}.properties", []); - $schemaProperties[$name] = $property; + foreach ($content as $name => $value) { + $property = Arr::get($properties, $name, []); + + if (is_null($value)) { + $property['nullable'] = true; + } else { + $property['type'] = gettype($value); } + + $schemaProperties[$name] = $property; } + } - $this->data['definitions']["{$this->method}{$action}{$code}ResponseObject"] = [ - 'type' => $schemaType, - 'properties' => $schemaProperties - ]; + protected function saveListResponseDefinition(array $content, array &$schemaProperties): void + { + $types = []; + + foreach ($content as $value) { + $type = gettype($value); + + if (!in_array($type, $types)) { + $types[] = $type; + $schemaProperties['items']['allOf'][]['type'] = $type; + } + } } - protected function parseResponse($response) + protected function parseResponse($response): void { $produceList = $this->data['paths'][$this->uri][$this->method]['produces']; - $produce = $response->headers->get('Content-type'); if (is_null($produce)) { @@ -343,23 +343,18 @@ protected function parseResponse($response) } $responses = $this->item['responses']; - $responseExampleLimitCount = config('auto-doc.response_example_limit_count'); - $content = json_decode($response->getContent(), true); - if (!empty($responseExampleLimitCount)) { - if (!empty($content['data'])) { - $limitedResponseData = array_slice($content['data'], 0, $responseExampleLimitCount, true); - $content['data'] = $limitedResponseData; - $content['to'] = count($limitedResponseData); - $content['total'] = count($limitedResponseData); - } + if (!empty($responseExampleLimitCount) && !empty($content['data'])) { + $limitedResponseData = array_slice($content['data'], 0, $responseExampleLimitCount, true); + $content['data'] = $limitedResponseData; + $content['to'] = count($limitedResponseData); + $content['total'] = count($limitedResponseData); } if (!empty($content['exception'])) { $uselessKeys = array_keys(Arr::except($content, ['message'])); - $content = Arr::except($content, $uselessKeys); } @@ -373,25 +368,25 @@ protected function parseResponse($response) ); } - $this->saveResponseSchema($content, $code); + $action = Str::ucfirst($this->getActionName($this->uri)); + $definition = "#/definitions/{$this->method}{$action}{$code}ResponseObject"; - if (is_array($this->item['responses'][$code])) { - $action = Str::ucfirst($this->getActionName($this->uri)); - $definition = "#/definitions/{$this->method}{$action}{$code}ResponseObject"; + $this->saveResponseSchema($content, $definition); + if (is_array($this->item['responses'][$code])) { $this->item['responses'][$code]['schema']['$ref'] = $definition; } } - protected function saveExample($code, $content, $produce) + protected function saveExample(int $code, string $content, string $produce): void { $description = $this->getResponseDescription($code); + $explodedContentType = explode('/', $produce); $availableContentTypes = [ 'application', 'text', 'image', ]; - $explodedContentType = explode('/', $produce); if (in_array($explodedContentType[0], $availableContentTypes)) { $this->item['responses'][$code] = $this->makeResponseExample($content, $produce, $description); @@ -400,7 +395,7 @@ protected function saveExample($code, $content, $produce) } } - protected function makeResponseExample($content, $mimeType, $description = ''): array + protected function makeResponseExample(string $content, string $mimeType, string $description = ''): array { $responseExample = ['description' => $description]; @@ -415,14 +410,13 @@ protected function makeResponseExample($content, $mimeType, $description = ''): return $responseExample; } - protected function saveParameters($request, array $annotations) + protected function saveParameters($request, array $annotations): void { $formRequest = new $request(); $formRequest->setUserResolver($this->request->getUserResolver()); $formRequest->setRouteResolver($this->request->getRouteResolver()); $rules = method_exists($formRequest, 'rules') ? $this->prepareRules($formRequest->rules()) : []; $attributes = method_exists($formRequest, 'attributes') ? $formRequest->attributes() : []; - $actionName = $this->getActionName($this->uri); if (in_array($this->method, ['get', 'delete'])) { @@ -451,7 +445,7 @@ protected function prepareRules(array $rules): array return $preparedRules; } - protected function getRuleAsString($rule): string + protected function getRuleAsString(object|string $rule): string { if (is_object($rule)) { if (method_exists($rule, '__toString')) { @@ -459,7 +453,6 @@ protected function getRuleAsString($rule): string } $shortName = Str::afterLast(get_class($rule), '\\'); - $ruleName = preg_replace('/Rule$/', '', $shortName); return Str::snake($ruleName); @@ -468,11 +461,10 @@ protected function getRuleAsString($rule): string return $rule; } - protected function saveGetRequestParameters($rules, array $attributes, array $annotations) + protected function saveGetRequestParameters(array $rules, array $attributes, array $annotations): void { foreach ($rules as $parameter => $rule) { $validation = explode('|', $rule); - $description = Arr::get($annotations, $parameter); if (empty($description)) { @@ -480,7 +472,7 @@ protected function saveGetRequestParameters($rules, array $attributes, array $an } $existedParameter = Arr::first($this->item['parameters'], function ($existedParameter) use ($parameter) { - return $existedParameter['name'] == $parameter; + return $existedParameter['name'] === $parameter; }); if (empty($existedParameter)) { @@ -490,6 +482,7 @@ protected function saveGetRequestParameters($rules, array $attributes, array $an 'description' => $description, 'type' => $this->getParameterType($validation) ]; + if (in_array('required', $validation)) { $parameterDefinition['required'] = true; } @@ -499,7 +492,12 @@ protected function saveGetRequestParameters($rules, array $attributes, array $an } } - protected function savePostRequestParameters($actionName, $rules, array $attributes, array $annotations) + protected function savePostRequestParameters( + string $actionName, + array $rules, + array $attributes, + array $annotations + ): void { if ($this->requestHasMoreProperties($actionName)) { if ($this->requestHasBody()) { @@ -518,7 +516,7 @@ protected function savePostRequestParameters($actionName, $rules, array $attribu } } - protected function saveDefinitions($objectName, $rules, $attributes, array $annotations) + protected function saveDefinitions(string $objectName, array $rules, array $attributes, array $annotations): void { $data = [ 'type' => 'object', @@ -550,7 +548,6 @@ protected function getParameterType(array $validation): string { $validationRules = $this->ruleToTypeMap; $validationRules['email'] = 'string'; - $parameterType = 'string'; foreach ($validation as $item) { @@ -562,14 +559,20 @@ protected function getParameterType(array $validation): string return $parameterType; } - protected function saveParameterType(&$data, $parameter, $parameterType) + protected function saveParameterType(array &$data, string $parameter, string $parameterType): void { $data['properties'][$parameter] = [ 'type' => $parameterType ]; } - protected function saveParameterDescription(&$data, $parameter, array $rulesArray, array $attributes, array $annotations) + protected function saveParameterDescription( + array &$data, + string $parameter, + array $rulesArray, + array $attributes, + array $annotations + ): void { $description = Arr::get($annotations, $parameter); @@ -580,7 +583,7 @@ protected function saveParameterDescription(&$data, $parameter, array $rulesArra $data['properties'][$parameter]['description'] = $description; } - protected function requestHasMoreProperties($actionName): bool + protected function requestHasMoreProperties(string $actionName): bool { $requestParametersCount = count($this->request->all()); @@ -598,28 +601,25 @@ protected function requestHasBody(): bool $parameters = $this->data['paths'][$this->uri][$this->method]['parameters']; $bodyParamExisted = Arr::where($parameters, function ($value) { - return $value['name'] == 'body'; + return $value['name'] === 'body'; }); return empty($bodyParamExisted); } - public function getConcreteRequest() + public function getConcreteRequest(): mixed { $controller = $this->request->route()->getActionName(); - if ($controller == 'Closure') { + if ($controller === 'Closure') { return null; } $explodedController = explode('@', $controller); - $class = $explodedController[0]; $method = $explodedController[1]; - $instance = app($class); $route = $this->request->route(); - $parameters = $this->resolveClassMethodDependencies( $route->parametersWithoutNulls(), $instance, @@ -631,7 +631,7 @@ public function getConcreteRequest() }); } - public function saveConsume() + public function saveConsume(): void { $consumeList = $this->data['paths'][$this->uri][$this->method]['consumes']; $consume = $this->request->header('Content-Type'); @@ -641,18 +641,16 @@ public function saveConsume() } } - public function saveTags() + public function saveTags(): void { $tagIndex = 1; - $explodedUri = explode('/', $this->uri); - $tag = Arr::get($explodedUri, $tagIndex); $this->item['tags'] = [$tag]; } - public function saveDescription($request, array $annotations) + public function saveDescription($request, array $annotations): void { $this->item['summary'] = $this->getSummary($request, $annotations); @@ -663,14 +661,14 @@ public function saveDescription($request, array $annotations) } } - protected function saveSecurity() + protected function saveSecurity(): void { if ($this->requestSupportAuth()) { $this->addSecurityToOperation(); } } - protected function addSecurityToOperation() + protected function addSecurityToOperation(): void { $security = &$this->data['paths'][$this->uri][$this->method]['security']; @@ -681,7 +679,7 @@ protected function addSecurityToOperation() } } - protected function getSummary($request, array $annotations) + protected function getSummary($request, array $annotations): ?string { $summary = Arr::get($annotations, 'summary'); @@ -706,21 +704,19 @@ protected function requestSupportAuth(): bool return !empty($header); } - protected function parseRequestName($request) + protected function parseRequestName($request): string { $explodedRequest = explode('\\', $request); $requestName = array_pop($explodedRequest); $summaryName = str_replace('Request', '', $requestName); - $underscoreRequestName = $this->camelCaseToUnderScore($summaryName); return preg_replace('/[_]/', ' ', $underscoreRequestName); } - protected function getResponseDescription($code) + protected function getResponseDescription(int $code): string { $defaultDescription = Response::$statusTexts[$code]; - $request = $this->getConcreteRequest(); if (empty($request)) { @@ -728,7 +724,6 @@ protected function getResponseDescription($code) } $annotations = $this->getClassAnnotations($request); - $localDescription = Arr::get($annotations, "_{$code}"); if (!empty($localDescription)) { @@ -738,7 +733,7 @@ protected function getResponseDescription($code) return Arr::get($this->config, "defaults.code-descriptions.{$code}", $defaultDescription); } - protected function getActionName($uri): string + protected function getActionName(string $uri): string { $action = preg_replace('[\/]', '', $uri); @@ -749,7 +744,7 @@ protected function getActionName($uri): string * @deprecated method is not in use * @codeCoverageIgnore */ - protected function saveTempData() + protected function saveTempData(): void { $exportFile = Arr::get($this->config, 'files.temporary'); $data = json_encode($this->data); @@ -757,12 +752,12 @@ protected function saveTempData() file_put_contents($exportFile, $data); } - public function saveProductionData() + public function saveProductionData(): void { $this->driver->saveData(); } - public function getDocFileContent() + public function getDocFileContent(): array { $documentation = $this->driver->getDocumentation(); @@ -791,7 +786,7 @@ protected function camelCaseToUnderScore($input): string $ret = $matches[0]; foreach ($ret as &$match) { - $match = $match == strtoupper($match) ? strtolower($match) : lcfirst($match); + $match = ($match === strtoupper($match)) ? strtolower($match) : lcfirst($match); } return implode('_', $ret); @@ -807,19 +802,17 @@ protected function generateExample($properties): array return $example; } - protected function replaceObjectValues($parameters): array + protected function replaceObjectValues(array $parameters): array { + $parameters = Arr::dot($parameters); + $returnParameters = []; $classNamesValues = [ File::class => '[uploaded_file]', ]; - $parameters = Arr::dot($parameters); - $returnParameters = []; - foreach ($parameters as $parameter => $value) { if (is_object($value)) { $class = get_class($value); - $value = Arr::get($classNamesValues, $class, $class); } @@ -832,11 +825,8 @@ protected function replaceObjectValues($parameters): array protected function getClassAnnotations($class): array { $reflection = new ReflectionClass($class); - $annotations = $reflection->getDocComment(); - $blocks = explode("\n", $annotations); - $result = []; foreach ($blocks as $block) { @@ -844,7 +834,6 @@ protected function getClassAnnotations($class): array $index = strpos($block, '@'); $block = substr($block, $index); $exploded = explode(' ', $block); - $paramName = str_replace('@', '', array_shift($exploded)); $paramValue = implode(' ', $exploded); @@ -864,7 +853,7 @@ protected function getClassAnnotations($class): array * this issue: https://github.com/OAI/OpenAPI-Specification/issues/229 * We hope swagger developers will resolve this problem in next release of Swagger OpenAPI * */ - protected function replaceNullValues($parameters, $types, &$example) + protected function replaceNullValues(array $parameters, array $types, array &$example): void { foreach ($parameters as $parameter => $value) { if (is_null($value) && array_key_exists($parameter, $types)) { @@ -877,7 +866,7 @@ protected function replaceNullValues($parameters, $types, &$example) } } - protected function getDefaultValueByType($type) + protected function getDefaultValueByType(string $type): mixed { $values = [ 'object' => 'null', diff --git a/src/Tests/AutoDocTestCaseTrait.php b/src/Tests/AutoDocTestCaseTrait.php index 77d3e6b..317d807 100644 --- a/src/Tests/AutoDocTestCaseTrait.php +++ b/src/Tests/AutoDocTestCaseTrait.php @@ -9,7 +9,7 @@ trait AutoDocTestCaseTrait /** * Disabling documentation collecting on current test */ - public function skipDocumentationCollecting() + public function skipDocumentationCollecting(): void { AutoDocMiddleware::$skipped = true; } diff --git a/src/Traits/GetDependenciesTrait.php b/src/Traits/GetDependenciesTrait.php index 8a04978..884c4c6 100644 --- a/src/Traits/GetDependenciesTrait.php +++ b/src/Traits/GetDependenciesTrait.php @@ -11,7 +11,7 @@ trait GetDependenciesTrait { - protected function resolveClassMethodDependencies(array $parameters, $instance, $method) + protected function resolveClassMethodDependencies(array $parameters, object $instance, string $method): array { if (!method_exists($instance, $method)) { return $parameters; @@ -22,14 +22,14 @@ protected function resolveClassMethodDependencies(array $parameters, $instance, ); } - public function getDependencies(ReflectionFunctionAbstract $reflector) + public function getDependencies(ReflectionFunctionAbstract $reflector): array { return array_map(function ($parameter) { return $this->transformDependency($parameter); }, $reflector->getParameters()); } - protected function transformDependency(ReflectionParameter $parameter) + protected function transformDependency(ReflectionParameter $parameter): ?string { $class = $parameter->getClass(); @@ -40,7 +40,7 @@ protected function transformDependency(ReflectionParameter $parameter) return interface_exists($class->name) ? $this->getClassByInterface($class->name) : $class->name; } - protected function getClassByInterface($interfaceName) + protected function getClassByInterface(string $interfaceName): ?string { $bindings = Container::getInstance()->getBindings(); diff --git a/src/Validators/SwaggerSpecValidator.php b/src/Validators/SwaggerSpecValidator.php index 968a419..f1e2210 100644 --- a/src/Validators/SwaggerSpecValidator.php +++ b/src/Validators/SwaggerSpecValidator.php @@ -20,9 +20,6 @@ use RonasIT\Support\AutoDoc\Exceptions\SpecValidation\MissingRefFileException; use RonasIT\Support\AutoDoc\Services\SwaggerService; -/** - * @property array $doc - */ class SwaggerSpecValidator { public const SCHEMA_TYPES = [ @@ -77,7 +74,7 @@ class SwaggerSpecValidator public const MIME_TYPE_MULTIPART_FORM_DATA = 'multipart/form-data'; public const MIME_TYPE_APPLICATION_URLENCODED = 'application/x-www-form-urlencoded'; - protected $doc; + protected array $doc; public function validate(array $doc): void { @@ -125,7 +122,6 @@ protected function validatePaths(): void $this->validateFieldsPresent(self::REQUIRED_FIELDS['operation'], $operationId); $this->validateFieldValue("{$operationId}.schemes", self::ALLOWED_VALUES['schemes']); - $this->validateParameters($operation, $path, $operationId); foreach ($operation['responses'] as $statusCode => $response) { @@ -154,7 +150,6 @@ protected function validateSecurityDefinitions(): void $parentId = "securityDefinitions.{$index}"; $this->validateFieldsPresent(self::REQUIRED_FIELDS['security_definition'], $parentId); - $this->validateFieldValue("{$parentId}.type", self::ALLOWED_VALUES['security_definition_type']); $this->validateFieldValue("{$parentId}.in", self::ALLOWED_VALUES['security_definition_in']); $this->validateFieldValue("{$parentId}.flow", self::ALLOWED_VALUES['security_definition_flow']); From 1d84a44a65c9693e3204536119de8ff5ab0433ab Mon Sep 17 00:00:00 2001 From: Konstantin Lapkovsky Date: Wed, 13 Dec 2023 19:21:20 +0400 Subject: [PATCH 5/6] Revert "style: correct code style." This reverts commit ecafd32c38586bdf751ea7a694be01f822ac4b41. --- src/AutoDocServiceProvider.php | 2 +- src/Drivers/BaseDriver.php | 2 +- src/Drivers/LocalDriver.php | 2 +- src/Drivers/RemoteDriver.php | 4 +- src/Drivers/StorageDriver.php | 5 +- src/Http/Controllers/AutoDocController.php | 13 +- src/Http/Middleware/AutoDocMiddleware.php | 2 +- src/Interfaces/SwaggerDriverInterface.php | 8 +- src/Services/SwaggerService.php | 265 +++++++++++---------- src/Tests/AutoDocTestCaseTrait.php | 2 +- src/Traits/GetDependenciesTrait.php | 8 +- src/Validators/SwaggerSpecValidator.php | 7 +- 12 files changed, 167 insertions(+), 153 deletions(-) diff --git a/src/AutoDocServiceProvider.php b/src/AutoDocServiceProvider.php index f985f9d..ec4a276 100644 --- a/src/AutoDocServiceProvider.php +++ b/src/AutoDocServiceProvider.php @@ -7,7 +7,7 @@ class AutoDocServiceProvider extends ServiceProvider { - public function boot(): void + public function boot() { $this->mergeConfigFrom(__DIR__ . '/../config/auto-doc.php', 'auto-doc'); diff --git a/src/Drivers/BaseDriver.php b/src/Drivers/BaseDriver.php index 7fd70a0..ddd1879 100644 --- a/src/Drivers/BaseDriver.php +++ b/src/Drivers/BaseDriver.php @@ -6,7 +6,7 @@ abstract class BaseDriver implements SwaggerDriverInterface { - protected string $tempFilePath; + protected $tempFilePath; public function __construct() { diff --git a/src/Drivers/LocalDriver.php b/src/Drivers/LocalDriver.php index 128adc8..c280156 100755 --- a/src/Drivers/LocalDriver.php +++ b/src/Drivers/LocalDriver.php @@ -7,7 +7,7 @@ class LocalDriver extends BaseDriver { - protected string $prodFilePath; + protected $prodFilePath; public function __construct() { diff --git a/src/Drivers/RemoteDriver.php b/src/Drivers/RemoteDriver.php index ca92166..c760546 100755 --- a/src/Drivers/RemoteDriver.php +++ b/src/Drivers/RemoteDriver.php @@ -7,8 +7,8 @@ class RemoteDriver extends BaseDriver { - protected string $key; - protected string $remoteUrl; + protected $key; + protected $remoteUrl; public function __construct() { diff --git a/src/Drivers/StorageDriver.php b/src/Drivers/StorageDriver.php index 0166f2f..b0b142f 100755 --- a/src/Drivers/StorageDriver.php +++ b/src/Drivers/StorageDriver.php @@ -3,14 +3,13 @@ namespace RonasIT\Support\AutoDoc\Drivers; use Illuminate\Contracts\Filesystem\FileNotFoundException; -use Illuminate\Contracts\Filesystem\Filesystem; use Illuminate\Support\Facades\Storage; use RonasIT\Support\AutoDoc\Exceptions\MissedProductionFilePathException; class StorageDriver extends BaseDriver { - protected Filesystem $disk; - protected string $prodFilePath; + protected $disk; + protected $prodFilePath; public function __construct() { diff --git a/src/Http/Controllers/AutoDocController.php b/src/Http/Controllers/AutoDocController.php index 3380787..6b23f48 100644 --- a/src/Http/Controllers/AutoDocController.php +++ b/src/Http/Controllers/AutoDocController.php @@ -2,18 +2,15 @@ namespace RonasIT\Support\AutoDoc\Http\Controllers; -use Illuminate\Contracts\View\View; -use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; -use Illuminate\Http\Response; use Illuminate\Routing\Controller as BaseController; use RonasIT\Support\AutoDoc\Services\SwaggerService; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; class AutoDocController extends BaseController { - protected SwaggerService $service; - protected string $documentationViewer; + protected $service; + protected $documentationViewer; public function __construct() { @@ -21,14 +18,14 @@ public function __construct() $this->documentationViewer = config('auto-doc.documentation_viewer'); } - public function documentation(): JsonResponse + public function documentation() { $documentation = $this->service->getDocFileContent(); return response()->json($documentation); } - public function index(): View|Response + public function index() { $currentEnvironment = config('app.env'); @@ -39,7 +36,7 @@ public function index(): View|Response return response('Forbidden.', 403); } - public function getFile(Request $request, $file): Response + public function getFile(Request $request, $file) { $filePath = __DIR__ . "/../../../resources/assets/{$this->documentationViewer}/" . $file; diff --git a/src/Http/Middleware/AutoDocMiddleware.php b/src/Http/Middleware/AutoDocMiddleware.php index e047211..a048448 100644 --- a/src/Http/Middleware/AutoDocMiddleware.php +++ b/src/Http/Middleware/AutoDocMiddleware.php @@ -16,7 +16,7 @@ public function handle($request, Closure $next) { $response = $next($request); - if ((config('app.env') === 'testing') && !self::$skipped && !empty($request->route())) { + if ((config('app.env') == 'testing') && !self::$skipped && !empty($request->route())) { app(SwaggerService::class)->addData($request, $response); } diff --git a/src/Interfaces/SwaggerDriverInterface.php b/src/Interfaces/SwaggerDriverInterface.php index f0e1840..45ba0fc 100644 --- a/src/Interfaces/SwaggerDriverInterface.php +++ b/src/Interfaces/SwaggerDriverInterface.php @@ -6,18 +6,20 @@ interface SwaggerDriverInterface { /** * Save temporary data + * + * @param array $data */ - public function saveTmpData(array $data): void; + public function saveTmpData($data); /** * Get temporary data */ - public function getTmpData(): void; + public function getTmpData(); /** * Save production data */ - public function saveData(): void; + public function saveData(); /** * Get production documentation diff --git a/src/Services/SwaggerService.php b/src/Services/SwaggerService.php index c7c669a..f295b50 100755 --- a/src/Services/SwaggerService.php +++ b/src/Services/SwaggerService.php @@ -31,22 +31,22 @@ class SwaggerService public const SWAGGER_VERSION = '2.0'; + protected $driver; + protected $openAPIValidator; + + protected $data; + protected $config; + protected $container; + private $uri; + private $method; /** - * @var SwaggerDriverInterface|mixed + * @var Request */ - protected $driver; - protected SwaggerSpecValidator $openAPIValidator; - - protected ?array $data; - protected array $config; - protected Container $container; - private string $uri; - private string $method; - private Request $request; - private array $item; - private string $security; - - protected array $ruleToTypeMap = [ + private $request; + private $item; + private $security; + + protected $ruleToTypeMap = [ 'array' => 'object', 'boolean' => 'boolean', 'date' => 'date', @@ -57,7 +57,7 @@ class SwaggerService 'int' => 'integer' ]; - protected array $booleanAnnotations = [ + protected $booleanAnnotations = [ 'deprecated' ]; @@ -66,9 +66,10 @@ public function __construct(Container $container) $this->openAPIValidator = app(SwaggerSpecValidator::class); $this->initConfig(); + $this->setDriver(); - if (config('app.env') === 'testing') { + if (config('app.env') == 'testing') { $this->container = $container; $this->security = $this->config['security']; @@ -83,7 +84,7 @@ public function __construct(Container $container) } } - protected function initConfig(): void + protected function initConfig() { $this->config = config('auto-doc'); @@ -106,7 +107,7 @@ protected function initConfig(): void } } - protected function setDriver(): void + protected function setDriver() { $driver = $this->config['driver']; $className = Arr::get($this->config, "drivers.{$driver}.class"); @@ -167,35 +168,40 @@ protected function generateSecurityDefinition(): ?array ]; } - protected function generateSecurityDefinitionObject(string $type): array + protected function generateSecurityDefinitionObject($type): array { - return match ($type) { - 'jwt' => [ - 'type' => 'apiKey', - 'name' => 'authorization', - 'in' => 'header' - ], - 'laravel' => [ - 'type' => 'apiKey', - 'name' => 'Cookie', - 'in' => 'header' - ], - default => throw new WrongSecurityConfigException(), - }; + switch ($type) { + case 'jwt': + return [ + 'type' => 'apiKey', + 'name' => 'authorization', + 'in' => 'header' + ]; + + case 'laravel': + return [ + 'type' => 'apiKey', + 'name' => 'Cookie', + 'in' => 'header' + ]; + default: + throw new WrongSecurityConfigException(); + } } - public function addData(Request $request, $response): void + public function addData(Request $request, $response) { $this->request = $request; $this->prepareItem(); + $this->parseRequest(); $this->parseResponse($response); $this->driver->saveTmpData($this->data); } - protected function prepareItem(): void + protected function prepareItem() { $this->uri = "/{$this->getUri()}"; $this->method = strtolower($this->request->getMethod()); @@ -215,7 +221,7 @@ protected function prepareItem(): void $this->item = &$this->data['paths'][$this->uri][$this->method]; } - protected function getUri(): string + protected function getUri() { $uri = $this->request->route()->uri(); $basePath = preg_replace("/^\//", '', $this->config['basePath']); @@ -249,7 +255,7 @@ protected function getPathParams(): array return $result; } - protected function parseRequest(): void + protected function parseRequest() { $this->saveConsume(); $this->saveTags(); @@ -270,68 +276,62 @@ protected function parseRequest(): void $this->saveDescription($concreteRequest, $annotations); } - protected function markAsDeprecated(array $annotations): void + protected function markAsDeprecated(array $annotations) { $this->item['deprecated'] = Arr::get($annotations, 'deprecated', false); } - protected function saveResponseSchema(?array $content, string $definition): void + protected function saveResponseSchema(?array $content, int $code) { if (empty($content)) { return; } $schemaProperties = []; + $action = Str::ucfirst($this->getActionName($this->uri)); $schemaType = 'object'; if (array_is_list($content)) { - $this->saveListResponseDefinition($content, $schemaProperties); - $schemaType = 'array'; - } else { - $this->saveObjectResponseDefinitions($definition, $content, $schemaProperties); - } + $types = []; - $this->data['definitions'][$definition] = [ - 'type' => $schemaType, - 'properties' => $schemaProperties - ]; - } - - protected function saveObjectResponseDefinitions(string $definition, array $content, array &$schemaProperties): void - { - $properties = Arr::get($this->data['definitions'], "{$definition}.properties", []); - - foreach ($content as $name => $value) { - $property = Arr::get($properties, $name, []); - - if (is_null($value)) { - $property['nullable'] = true; - } else { - $property['type'] = gettype($value); + foreach ($content as $value) { + $type = gettype($value); + if (!in_array($type, $types)) { + $types[] = $type; + $schemaProperties['items']['allOf'][]['type'] = $type; + } } + } else { + $properties = Arr::get( + $this->data['definitions'], + "{$this->method}{$action}{$code}ResponseObject.properties", + [] + ); - $schemaProperties[$name] = $property; - } - } - - protected function saveListResponseDefinition(array $content, array &$schemaProperties): void - { - $types = []; + foreach ($content as $name => $value) { + $property = Arr::get($properties, $name, []); - foreach ($content as $value) { - $type = gettype($value); + if (is_null($value)) { + $property['nullable'] = true; + } else { + $property['type'] = gettype($value); + } - if (!in_array($type, $types)) { - $types[] = $type; - $schemaProperties['items']['allOf'][]['type'] = $type; + $schemaProperties[$name] = $property; } } + + $this->data['definitions']["{$this->method}{$action}{$code}ResponseObject"] = [ + 'type' => $schemaType, + 'properties' => $schemaProperties + ]; } - protected function parseResponse($response): void + protected function parseResponse($response) { $produceList = $this->data['paths'][$this->uri][$this->method]['produces']; + $produce = $response->headers->get('Content-type'); if (is_null($produce)) { @@ -343,18 +343,23 @@ protected function parseResponse($response): void } $responses = $this->item['responses']; + $responseExampleLimitCount = config('auto-doc.response_example_limit_count'); + $content = json_decode($response->getContent(), true); - if (!empty($responseExampleLimitCount) && !empty($content['data'])) { - $limitedResponseData = array_slice($content['data'], 0, $responseExampleLimitCount, true); - $content['data'] = $limitedResponseData; - $content['to'] = count($limitedResponseData); - $content['total'] = count($limitedResponseData); + if (!empty($responseExampleLimitCount)) { + if (!empty($content['data'])) { + $limitedResponseData = array_slice($content['data'], 0, $responseExampleLimitCount, true); + $content['data'] = $limitedResponseData; + $content['to'] = count($limitedResponseData); + $content['total'] = count($limitedResponseData); + } } if (!empty($content['exception'])) { $uselessKeys = array_keys(Arr::except($content, ['message'])); + $content = Arr::except($content, $uselessKeys); } @@ -368,25 +373,25 @@ protected function parseResponse($response): void ); } - $action = Str::ucfirst($this->getActionName($this->uri)); - $definition = "#/definitions/{$this->method}{$action}{$code}ResponseObject"; - - $this->saveResponseSchema($content, $definition); + $this->saveResponseSchema($content, $code); if (is_array($this->item['responses'][$code])) { + $action = Str::ucfirst($this->getActionName($this->uri)); + $definition = "#/definitions/{$this->method}{$action}{$code}ResponseObject"; + $this->item['responses'][$code]['schema']['$ref'] = $definition; } } - protected function saveExample(int $code, string $content, string $produce): void + protected function saveExample($code, $content, $produce) { $description = $this->getResponseDescription($code); - $explodedContentType = explode('/', $produce); $availableContentTypes = [ 'application', 'text', 'image', ]; + $explodedContentType = explode('/', $produce); if (in_array($explodedContentType[0], $availableContentTypes)) { $this->item['responses'][$code] = $this->makeResponseExample($content, $produce, $description); @@ -395,7 +400,7 @@ protected function saveExample(int $code, string $content, string $produce): voi } } - protected function makeResponseExample(string $content, string $mimeType, string $description = ''): array + protected function makeResponseExample($content, $mimeType, $description = ''): array { $responseExample = ['description' => $description]; @@ -410,13 +415,14 @@ protected function makeResponseExample(string $content, string $mimeType, string return $responseExample; } - protected function saveParameters($request, array $annotations): void + protected function saveParameters($request, array $annotations) { $formRequest = new $request(); $formRequest->setUserResolver($this->request->getUserResolver()); $formRequest->setRouteResolver($this->request->getRouteResolver()); $rules = method_exists($formRequest, 'rules') ? $this->prepareRules($formRequest->rules()) : []; $attributes = method_exists($formRequest, 'attributes') ? $formRequest->attributes() : []; + $actionName = $this->getActionName($this->uri); if (in_array($this->method, ['get', 'delete'])) { @@ -445,7 +451,7 @@ protected function prepareRules(array $rules): array return $preparedRules; } - protected function getRuleAsString(object|string $rule): string + protected function getRuleAsString($rule): string { if (is_object($rule)) { if (method_exists($rule, '__toString')) { @@ -453,6 +459,7 @@ protected function getRuleAsString(object|string $rule): string } $shortName = Str::afterLast(get_class($rule), '\\'); + $ruleName = preg_replace('/Rule$/', '', $shortName); return Str::snake($ruleName); @@ -461,10 +468,11 @@ protected function getRuleAsString(object|string $rule): string return $rule; } - protected function saveGetRequestParameters(array $rules, array $attributes, array $annotations): void + protected function saveGetRequestParameters($rules, array $attributes, array $annotations) { foreach ($rules as $parameter => $rule) { $validation = explode('|', $rule); + $description = Arr::get($annotations, $parameter); if (empty($description)) { @@ -472,7 +480,7 @@ protected function saveGetRequestParameters(array $rules, array $attributes, arr } $existedParameter = Arr::first($this->item['parameters'], function ($existedParameter) use ($parameter) { - return $existedParameter['name'] === $parameter; + return $existedParameter['name'] == $parameter; }); if (empty($existedParameter)) { @@ -482,7 +490,6 @@ protected function saveGetRequestParameters(array $rules, array $attributes, arr 'description' => $description, 'type' => $this->getParameterType($validation) ]; - if (in_array('required', $validation)) { $parameterDefinition['required'] = true; } @@ -492,12 +499,7 @@ protected function saveGetRequestParameters(array $rules, array $attributes, arr } } - protected function savePostRequestParameters( - string $actionName, - array $rules, - array $attributes, - array $annotations - ): void + protected function savePostRequestParameters($actionName, $rules, array $attributes, array $annotations) { if ($this->requestHasMoreProperties($actionName)) { if ($this->requestHasBody()) { @@ -516,7 +518,7 @@ protected function savePostRequestParameters( } } - protected function saveDefinitions(string $objectName, array $rules, array $attributes, array $annotations): void + protected function saveDefinitions($objectName, $rules, $attributes, array $annotations) { $data = [ 'type' => 'object', @@ -548,6 +550,7 @@ protected function getParameterType(array $validation): string { $validationRules = $this->ruleToTypeMap; $validationRules['email'] = 'string'; + $parameterType = 'string'; foreach ($validation as $item) { @@ -559,20 +562,14 @@ protected function getParameterType(array $validation): string return $parameterType; } - protected function saveParameterType(array &$data, string $parameter, string $parameterType): void + protected function saveParameterType(&$data, $parameter, $parameterType) { $data['properties'][$parameter] = [ 'type' => $parameterType ]; } - protected function saveParameterDescription( - array &$data, - string $parameter, - array $rulesArray, - array $attributes, - array $annotations - ): void + protected function saveParameterDescription(&$data, $parameter, array $rulesArray, array $attributes, array $annotations) { $description = Arr::get($annotations, $parameter); @@ -583,7 +580,7 @@ protected function saveParameterDescription( $data['properties'][$parameter]['description'] = $description; } - protected function requestHasMoreProperties(string $actionName): bool + protected function requestHasMoreProperties($actionName): bool { $requestParametersCount = count($this->request->all()); @@ -601,25 +598,28 @@ protected function requestHasBody(): bool $parameters = $this->data['paths'][$this->uri][$this->method]['parameters']; $bodyParamExisted = Arr::where($parameters, function ($value) { - return $value['name'] === 'body'; + return $value['name'] == 'body'; }); return empty($bodyParamExisted); } - public function getConcreteRequest(): mixed + public function getConcreteRequest() { $controller = $this->request->route()->getActionName(); - if ($controller === 'Closure') { + if ($controller == 'Closure') { return null; } $explodedController = explode('@', $controller); + $class = $explodedController[0]; $method = $explodedController[1]; + $instance = app($class); $route = $this->request->route(); + $parameters = $this->resolveClassMethodDependencies( $route->parametersWithoutNulls(), $instance, @@ -631,7 +631,7 @@ public function getConcreteRequest(): mixed }); } - public function saveConsume(): void + public function saveConsume() { $consumeList = $this->data['paths'][$this->uri][$this->method]['consumes']; $consume = $this->request->header('Content-Type'); @@ -641,16 +641,18 @@ public function saveConsume(): void } } - public function saveTags(): void + public function saveTags() { $tagIndex = 1; + $explodedUri = explode('/', $this->uri); + $tag = Arr::get($explodedUri, $tagIndex); $this->item['tags'] = [$tag]; } - public function saveDescription($request, array $annotations): void + public function saveDescription($request, array $annotations) { $this->item['summary'] = $this->getSummary($request, $annotations); @@ -661,14 +663,14 @@ public function saveDescription($request, array $annotations): void } } - protected function saveSecurity(): void + protected function saveSecurity() { if ($this->requestSupportAuth()) { $this->addSecurityToOperation(); } } - protected function addSecurityToOperation(): void + protected function addSecurityToOperation() { $security = &$this->data['paths'][$this->uri][$this->method]['security']; @@ -679,7 +681,7 @@ protected function addSecurityToOperation(): void } } - protected function getSummary($request, array $annotations): ?string + protected function getSummary($request, array $annotations) { $summary = Arr::get($annotations, 'summary'); @@ -704,19 +706,21 @@ protected function requestSupportAuth(): bool return !empty($header); } - protected function parseRequestName($request): string + protected function parseRequestName($request) { $explodedRequest = explode('\\', $request); $requestName = array_pop($explodedRequest); $summaryName = str_replace('Request', '', $requestName); + $underscoreRequestName = $this->camelCaseToUnderScore($summaryName); return preg_replace('/[_]/', ' ', $underscoreRequestName); } - protected function getResponseDescription(int $code): string + protected function getResponseDescription($code) { $defaultDescription = Response::$statusTexts[$code]; + $request = $this->getConcreteRequest(); if (empty($request)) { @@ -724,6 +728,7 @@ protected function getResponseDescription(int $code): string } $annotations = $this->getClassAnnotations($request); + $localDescription = Arr::get($annotations, "_{$code}"); if (!empty($localDescription)) { @@ -733,7 +738,7 @@ protected function getResponseDescription(int $code): string return Arr::get($this->config, "defaults.code-descriptions.{$code}", $defaultDescription); } - protected function getActionName(string $uri): string + protected function getActionName($uri): string { $action = preg_replace('[\/]', '', $uri); @@ -744,7 +749,7 @@ protected function getActionName(string $uri): string * @deprecated method is not in use * @codeCoverageIgnore */ - protected function saveTempData(): void + protected function saveTempData() { $exportFile = Arr::get($this->config, 'files.temporary'); $data = json_encode($this->data); @@ -752,12 +757,12 @@ protected function saveTempData(): void file_put_contents($exportFile, $data); } - public function saveProductionData(): void + public function saveProductionData() { $this->driver->saveData(); } - public function getDocFileContent(): array + public function getDocFileContent() { $documentation = $this->driver->getDocumentation(); @@ -786,7 +791,7 @@ protected function camelCaseToUnderScore($input): string $ret = $matches[0]; foreach ($ret as &$match) { - $match = ($match === strtoupper($match)) ? strtolower($match) : lcfirst($match); + $match = $match == strtoupper($match) ? strtolower($match) : lcfirst($match); } return implode('_', $ret); @@ -802,17 +807,19 @@ protected function generateExample($properties): array return $example; } - protected function replaceObjectValues(array $parameters): array + protected function replaceObjectValues($parameters): array { - $parameters = Arr::dot($parameters); - $returnParameters = []; $classNamesValues = [ File::class => '[uploaded_file]', ]; + $parameters = Arr::dot($parameters); + $returnParameters = []; + foreach ($parameters as $parameter => $value) { if (is_object($value)) { $class = get_class($value); + $value = Arr::get($classNamesValues, $class, $class); } @@ -825,8 +832,11 @@ protected function replaceObjectValues(array $parameters): array protected function getClassAnnotations($class): array { $reflection = new ReflectionClass($class); + $annotations = $reflection->getDocComment(); + $blocks = explode("\n", $annotations); + $result = []; foreach ($blocks as $block) { @@ -834,6 +844,7 @@ protected function getClassAnnotations($class): array $index = strpos($block, '@'); $block = substr($block, $index); $exploded = explode(' ', $block); + $paramName = str_replace('@', '', array_shift($exploded)); $paramValue = implode(' ', $exploded); @@ -853,7 +864,7 @@ protected function getClassAnnotations($class): array * this issue: https://github.com/OAI/OpenAPI-Specification/issues/229 * We hope swagger developers will resolve this problem in next release of Swagger OpenAPI * */ - protected function replaceNullValues(array $parameters, array $types, array &$example): void + protected function replaceNullValues($parameters, $types, &$example) { foreach ($parameters as $parameter => $value) { if (is_null($value) && array_key_exists($parameter, $types)) { @@ -866,7 +877,7 @@ protected function replaceNullValues(array $parameters, array $types, array &$ex } } - protected function getDefaultValueByType(string $type): mixed + protected function getDefaultValueByType($type) { $values = [ 'object' => 'null', diff --git a/src/Tests/AutoDocTestCaseTrait.php b/src/Tests/AutoDocTestCaseTrait.php index 317d807..77d3e6b 100644 --- a/src/Tests/AutoDocTestCaseTrait.php +++ b/src/Tests/AutoDocTestCaseTrait.php @@ -9,7 +9,7 @@ trait AutoDocTestCaseTrait /** * Disabling documentation collecting on current test */ - public function skipDocumentationCollecting(): void + public function skipDocumentationCollecting() { AutoDocMiddleware::$skipped = true; } diff --git a/src/Traits/GetDependenciesTrait.php b/src/Traits/GetDependenciesTrait.php index 884c4c6..8a04978 100644 --- a/src/Traits/GetDependenciesTrait.php +++ b/src/Traits/GetDependenciesTrait.php @@ -11,7 +11,7 @@ trait GetDependenciesTrait { - protected function resolveClassMethodDependencies(array $parameters, object $instance, string $method): array + protected function resolveClassMethodDependencies(array $parameters, $instance, $method) { if (!method_exists($instance, $method)) { return $parameters; @@ -22,14 +22,14 @@ protected function resolveClassMethodDependencies(array $parameters, object $ins ); } - public function getDependencies(ReflectionFunctionAbstract $reflector): array + public function getDependencies(ReflectionFunctionAbstract $reflector) { return array_map(function ($parameter) { return $this->transformDependency($parameter); }, $reflector->getParameters()); } - protected function transformDependency(ReflectionParameter $parameter): ?string + protected function transformDependency(ReflectionParameter $parameter) { $class = $parameter->getClass(); @@ -40,7 +40,7 @@ protected function transformDependency(ReflectionParameter $parameter): ?string return interface_exists($class->name) ? $this->getClassByInterface($class->name) : $class->name; } - protected function getClassByInterface(string $interfaceName): ?string + protected function getClassByInterface($interfaceName) { $bindings = Container::getInstance()->getBindings(); diff --git a/src/Validators/SwaggerSpecValidator.php b/src/Validators/SwaggerSpecValidator.php index f1e2210..968a419 100644 --- a/src/Validators/SwaggerSpecValidator.php +++ b/src/Validators/SwaggerSpecValidator.php @@ -20,6 +20,9 @@ use RonasIT\Support\AutoDoc\Exceptions\SpecValidation\MissingRefFileException; use RonasIT\Support\AutoDoc\Services\SwaggerService; +/** + * @property array $doc + */ class SwaggerSpecValidator { public const SCHEMA_TYPES = [ @@ -74,7 +77,7 @@ class SwaggerSpecValidator public const MIME_TYPE_MULTIPART_FORM_DATA = 'multipart/form-data'; public const MIME_TYPE_APPLICATION_URLENCODED = 'application/x-www-form-urlencoded'; - protected array $doc; + protected $doc; public function validate(array $doc): void { @@ -122,6 +125,7 @@ protected function validatePaths(): void $this->validateFieldsPresent(self::REQUIRED_FIELDS['operation'], $operationId); $this->validateFieldValue("{$operationId}.schemes", self::ALLOWED_VALUES['schemes']); + $this->validateParameters($operation, $path, $operationId); foreach ($operation['responses'] as $statusCode => $response) { @@ -150,6 +154,7 @@ protected function validateSecurityDefinitions(): void $parentId = "securityDefinitions.{$index}"; $this->validateFieldsPresent(self::REQUIRED_FIELDS['security_definition'], $parentId); + $this->validateFieldValue("{$parentId}.type", self::ALLOWED_VALUES['security_definition_type']); $this->validateFieldValue("{$parentId}.in", self::ALLOWED_VALUES['security_definition_in']); $this->validateFieldValue("{$parentId}.flow", self::ALLOWED_VALUES['security_definition_flow']); From ddcc18481a0068a87bf2457d35a418d813df9952 Mon Sep 17 00:00:00 2001 From: Konstantin Lapkovsky Date: Wed, 13 Dec 2023 19:50:50 +0400 Subject: [PATCH 6/6] chore: correct code structure. --- src/Http/Middleware/AutoDocMiddleware.php | 2 +- src/Services/SwaggerService.php | 83 ++++++++++++----------- 2 files changed, 46 insertions(+), 39 deletions(-) diff --git a/src/Http/Middleware/AutoDocMiddleware.php b/src/Http/Middleware/AutoDocMiddleware.php index a048448..e047211 100644 --- a/src/Http/Middleware/AutoDocMiddleware.php +++ b/src/Http/Middleware/AutoDocMiddleware.php @@ -16,7 +16,7 @@ public function handle($request, Closure $next) { $response = $next($request); - if ((config('app.env') == 'testing') && !self::$skipped && !empty($request->route())) { + if ((config('app.env') === 'testing') && !self::$skipped && !empty($request->route())) { app(SwaggerService::class)->addData($request, $response); } diff --git a/src/Services/SwaggerService.php b/src/Services/SwaggerService.php index f295b50..512565b 100755 --- a/src/Services/SwaggerService.php +++ b/src/Services/SwaggerService.php @@ -69,7 +69,7 @@ public function __construct(Container $container) $this->setDriver(); - if (config('app.env') == 'testing') { + if (config('app.env') === 'testing') { $this->container = $container; $this->security = $this->config['security']; @@ -281,51 +281,58 @@ protected function markAsDeprecated(array $annotations) $this->item['deprecated'] = Arr::get($annotations, 'deprecated', false); } - protected function saveResponseSchema(?array $content, int $code) + protected function saveResponseSchema(?array $content, string $definition): void { if (empty($content)) { return; } $schemaProperties = []; - $action = Str::ucfirst($this->getActionName($this->uri)); $schemaType = 'object'; if (array_is_list($content)) { - $schemaType = 'array'; - $types = []; + $this->saveListResponseDefinitions($content, $schemaProperties); - foreach ($content as $value) { - $type = gettype($value); - if (!in_array($type, $types)) { - $types[] = $type; - $schemaProperties['items']['allOf'][]['type'] = $type; - } - } + $schemaType = 'array'; } else { - $properties = Arr::get( - $this->data['definitions'], - "{$this->method}{$action}{$code}ResponseObject.properties", - [] - ); + $this->saveObjectResponseDefinitions($content, $schemaProperties, $definition); + } - foreach ($content as $name => $value) { - $property = Arr::get($properties, $name, []); + $this->data['definitions'][$definition] = [ + 'type' => $schemaType, + 'properties' => $schemaProperties + ]; + } - if (is_null($value)) { - $property['nullable'] = true; - } else { - $property['type'] = gettype($value); - } + protected function saveListResponseDefinitions(array $content, array &$schemaProperties): void + { + $types = []; + + foreach ($content as $value) { + $type = gettype($value); - $schemaProperties[$name] = $property; + if (!in_array($type, $types)) { + $types[] = $type; + $schemaProperties['items']['allOf'][]['type'] = $type; } } + } - $this->data['definitions']["{$this->method}{$action}{$code}ResponseObject"] = [ - 'type' => $schemaType, - 'properties' => $schemaProperties - ]; + protected function saveObjectResponseDefinitions(array $content, array &$schemaProperties, string $definition): void + { + $properties = Arr::get($this->data['definitions'], $definition, []); + + foreach ($content as $name => $value) { + $property = Arr::get($properties, $name, []); + + if (is_null($value)) { + $property['nullable'] = true; + } else { + $property['type'] = gettype($value); + } + + $schemaProperties[$name] = $property; + } } protected function parseResponse($response) @@ -373,13 +380,13 @@ protected function parseResponse($response) ); } - $this->saveResponseSchema($content, $code); + $action = Str::ucfirst($this->getActionName($this->uri)); + $definition = "{$this->method}{$action}{$code}ResponseObject"; - if (is_array($this->item['responses'][$code])) { - $action = Str::ucfirst($this->getActionName($this->uri)); - $definition = "#/definitions/{$this->method}{$action}{$code}ResponseObject"; + $this->saveResponseSchema($content, $definition); - $this->item['responses'][$code]['schema']['$ref'] = $definition; + if (is_array($this->item['responses'][$code])) { + $this->item['responses'][$code]['schema']['$ref'] = "#/definitions/{$definition}"; } } @@ -480,7 +487,7 @@ protected function saveGetRequestParameters($rules, array $attributes, array $an } $existedParameter = Arr::first($this->item['parameters'], function ($existedParameter) use ($parameter) { - return $existedParameter['name'] == $parameter; + return $existedParameter['name'] === $parameter; }); if (empty($existedParameter)) { @@ -598,7 +605,7 @@ protected function requestHasBody(): bool $parameters = $this->data['paths'][$this->uri][$this->method]['parameters']; $bodyParamExisted = Arr::where($parameters, function ($value) { - return $value['name'] == 'body'; + return $value['name'] === 'body'; }); return empty($bodyParamExisted); @@ -608,7 +615,7 @@ public function getConcreteRequest() { $controller = $this->request->route()->getActionName(); - if ($controller == 'Closure') { + if ($controller === 'Closure') { return null; } @@ -791,7 +798,7 @@ protected function camelCaseToUnderScore($input): string $ret = $matches[0]; foreach ($ret as &$match) { - $match = $match == strtoupper($match) ? strtolower($match) : lcfirst($match); + $match = ($match === strtoupper($match)) ? strtolower($match) : lcfirst($match); } return implode('_', $ret);