From 7492d9bba3026248a611707d0157b3f4c7a1b45e Mon Sep 17 00:00:00 2001 From: Pulkit Kathuria Date: Sun, 1 Aug 2021 15:05:59 +0900 Subject: [PATCH] initial commit --- .editorconfig | 15 +++ .gitattributes | 14 +++ .github/workflows/phptest.yml | 37 ++++++++ .gitignore | 14 +++ LICENSE.md | 21 ++++ README.md | 82 ++++++++++++++++ composer.json | 61 ++++++++++++ config/request-docs.php | 11 +++ phpcs.xml | 12 +++ resources/views/.gitkeep | 0 resources/views/index.blade.php | 95 +++++++++++++++++++ src/Commands/LaravelRequestDocsCommand.php | 38 ++++++++ .../LaravelRequestDocsController.php | 25 +++++ src/LaravelRequestDocs.php | 89 +++++++++++++++++ src/LaravelRequestDocsFacade.php | 16 ++++ src/LaravelRequestDocsServiceProvider.php | 29 ++++++ tests/ExampleTest.php | 12 +++ tests/TestCase.php | 27 ++++++ 18 files changed, 598 insertions(+) create mode 100644 .editorconfig create mode 100644 .gitattributes create mode 100644 .github/workflows/phptest.yml create mode 100644 .gitignore create mode 100644 LICENSE.md create mode 100644 README.md create mode 100644 composer.json create mode 100644 config/request-docs.php create mode 100644 phpcs.xml create mode 100644 resources/views/.gitkeep create mode 100644 resources/views/index.blade.php create mode 100644 src/Commands/LaravelRequestDocsCommand.php create mode 100644 src/Controllers/LaravelRequestDocsController.php create mode 100644 src/LaravelRequestDocs.php create mode 100644 src/LaravelRequestDocsFacade.php create mode 100644 src/LaravelRequestDocsServiceProvider.php create mode 100644 tests/ExampleTest.php create mode 100644 tests/TestCase.php diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..a7c44dd --- /dev/null +++ b/.editorconfig @@ -0,0 +1,15 @@ +root = true + +[*] +charset = utf-8 +indent_size = 4 +indent_style = space +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true + +[*.md] +trim_trailing_whitespace = false + +[*.{yml,yaml}] +indent_size = 2 diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..886475c --- /dev/null +++ b/.gitattributes @@ -0,0 +1,14 @@ +# Path-based git attributes +# https://www.kernel.org/pub/software/scm/git/docs/gitattributes.html + +# Ignore all test and documentation with "export-ignore". +/.github export-ignore +/.gitattributes export-ignore +/.gitignore export-ignore +/phpunit.xml.dist export-ignore +/tests export-ignore +/.editorconfig export-ignore +/.php_cs.dist export-ignore +/psalm.xml export-ignore +/psalm.xml.dist export-ignore +/testbench.yaml export-ignore diff --git a/.github/workflows/phptest.yml b/.github/workflows/phptest.yml new file mode 100644 index 0000000..15a488a --- /dev/null +++ b/.github/workflows/phptest.yml @@ -0,0 +1,37 @@ +on: [push] + +name: "CI" + +jobs: + test: + name: Test + + runs-on: ubuntu-latest + + strategy: + matrix: + php-versions: [7.4, 8.0.6] + # laravel-versions: [8.*, 8.12] + + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: Install PHP with extensions + uses: shivammathur/setup-php@v2 + with: + coverage: pcov + extensions: intl, gd, zip, pdo, sqlite, pdo_sqlite, dom, curl, libxml, mbstring, fileinfo, exif, iconv + ini-values: memory_limit=-1,disable_functions="",pcov.exclude="~(vendor|tests|node_modules)~",pcov.directory="./" + php-version: ${{ matrix.php-versions }} + tools: composer:v2 + + - name: Composer Install + run: composer install + + - name: PHPUNIT Tests + run: | + ./vendor/bin/phpunit + + + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0a63bc1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,14 @@ +.idea +.php_cs +.php_cs.cache +.phpunit.result.cache +build +composer.lock +coverage +docs +phpunit.xml +psalm.xml +testbench.yaml +vendor +node_modules +.php-cs-fixer.cache diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..a84bef1 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) rakutentech + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..6bb3a38 --- /dev/null +++ b/README.md @@ -0,0 +1,82 @@ +# Automatically generate Laravel docs from request rules, controllers and routes + +[![Latest Version on Packagist](https://img.shields.io/packagist/v/rakutentech/laravel-request-docs.svg?style=flat-square)](https://packagist.org/packages/rakutentech/laravel-request-docs) +[![GitHub Tests Action Status](https://img.shields.io/github/workflow/status/rakutentech/laravel-request-docs/run-tests?label=tests)](https://github.com/rakutentech/laravel-request-docs/actions?query=workflow%3Arun-tests+branch%3Amain) +[![GitHub Code Style Action Status](https://img.shields.io/github/workflow/status/rakutentech/laravel-request-docs/Check%20&%20fix%20styling?label=code%20style)](https://github.com/rakutentech/laravel-request-docs/actions?query=workflow%3A"Check+%26+fix+styling"+branch%3Amain) +[![Total Downloads](https://img.shields.io/packagist/dt/rakutentech/laravel-request-docs.svg?style=flat-square)](https://packagist.org/packages/rakutentech/laravel-request-docs) + +--- +This repo can be used to scaffold a Laravel package. Follow these steps to get started: + +1. Press the "Use template" button at the top of this repo to create a new repo with the contents of this laravel-request-docs +2. Run "./configure-laravel-request-docs.sh" to run a script that will replace all placeholders throughout all the files +3. Remove this block of text. +4. Have fun creating your package. +5. If you need help creating a package, consider picking up our Laravel Package Training video course. +--- + +This is where your description should go. Limit it to a paragraph or two. Consider adding a small example. + +## Support us + +[](https://spatie.be/github-ad-click/laravel-request-docs) + +We invest a lot of resources into creating [best in class open source packages](https://spatie.be/open-source). You can support us by [buying one of our paid products](https://spatie.be/open-source/support-us). + +We highly appreciate you sending us a postcard from your hometown, mentioning which of our package(s) you are using. You'll find our address on [our contact page](https://spatie.be/about-us). We publish all received postcards on [our virtual postcard wall](https://spatie.be/open-source/postcards). + +## Installation + +You can install the package via composer: + +```bash +composer require rakutentech/laravel-request-docs +``` + +You can publish and run the migrations with: + +```bash +php artisan vendor:publish --provider="Rakutentech\LaravelRequestDocs\LaravelRequestDocsServiceProvider" +``` + + +This is the contents of the published config file: + +```php +return [ +]; +``` + +## Usage + +```php +$laravel-request-docs = new Rakutentech\LaravelRequestDocs(); +echo $laravel-request-docs->echoPhrase('Hello, Spatie!'); +``` + +## Testing + +```bash +composer test +``` + +## Changelog + +Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently. + +## Contributing + +Please see [CONTRIBUTING](.github/CONTRIBUTING.md) for details. + +## Security Vulnerabilities + +Please review [our security policy](../../security/policy) on how to report security vulnerabilities. + +## Credits + +- [Pulkit Kathuria](https://github.com/rakutentech) +- [All Contributors](../../contributors) + +## License + +The MIT License (MIT). Please see [License File](LICENSE.md) for more information. diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..59e2f9c --- /dev/null +++ b/composer.json @@ -0,0 +1,61 @@ +{ + "name": "rakutentech/laravel-request-docs", + "description": "Automatically generate Laravel docs from request rules, controllers and routes", + "keywords": [ + "rakutentech", + "laravel", + "laravel-request-docs" + ], + "homepage": "https://github.com/rakutentech/laravel-request-docs", + "license": "MIT", + "authors": [ + { + "name": "Pulkit Kathuria", + "email": "pulkit.kathuria@rakuten.com", + "role": "Developer" + } + ], + "require": { + "php": "^8.0", + "spatie/laravel-package-tools": "^1.4.3", + "illuminate/contracts": "^8.37" + }, + "require-dev": { + "brianium/paratest": "^6.2", + "nunomaduro/collision": "^5.3", + "orchestra/testbench": "^6.15", + "phpunit/phpunit": "^9.3", + "spatie/laravel-ray": "^1.23", + "vimeo/psalm": "^4.8" + }, + "autoload": { + "psr-4": { + "Rakutentech\\LaravelRequestDocs\\": "src" + } + }, + "autoload-dev": { + "psr-4": { + "Rakutentech\\LaravelRequestDocs\\Tests\\": "tests" + } + }, + "scripts": { + "psalm": "vendor/bin/psalm", + "test": "./vendor/bin/testbench package:test --parallel --no-coverage", + "test-coverage": "vendor/bin/phpunit --coverage-html coverage" + }, + "config": { + "sort-packages": true + }, + "extra": { + "laravel": { + "providers": [ + "Rakutentech\\LaravelRequestDocs\\LaravelRequestDocsServiceProvider" + ], + "aliases": { + "LaravelRequestDocs": "Rakutentech\\LaravelRequestDocs\\LaravelRequestDocsFacade" + } + } + }, + "minimum-stability": "dev", + "prefer-stable": true +} diff --git a/config/request-docs.php b/config/request-docs.php new file mode 100644 index 0000000..01e484a --- /dev/null +++ b/config/request-docs.php @@ -0,0 +1,11 @@ + 'request-docs', + 'middlewares' => [ + //Example + // \App\Http\Middleware\NotFoundWhenProduction::class, + ], + 'docs_path' => base_path('docs/request-docs/') +]; diff --git a/phpcs.xml b/phpcs.xml new file mode 100644 index 0000000..d314786 --- /dev/null +++ b/phpcs.xml @@ -0,0 +1,12 @@ + + + Standard Based on PSR2 + tests/* + + + + + + + + diff --git a/resources/views/.gitkeep b/resources/views/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/resources/views/index.blade.php b/resources/views/index.blade.php new file mode 100644 index 0000000..13f9356 --- /dev/null +++ b/resources/views/index.blade.php @@ -0,0 +1,95 @@ + + + + + + + Laravel Request Docs + + + + + + +
+
+

