Files
alrahma_sunday_school_api/app/Services/Docs/OpenApiRouteExporter.php
T
2026-06-09 01:25:14 -04:00

133 lines
3.4 KiB
PHP

<?php
namespace App\Services\Docs;
use Illuminate\Routing\Route;
use Illuminate\Support\Facades\Route as RouteFacade;
use Illuminate\Support\Str;
class OpenApiRouteExporter
{
public function exportFromFile(string $path): array
{
$base = [];
if (is_file($path)) {
$json = json_decode((string) file_get_contents($path), true);
if (is_array($json)) {
$base = $json;
}
}
$base['paths'] = $base['paths'] ?? [];
foreach (RouteFacade::getRoutes() as $route) {
$this->mergeRoute($base['paths'], $route);
}
return $base;
}
private function mergeRoute(array &$paths, Route $route): void
{
if (! $this->isDocumentableRoute($route)) {
return;
}
$uriRaw = ltrim($route->uri(), '/');
if (str_starts_with($uriRaw, 'api/')) {
$uri = '/'.$uriRaw;
} elseif (str_starts_with($uriRaw, 'v1/')) {
$uri = '/api/'.$uriRaw;
} elseif ($uriRaw === 'v1') {
$uri = '/api/v1';
} else {
return;
}
if (! str_starts_with($uri, '/api/v1')) {
return;
}
$methods = array_diff($route->methods(), ['HEAD']);
if (empty($methods)) {
return;
}
$tag = $this->resolveTag($uri);
foreach ($methods as $method) {
$lower = strtolower($method);
if (! isset($paths[$uri][$lower])) {
$paths[$uri][$lower] = [
'tags' => [$tag],
'summary' => $this->summaryFromAction($route),
'responses' => [
'200' => [
'description' => 'OK',
],
],
];
}
}
}
private function isDocumentableRoute(Route $route): bool
{
$uri = ltrim($route->uri(), '/');
if (! str_starts_with($uri, 'api/v1') && ! str_starts_with($uri, 'v1/')) {
return false;
}
$action = $route->getActionName();
if (! is_string($action)) {
return false;
}
if (str_contains($action, 'DocsController')) {
return false;
}
if ($action === 'Closure') {
return true;
}
return true;
}
private function resolveTag(string $uri): string
{
$trimmed = trim(str_replace('/api/v1', '', $uri), '/');
if ($trimmed === '') {
return 'api';
}
$segments = explode('/', $trimmed);
$segment = $segments[0] ?: 'api';
$secondary = $segments[1] ?? null;
$normalized = Str::title(str_replace('-', ' ', $segment));
$overrides = [
'Whatsapp' => 'WhatsApp',
];
if ($segment === 'finance' && $secondary === 'refunds') {
return 'Refunds';
}
return $overrides[$normalized] ?? $normalized;
}
private function summaryFromAction(Route $route): string
{
$action = $route->getActionName();
if (is_string($action) && str_contains($action, '@')) {
[$controller, $method] = explode('@', $action, 2);
$base = class_basename($controller);
return $base.'::'.$method;
}
if (is_string($action)) {
return $action;
}
return 'Endpoint';
}
}