From cb7c03a02791eb3c84f65cb79f0d85b63c61eda4 Mon Sep 17 00:00:00 2001 From: Mohammad Hafijul Islam Date: Sun, 1 Oct 2023 05:11:37 +0600 Subject: [PATCH 1/2] artisan command to export collection as file --- config/request-docs.php | 4 + src/Commands/ExportRequestDocsCommand.php | 134 ++++++++++++++++++++++ src/LaravelRequestDocsServiceProvider.php | 2 + 3 files changed, 140 insertions(+) create mode 100644 src/Commands/ExportRequestDocsCommand.php diff --git a/config/request-docs.php b/config/request-docs.php index fdca916..ef767a2 100644 --- a/config/request-docs.php +++ b/config/request-docs.php @@ -153,4 +153,8 @@ ], ], ], + + //export request docs as json file from terminal + //from project root directory + 'export_path' => 'api.json' ]; diff --git a/src/Commands/ExportRequestDocsCommand.php b/src/Commands/ExportRequestDocsCommand.php new file mode 100644 index 0000000..e7e7924 --- /dev/null +++ b/src/Commands/ExportRequestDocsCommand.php @@ -0,0 +1,134 @@ +laravelRequestDocs = $laravelRequestDoc; + $this->laravelRequestDocsToOpenApi = $laravelRequestDocsToOpenApi; + } + + /** + * The name and signature of the console command. + * + * @var string + */ + protected $signature = 'laravel-request-docs:export + {path? : Export file location} + {--force : Whether to overwrite existing file}'; + + /** + * The console command description. + * + * @var string + */ + protected $description = 'Generate OpenAPI collection as json file'; + + private string $exportFilePath; + + /** + * Execute the console command. + */ + public function handle() + { + if ($this->confirmFilePath()) { + try { + $excludedMethods = config('request-docs.open_api.exclude_http_methods', []); + + $excludedMethods = array_map(fn($item) => strtolower($item), $excludedMethods); + + $showGet = !in_array('get', $excludedMethods); + $showPost = !in_array('post', $excludedMethods); + $showPut = !in_array('put', $excludedMethods); + $showPatch = !in_array('patch', $excludedMethods); + $showDelete = !in_array('delete', $excludedMethods); + $showHead = !in_array('head', $excludedMethods); + + // Get a list of Doc with route and rules information. + // If user defined `Route::match(['get', 'post'], 'uri', ...)`, + // only a single Doc will be generated. + $docs = $this->laravelRequestDocs->getDocs( + $showGet, + $showPost, + $showPut, + $showPatch, + $showDelete, + $showHead, + ); + + // Loop and split Doc by the `methods` property. + // `Route::match([...n], 'uri', ...)` will generate n number of Doc. + $docs = $this->laravelRequestDocs->splitByMethods($docs); + $docs = $this->laravelRequestDocs->sortDocs($docs, 'default'); + $docs = $this->laravelRequestDocs->groupDocs($docs, 'default'); + + $content = json_encode( + $this->laravelRequestDocsToOpenApi->openApi($docs->all())->toArray(), + JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE + ); + + if (!$this->writeFile($content)) { + throw new \ErrorException("Failed to write on [{$this->exportFilePath}] file."); + } + } catch (\Exception $exception) { + $this->error('Error : ' . $exception->getMessage()); + return self::FAILURE; + } + } + + return self::SUCCESS; + } + + /** + * @return bool + */ + private function confirmFilePath(): bool + { + $path = $this->argument('path'); + + if (!$path) { + $path = config('request-docs.export_path', 'api.json'); + } + + $this->exportFilePath = base_path($path); + + $path = str_replace(base_path('/'), '', $this->exportFilePath); + + if (file_exists($this->exportFilePath)) { + if (!$this->option('force')) { + if ($this->confirm("File exists on [{$path}]. Overwrite?", false) == true) { + return true; + } + return false; + } + } + + return true; + } + + /** + * @param $content + * @return false|int + */ + private function writeFile($content) + { + $targetDirectory = dirname($this->exportFilePath); + + if (!is_dir($targetDirectory)) { + mkdir($targetDirectory, 0755, true); + } + + return file_put_contents($this->exportFilePath, $content); + } +} diff --git a/src/LaravelRequestDocsServiceProvider.php b/src/LaravelRequestDocsServiceProvider.php index c4178b0..0125d7e 100644 --- a/src/LaravelRequestDocsServiceProvider.php +++ b/src/LaravelRequestDocsServiceProvider.php @@ -3,6 +3,7 @@ namespace Rakutentech\LaravelRequestDocs; use Illuminate\Support\Facades\Route; +use Rakutentech\LaravelRequestDocs\Commands\ExportRequestDocsCommand; use Spatie\LaravelPackageTools\Package; use Spatie\LaravelPackageTools\PackageServiceProvider; @@ -18,6 +19,7 @@ public function configurePackage(Package $package): void $package ->name('laravel-request-docs') ->hasConfigFile('request-docs') + ->hasCommand(ExportRequestDocsCommand::class) // ->hasAssets() ->hasViews(); // ->hasAssets(); From 4bff5ec7e2ae784d22e52bb5cbff2dde56048b29 Mon Sep 17 00:00:00 2001 From: Mohammad Hafijul Islam Date: Mon, 2 Oct 2023 05:23:12 +0600 Subject: [PATCH 2/2] standard practices, doc block added and exception handler corrected --- src/Commands/ExportRequestDocsCommand.php | 99 ++++++++++++----------- 1 file changed, 52 insertions(+), 47 deletions(-) diff --git a/src/Commands/ExportRequestDocsCommand.php b/src/Commands/ExportRequestDocsCommand.php index e7e7924..f4934aa 100644 --- a/src/Commands/ExportRequestDocsCommand.php +++ b/src/Commands/ExportRequestDocsCommand.php @@ -2,7 +2,10 @@ namespace Rakutentech\LaravelRequestDocs\Commands; +use ErrorException; +use Exception; use Illuminate\Console\Command; +use Illuminate\Support\Collection; use Rakutentech\LaravelRequestDocs\LaravelRequestDocs; use Rakutentech\LaravelRequestDocs\LaravelRequestDocsToOpenApi; @@ -15,7 +18,7 @@ public function __construct(LaravelRequestDocs $laravelRequestDoc, LaravelReques { parent::__construct(); - $this->laravelRequestDocs = $laravelRequestDoc; + $this->laravelRequestDocs = $laravelRequestDoc; $this->laravelRequestDocsToOpenApi = $laravelRequestDocsToOpenApi; } @@ -42,49 +45,45 @@ public function __construct(LaravelRequestDocs $laravelRequestDoc, LaravelReques */ public function handle() { - if ($this->confirmFilePath()) { - try { - $excludedMethods = config('request-docs.open_api.exclude_http_methods', []); - - $excludedMethods = array_map(fn($item) => strtolower($item), $excludedMethods); - - $showGet = !in_array('get', $excludedMethods); - $showPost = !in_array('post', $excludedMethods); - $showPut = !in_array('put', $excludedMethods); - $showPatch = !in_array('patch', $excludedMethods); - $showDelete = !in_array('delete', $excludedMethods); - $showHead = !in_array('head', $excludedMethods); - - // Get a list of Doc with route and rules information. - // If user defined `Route::match(['get', 'post'], 'uri', ...)`, - // only a single Doc will be generated. - $docs = $this->laravelRequestDocs->getDocs( - $showGet, - $showPost, - $showPut, - $showPatch, - $showDelete, - $showHead, - ); - - // Loop and split Doc by the `methods` property. - // `Route::match([...n], 'uri', ...)` will generate n number of Doc. - $docs = $this->laravelRequestDocs->splitByMethods($docs); - $docs = $this->laravelRequestDocs->sortDocs($docs, 'default'); - $docs = $this->laravelRequestDocs->groupDocs($docs, 'default'); - - $content = json_encode( - $this->laravelRequestDocsToOpenApi->openApi($docs->all())->toArray(), - JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE - ); - - if (!$this->writeFile($content)) { - throw new \ErrorException("Failed to write on [{$this->exportFilePath}] file."); - } - } catch (\Exception $exception) { - $this->error('Error : ' . $exception->getMessage()); - return self::FAILURE; + if (!$this->confirmFilePathAvailability()) { + //silently stop command + return self::SUCCESS; + } + + try { + //get the excluded methods list from config + $excludedMethods = config('request-docs.open_api.exclude_http_methods', []); + $excludedMethods = array_map(fn($item) => strtolower($item), $excludedMethods); + + //filter while method apis to export + $showGet = !in_array('get', $excludedMethods); + $showPost = !in_array('post', $excludedMethods); + $showPut = !in_array('put', $excludedMethods); + $showPatch = !in_array('patch', $excludedMethods); + $showDelete = !in_array('delete', $excludedMethods); + $showHead = !in_array('head', $excludedMethods); + + // Get a list of Doc with route and rules information. + $docs = $this->laravelRequestDocs->getDocs( + $showGet, + $showPost, + $showPut, + $showPatch, + $showDelete, + $showHead, + ); + + // Loop and split Doc by the `methods` property. + $docs = $this->laravelRequestDocs->splitByMethods($docs); + $docs = $this->laravelRequestDocs->sortDocs($docs, 'default'); + $docs = $this->laravelRequestDocs->groupDocs($docs, 'default'); + + if (!$this->writeApiDocsToFile($docs)) { + throw new ErrorException("Failed to write on [{$this->exportFilePath}] file."); } + } catch (Exception $exception) { + $this->error('Error : ' . $exception->getMessage()); + return self::FAILURE; } return self::SUCCESS; @@ -93,7 +92,7 @@ public function handle() /** * @return bool */ - private function confirmFilePath(): bool + private function confirmFilePathAvailability(): bool { $path = $this->argument('path'); @@ -118,17 +117,23 @@ private function confirmFilePath(): bool } /** - * @param $content + * @param $docs * @return false|int */ - private function writeFile($content) + private function writeApiDocsToFile(Collection $docs): bool { + $content = json_encode( + $this->laravelRequestDocsToOpenApi->openApi($docs->all())->toArray(), + JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE + ); + $targetDirectory = dirname($this->exportFilePath); + //create parent directory if not exists if (!is_dir($targetDirectory)) { mkdir($targetDirectory, 0755, true); } - return file_put_contents($this->exportFilePath, $content); + return (bool)file_put_contents($this->exportFilePath, $content); } }