Routes List

+ + + @foreach ($docs as $index => $doc) + + + @endforeach + +
+ + + {{$doc['methods'][0]}} + + {{$doc['uri']}} + + +
+
+

+
+ @foreach ($docs as $index => $doc) +
+

+ {{$doc['methods'][0]}} + {{$doc['uri']}} +

+
+
+ + + + + + + + + + + @foreach ($doc['rules'] as $attribute => $rules) + + + + + + + @endforeach + +
AttributesRequiredTypeRules
{{$attribute}} + @foreach ($rules as $rule) + @if (str_contains($rule, 'required')) + REQUIRED + @endif +
+ @endforeach +
+ @foreach ($rules as $rule) + @if (str_contains($rule, 'integer')) + Integer + @endif + @if (str_contains($rule, 'string')) + String + @endif + @if (str_contains($rule, 'array')) + Array + @endif +
+ @endforeach +
+
+ @foreach ($rules as $rule) + {{ str_replace(["required|", "integer|", "string|"], ["", "", ""], $rule) }} + @endforeach +
+
+

+ @endforeach +
+
+ + diff --git a/src/Commands/LaravelRequestDocsCommand.php b/src/Commands/LaravelRequestDocsCommand.php new file mode 100644 index 0000000..4be73cb --- /dev/null +++ b/src/Commands/LaravelRequestDocsCommand.php @@ -0,0 +1,38 @@ +laravelRequestDocs = $laravelRequestDocs; + parent::__construct(); + } + + public function handle() + { + $destinationPath = config('request-docs.docs_path') ?? base_path('docs/request-docs/'); + $docs = $this->laravelRequestDocs->getDocs(); + + if (! File::exists($destinationPath)) { + File::makeDirectory($destinationPath, 0755, true); + } + File::put($destinationPath . '/index.html', + view('request-docs::index') + ->with(compact('docs')) + ->render() + ); + $this->comment('All done'); + } +} diff --git a/src/Controllers/LaravelRequestDocsController.php b/src/Controllers/LaravelRequestDocsController.php new file mode 100644 index 0000000..d095925 --- /dev/null +++ b/src/Controllers/LaravelRequestDocsController.php @@ -0,0 +1,25 @@ +laravelRequestDocs = $laravelRequestDocs; + } + + public function index() + { + $docs = $this->laravelRequestDocs->getDocs(); + return view('request-docs::index')->with(compact('docs')); + } + +} diff --git a/src/LaravelRequestDocs.php b/src/LaravelRequestDocs.php new file mode 100644 index 0000000..36dd661 --- /dev/null +++ b/src/LaravelRequestDocs.php @@ -0,0 +1,89 @@ +getControllersInfo(); + $controllersInfo = $this->appendRequestRules($controllersInfo); + foreach ($controllersInfo as $controllerInfo) { + if (!empty($controllerInfo['rules'])) { + $docs[] = $controllerInfo; + } + } + return array_filter($docs); + } + + public function getControllersInfo(): Array + { + $controllersInfo = []; + $routes = collect(Route::getRoutes()); + foreach ($routes as $route) { + $controllersInfo[] = [ + 'uri' => $route->uri, + 'methods' => $route->methods, + 'middleware' => $route->action['middleware'], + 'controller' => explode('@', $route->action['controller'])[0], + 'method' => explode('@', $route->action['controller'])[1], + ]; + } + + return $controllersInfo; + } + + public function appendRequestRules(Array $controllersInfo) + { + foreach ($controllersInfo as $index => $controllerInfo) { + $controllersInfo[$index]['rules'] = []; + $controller = $controllerInfo['controller']; + $method = $controllerInfo['method']; + $reflectionMethod = new ReflectionMethod($controller, $method); + $params = $reflectionMethod->getParameters(); + + foreach ($params as $param) { + if (!$param->getType()) { + continue; + } + $requestClassName = $param->getType()->getName(); + try { + $requestClass = new $requestClassName(); + if ($requestClass instanceof FormRequest) { + $controllersInfo[$index]['rules'] = $this->flattenRules($requestClass->rules()); + } + } catch (\Throwable $th) { + //throw $th; + } + } + } + return $controllersInfo; + } + + public function flattenRules($mixedRules) + { + $rules = []; + foreach ($mixedRules as $attribute => $rule) { + if (is_object($rule)) { + $rule = get_class($rule); + $rules[$attribute][] = $rule; + } else if (is_array($rule)) { + $rulesStrs = []; + foreach ($rule as $ruleItem) { + $rulesStrs[] = is_object($ruleItem) ? get_class($ruleItem) : $ruleItem; + } + $rules[$attribute][] = implode("|", $rulesStrs); + } else { + $rules[$attribute][] = $rule; + } + } + + return $rules; + } +} diff --git a/src/LaravelRequestDocsFacade.php b/src/LaravelRequestDocsFacade.php new file mode 100644 index 0000000..c21ecef --- /dev/null +++ b/src/LaravelRequestDocsFacade.php @@ -0,0 +1,16 @@ +name('laravel-request-docs') + ->hasConfigFile() + ->hasViews() + ->hasCommand(LaravelRequestDocsCommand::class); + + Route::get('/request-docs', [\Rakutentech\LaravelRequestDocs\Controllers\LaravelRequestDocsController::class, 'index']) + ->name('request-docs.index') + ->middleware(config('request-docs.middlewares')); + } +} diff --git a/tests/ExampleTest.php b/tests/ExampleTest.php new file mode 100644 index 0000000..21224ca --- /dev/null +++ b/tests/ExampleTest.php @@ -0,0 +1,12 @@ +assertTrue(true); + } +} diff --git a/tests/TestCase.php b/tests/TestCase.php new file mode 100644 index 0000000..91c792d --- /dev/null +++ b/tests/TestCase.php @@ -0,0 +1,27 @@ +set('database.default', 'testing'); + } +}