From 7c44e6c23de5dd52b0878927b2f1d182d43bd549 Mon Sep 17 00:00:00 2001 From: Bedram Tamang Date: Wed, 19 Oct 2022 09:15:22 +0545 Subject: [PATCH] Enum support --- .github/workflows/php-pint.yml | 28 ---------------------- composer.json | 7 +++--- config/api-generator.php | 7 ++++-- pint.json | 11 --------- src/Parser/HasPropertyType.php | 20 ++++++++++++---- src/Parser/RequestBodyComponent.php | 18 ++++++++------- src/Rules/EnumRule.php | 32 ++++++++++++++++++++++++++ src/Rules/FileRule.php | 3 --- src/Rules/IntegerRule.php | 4 ---- src/Rules/RequiredRule.php | 4 ---- src/Security/Bearer.php | 4 ++-- src/Security/HasParameter.php | 12 +++++----- src/Security/HasResponse.php | 12 +++++----- src/Security/HasSecurity.php | 2 +- src/Services/Generator.php | 8 +++---- src/Services/ProcessRequestTrait.php | 4 ++-- src/Traits/HasDocsGenerator.php | 22 +++++++++--------- tests/ResponseSchemeTest.php | 10 ++++---- tests/{ => Rules}/ArrayRuleTest.php | 3 ++- tests/Rules/EnumTest.php | 19 +++++++++++++++ tests/{ => Rules}/FileRuleTest.php | 3 ++- tests/{ => Rules}/IntegerRuleTest.php | 2 ++ tests/{ => Rules}/RequireRuleTest.php | 3 ++- tests/Stubs/ExampleFormRequest.php | 4 +++- tests/Stubs/FormRequestImageArray.php | 12 +++++----- tests/Stubs/RuleExampleFormRequest.php | 2 +- tests/Stubs/UsersController.php | 12 +++++----- 27 files changed, 145 insertions(+), 123 deletions(-) delete mode 100644 .github/workflows/php-pint.yml delete mode 100644 pint.json create mode 100644 src/Rules/EnumRule.php rename tests/{ => Rules}/ArrayRuleTest.php (83%) create mode 100644 tests/Rules/EnumTest.php rename tests/{ => Rules}/FileRuleTest.php (89%) rename tests/{ => Rules}/IntegerRuleTest.php (92%) rename tests/{ => Rules}/RequireRuleTest.php (87%) diff --git a/.github/workflows/php-pint.yml b/.github/workflows/php-pint.yml deleted file mode 100644 index 5443957..0000000 --- a/.github/workflows/php-pint.yml +++ /dev/null @@ -1,28 +0,0 @@ -name: Check & fix styling - -on: [ push ] - -jobs: - style: - runs-on: ubuntu-latest - - steps: - - name: Checkout code - uses: actions/checkout@v1 - - name: Fix style - uses: aglipanci/laravel-pint-action@1.0.0 - with: - preset: laravel - verboseMode: true - testMode: true - - name: Extract branch name - shell: bash - run: echo "##[set-output name=branch;]$(echo ${GITHUB_REF#refs/heads/})" - id: extract_branch - - name: Commit changes - uses: stefanzweifel/git-auto-commit-action@v2.3.0 - with: - commit_message: Fix styling - branch: ${{ steps.extract_branch.outputs.branch }} - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/composer.json b/composer.json index d6106d1..5a79e80 100644 --- a/composer.json +++ b/composer.json @@ -32,8 +32,8 @@ "scripts": { "test": "vendor/bin/phpunit", "psalm": "vendor/bin/psalm", - "test-coverage": "vendor/bin/phpunit --coverage-html coverage", - "format": "vendor/bin/pint" + "pint": "vendor/bin/pint", + "test-coverage": "vendor/bin/phpunit --coverage-html coverage" }, "autoload-dev": { "psr-4": { @@ -46,8 +46,7 @@ "require-dev": { "orchestra/testbench": "^6.15", "phpunit/phpunit": "^9.0", - "vimeo/psalm": "^4.7", - "laravel/pint": "^1.2" + "vimeo/psalm": "^4.7" }, "extra": { "laravel": { diff --git a/config/api-generator.php b/config/api-generator.php index 9f0d9bd..0ba7665 100644 --- a/config/api-generator.php +++ b/config/api-generator.php @@ -3,9 +3,12 @@ return [ 'servers' => [ 'url' => 'https://{environment}.localhost.test', + 'variables' => [ 'environment' => [ + 'default' => 'api', + 'enum' => [ 'api', 'api.dev', @@ -16,8 +19,8 @@ ], 'openapi' => '3.0.0', - 'title' => 'Reaching APP API', + 'title' => 'Reaching APP API', 'version' => '1.0.0', - 'file-path' => storage_path('api-docs/api-docs.json'), + 'file-path' => public_path('api-docs/api-docs.json'), ]; diff --git a/pint.json b/pint.json deleted file mode 100644 index cf5f303..0000000 --- a/pint.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "preset": "laravel", - "rules": { - "simplified_null_return": true, - "braces": false, - "new_with_braces": { - "anonymous_class": false, - "named_class": false - } - } -} diff --git a/src/Parser/HasPropertyType.php b/src/Parser/HasPropertyType.php index 87218f0..55858d5 100644 --- a/src/Parser/HasPropertyType.php +++ b/src/Parser/HasPropertyType.php @@ -4,6 +4,7 @@ use Illuminate\Support\Arr; use JoBins\APIGenerator\Rules\ArrayRule; +use JoBins\APIGenerator\Rules\EnumRule; use JoBins\APIGenerator\Rules\FileRule; use JoBins\APIGenerator\Rules\IntegerRule; @@ -22,15 +23,16 @@ trait HasPropertyType /** * @param array $rules * @param string $name + * * @return array|string[] */ public function getPropertyType(array $rules, string $name): array { - if (ArrayRule::check($rules)) { + if ( ArrayRule::check($rules) ) { $rules = Arr::get($this->rulesArray, "{$name}.*"); return [ - 'type' => 'array', + 'type' => 'array', 'items' => $this->getPropertyItemType($rules), ]; } @@ -48,21 +50,29 @@ public function setRulesArray(array $rulesArray): void private function getPropertyItemType(array $rules): array { - if (FileRule::check($rules)) { + if ( FileRule::check($rules) ) { $this->contentType = 'multipart/form-data'; return [ - 'type' => 'string', + 'type' => 'string', 'format' => 'binary', ]; } - if (IntegerRule::check($rules)) { + if ( IntegerRule::check($rules) ) { return [ 'type' => 'integer', ]; } + $enums = EnumRule::data($rules); + if ( count($enums) > 0 ) { + return [ + 'type' => 'string', + 'enum' => $enums, + ]; + } + return [ 'type' => 'string', ]; diff --git a/src/Parser/RequestBodyComponent.php b/src/Parser/RequestBodyComponent.php index 6b231da..d0fa19f 100644 --- a/src/Parser/RequestBodyComponent.php +++ b/src/Parser/RequestBodyComponent.php @@ -41,12 +41,14 @@ public function getRules(object $class): array return []; } - return collect($class->rules())->map(function ($item) { - if (! is_array($item)) { - return explode('|', $item); + return collect($class->rules())->map(function ($rules) { + if (! is_array($rules)) { + return explode('|', $rules); } - return $item; + return collect($rules)->filter(function ($item) { + return is_string($item); + }); })->toArray(); } @@ -61,10 +63,10 @@ public function getDescriptions(object $class): array public function getParseSchema(array $request): array { - $data = []; + $data = []; $data['schema'] = [ - 'type' => 'object', - 'required' => $this->getRequired($request), + 'type' => 'object', + 'required' => $this->getRequired($request), 'properties' => $this->getProperties($request), ]; @@ -82,7 +84,7 @@ public function parseRequestBodies(): array } /** @var FormRequest $class */ - $class = (new $className); + $class = new $className; // Set rules of a class for global access. $rules = $this->getRules($class); diff --git a/src/Rules/EnumRule.php b/src/Rules/EnumRule.php new file mode 100644 index 0000000..7bc6880 --- /dev/null +++ b/src/Rules/EnumRule.php @@ -0,0 +1,32 @@ +filter(function ($item) { - return is_string($item); - })->toArray(); - if (count(array_intersect(self::CONTAIN, $rules)) > 0) { return true; } diff --git a/src/Rules/RequiredRule.php b/src/Rules/RequiredRule.php index 3c2b864..8a1626e 100644 --- a/src/Rules/RequiredRule.php +++ b/src/Rules/RequiredRule.php @@ -23,10 +23,6 @@ class RequiredRule */ public static function check(array $rules): bool { - $rules = collect($rules)->filter(function ($item) { - return is_string($item); - })->toArray(); - if (count(array_intersect(self::CONTAIN, $rules)) == 0) { return false; } diff --git a/src/Security/Bearer.php b/src/Security/Bearer.php index e483c49..bd058c9 100644 --- a/src/Security/Bearer.php +++ b/src/Security/Bearer.php @@ -10,8 +10,8 @@ class Bearer public function getSchema() { return [ - 'name' => 'barerToken', - 'type' => 'http', + 'name' => 'barerToken', + 'type' => 'http', 'scheme' => 'bearer', ]; } diff --git a/src/Security/HasParameter.php b/src/Security/HasParameter.php index 134cb97..0bfe155 100644 --- a/src/Security/HasParameter.php +++ b/src/Security/HasParameter.php @@ -16,7 +16,7 @@ trait HasParameter */ public function preparePathWithParam(): array { - $url = Arr::get($this->request, 'url'); + $url = Arr::get($this->request, 'url'); $method = Arr::get($this->request, 'method'); $route = Route::getRoutes()->match(Request::create($url, $method)); @@ -39,8 +39,8 @@ public function processQuery(array $queries): array return collect($queries)->map(function ($value, $param) use ($definitions) { return [ - 'in' => 'query', - 'name' => $param, + 'in' => 'query', + 'name' => $param, 'schema' => [ 'type' => is_numeric($value) ? 'integer' : 'string', ], @@ -59,12 +59,12 @@ public function processParameters($parameters): array return collect($parameters)->map(function ($value, $param) use ($definitions) { return [ - 'in' => 'path', - 'name' => $param, + 'in' => 'path', + 'name' => $param, 'schema' => [ 'type' => is_numeric($value) ? 'integer' : 'string', ], - 'required' => true, + 'required' => true, 'description' => Arr::get($definitions, $param) ?? ' ', ]; })->toArray(); diff --git a/src/Security/HasResponse.php b/src/Security/HasResponse.php index 68ec0c0..2379bac 100644 --- a/src/Security/HasResponse.php +++ b/src/Security/HasResponse.php @@ -20,7 +20,7 @@ public function processResponse() if (Str::contains($attribute, '*') && $refSchemaName) { return [ - 'type' => 'array', + 'type' => 'array', 'items' => [ '$ref' => "#/components/schemas/{$refSchemaName}", ], @@ -42,7 +42,7 @@ public function processResponse() } return [ - 'type' => 'string', + 'type' => 'string', 'description' => $properties, ]; })->toArray(); @@ -52,7 +52,7 @@ public function parseResponse($originalResponseData) { $code = $this->response->getStatusCode(); - $schema = []; + $schema = []; $properties = $this->processResponse(); if (! empty($properties)) { $schema['properties'] = $this->processResponse(); @@ -66,7 +66,7 @@ public function parseResponse($originalResponseData) $responseData = [ $code => [ 'description' => "{$code} status response", - 'content' => [ + 'content' => [ 'application/json' => [ 'schema' => $schema, ], @@ -80,7 +80,7 @@ public function parseResponse($originalResponseData) private function defineSchema(string $name, string $type, array $properties) { $schemaData = [ - 'type' => $type, + 'type' => $type, 'items' => [ 'type' => 'object', ], @@ -94,7 +94,7 @@ private function getSchemaProperties($properties) { return collect($properties)->map(function ($definition) { return [ - 'type' => 'string', + 'type' => 'string', 'description' => $definition, ]; })->toArray(); diff --git a/src/Security/HasSecurity.php b/src/Security/HasSecurity.php index 03bdd3a..86870c1 100644 --- a/src/Security/HasSecurity.php +++ b/src/Security/HasSecurity.php @@ -34,7 +34,7 @@ public function ensureSecuritySchemaExists(array $schema): void } data_set($this->data, $key, [ - 'type' => 'http', + 'type' => 'http', 'scheme' => 'bearer', ]); } diff --git a/src/Services/Generator.php b/src/Services/Generator.php index 9a2a208..7bd86b0 100644 --- a/src/Services/Generator.php +++ b/src/Services/Generator.php @@ -37,8 +37,8 @@ public function __construct() $this->data = array_merge($this->data, [ 'servers' => $this->processServer(config()->get('api-generator')), 'openapi' => config()->get('api-generator.openapi'), - 'info' => [ - 'title' => config()->get('api-generator.title'), + 'info' => [ + 'title' => config()->get('api-generator.title'), 'version' => config()->get('api-generator.version'), ], ]); @@ -117,8 +117,8 @@ public function getBasicPathInfoData($responseData) private function parseParam() { [$url, $parameters] = $this->preparePathWithParam(); - $method = $this->request['method']; - $pathKey = "paths.{$url}.{$method}"; + $method = $this->request['method']; + $pathKey = "paths.{$url}.{$method}"; $pathData = Arr::get($this->data, $pathKey, []); $pathData = $pathData + $this->getBasicPathInfo($pathData, $parameters); diff --git a/src/Services/ProcessRequestTrait.php b/src/Services/ProcessRequestTrait.php index d5ea6f7..061eae6 100644 --- a/src/Services/ProcessRequestTrait.php +++ b/src/Services/ProcessRequestTrait.php @@ -24,9 +24,9 @@ public function setRequest(array $request): self private function parseRequestBody(): ?array { - $requestClass = app($this->request); + $className = Arr::get($this->request, 'rule'); - if (! ($className = Arr::get($this->request, 'rule'))) { + if (empty($className)) { return null; } diff --git a/src/Traits/HasDocsGenerator.php b/src/Traits/HasDocsGenerator.php index 2ef992a..d944eaa 100644 --- a/src/Traits/HasDocsGenerator.php +++ b/src/Traits/HasDocsGenerator.php @@ -175,17 +175,17 @@ public function jsond(string $method, string $uri, array $data = [], array $head public function getParams(): array { return [ - 'security' => $this->d_security, - 'operationID' => $this->d_operationId, - 'summary' => $this->d_summary, - 'tags' => $this->d_tags, - 'rule' => $this->d_request, - 'data' => $this->d_data, - 'header' => $this->d_header, - 'definitions' => $this->d_definitions, - 'url' => $this->d_url, - 'method' => $this->d_method, - 'ignoreData' => $this->d_ignore_request_data, + 'security' => $this->d_security, + 'operationID' => $this->d_operationId, + 'summary' => $this->d_summary, + 'tags' => $this->d_tags, + 'rule' => $this->d_request, + 'data' => $this->d_data, + 'header' => $this->d_header, + 'definitions' => $this->d_definitions, + 'url' => $this->d_url, + 'method' => $this->d_method, + 'ignoreData' => $this->d_ignore_request_data, 'responseSchema' => $this->d_response_schema, ]; } diff --git a/tests/ResponseSchemeTest.php b/tests/ResponseSchemeTest.php index 1b68706..7f0e45e 100644 --- a/tests/ResponseSchemeTest.php +++ b/tests/ResponseSchemeTest.php @@ -19,8 +19,8 @@ public function it_generates_scheme_for_list_responses() $responseSchema = [ 'description' => 'A User Object', - 'define' => [ - 'data.*' => ['refSchema' => 'UserSchema'], + 'define' => [ + 'data.*' => ['refSchema' => 'UserSchema'], 'message' => 'Message for user', ], ]; @@ -43,11 +43,11 @@ public function it_generates_scheme_for_detail_responses() deleteDocs(); $responseSchema = [ - 'schema' => 'UserSchema', + 'schema' => 'UserSchema', 'description' => 'A User Object', - 'define' => [ + 'define' => [ 'data' => [ - 'name' => 'Full name of an User', + 'name' => 'Full name of an User', 'email' => 'Email of an User.', ], ], diff --git a/tests/ArrayRuleTest.php b/tests/Rules/ArrayRuleTest.php similarity index 83% rename from tests/ArrayRuleTest.php rename to tests/Rules/ArrayRuleTest.php index 416c61b..2b1f828 100644 --- a/tests/ArrayRuleTest.php +++ b/tests/Rules/ArrayRuleTest.php @@ -1,8 +1,9 @@ assertTrue(EnumRule::check(['in:football,volleyball'])); + $this->assertEquals(['football', 'volleyball'], EnumRule::data(['in:football,volleyball'])); + } +} diff --git a/tests/FileRuleTest.php b/tests/Rules/FileRuleTest.php similarity index 89% rename from tests/FileRuleTest.php rename to tests/Rules/FileRuleTest.php index 389f4d0..c18ca25 100644 --- a/tests/FileRuleTest.php +++ b/tests/Rules/FileRuleTest.php @@ -1,9 +1,10 @@ 'required|in:football,cricket', + ]; } public function descriptions() diff --git a/tests/Stubs/FormRequestImageArray.php b/tests/Stubs/FormRequestImageArray.php index 4334c81..3f20c27 100644 --- a/tests/Stubs/FormRequestImageArray.php +++ b/tests/Stubs/FormRequestImageArray.php @@ -13,11 +13,11 @@ class FormRequestImageArray extends FormRequest implements Description public function rules() { return [ - 'profile' => 'required|image', - 'images' => 'nullable|sometimes|array|min:1|max:10', + 'profile' => 'required|image', + 'images' => 'nullable|sometimes|array|min:1|max:10', 'images.*' => 'image', - 'keys' => 'array', - 'keys.*' => 'integer', + 'keys' => 'array', + 'keys.*' => 'integer', ]; } @@ -25,8 +25,8 @@ public function descriptions(): array { return [ 'profiles' => 'Profiles', - 'images' => 'Images only', - 'keys.*' => 'Asterik', + 'images' => 'Images only', + 'keys.*' => 'Asterik', ]; } } diff --git a/tests/Stubs/RuleExampleFormRequest.php b/tests/Stubs/RuleExampleFormRequest.php index 0c54ef3..8efabaf 100644 --- a/tests/Stubs/RuleExampleFormRequest.php +++ b/tests/Stubs/RuleExampleFormRequest.php @@ -9,7 +9,7 @@ class RuleExampleFormRequest extends FormRequest public function rules() { return [ - 'name' => 'required', + 'name' => 'required', 'full_name' => 'sometimes|required', 'last_name' => 'nullable|required', ]; diff --git a/tests/Stubs/UsersController.php b/tests/Stubs/UsersController.php index cd555b4..6ae0908 100644 --- a/tests/Stubs/UsersController.php +++ b/tests/Stubs/UsersController.php @@ -17,7 +17,7 @@ public function index(): JsonResponse return response()->json( [ 'message' => 'List of Users', - 'data' => [ + 'data' => [ ['id' => 1, 'name' => 'Vedas Bomjon', 'email' => 'bedram@jobins.jp'], ['id' => 2, 'name' => 'Puncoz', 'email' => 'puncoz@jobins.jp'], ], @@ -30,12 +30,12 @@ public function show(): JsonResponse return response()->json( [ 'message' => 'Detail of a User.', - 'data' => [ - 'id' => 1, - 'name' => 'Vedas Bomjon', - 'email' => 'bedram@jobins.jp', + 'data' => [ + 'id' => 1, + 'name' => 'Vedas Bomjon', + 'email' => 'bedram@jobins.jp', 'company' => [ - 'name' => 'JoBins Inc.', + 'name' => 'JoBins Inc.', 'country' => 'Japan', ], ],