Skip to content

Commit baa74d7

Browse files
committed
First pass at swagger docs
1 parent 5df395b commit baa74d7

15 files changed

Lines changed: 281 additions & 0 deletions

src/Router.php

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
use PhpApi\Model\Request\AbstractRequest;
1212
use PhpApi\Model\Response\AbstractResponse;
1313
use PhpApi\Model\RouterOptions;
14+
use PhpApi\Swagger\GenerateSwaggerDocs;
1415
use PhpApi\Utility\Arrays;
1516
use ReflectionClass;
1617
use ReflectionFunction;
@@ -20,6 +21,13 @@
2021

2122
class Router
2223
{
24+
public const StaticRoutes = [
25+
'GET' => [
26+
'/swagger' => 'handleSwaggerPage',
27+
'/swagger/json' => 'handleSwaggerJson',
28+
],
29+
];
30+
2331
protected AutoRoute $autoRoute;
2432

2533
/** @var IRequestMiddleware[] $requestMiddlewares */
@@ -31,6 +39,9 @@ class Router
3139
/** @var array<int, callable> $errorHandlers */
3240
private array $errorHandlers = [];
3341

42+
/**
43+
* @param callable|null $controllerFactory
44+
*/
3445
public function __construct(
3546
private RouterOptions $routerOptions,
3647
private mixed $controllerFactory = null,
@@ -60,6 +71,12 @@ public function route(?Request $request = null): void
6071
$request = new Request();
6172
}
6273

74+
if (isset(self::StaticRoutes[$request->method->name][$request->url->path])) {
75+
$method = self::StaticRoutes[$request->method->name][$request->url->path];
76+
$this->$method();
77+
return;
78+
}
79+
6380
$route = $this->autoRoute->getRouter()
6481
->route($request->method->name ?? 'GET', $request->url->path ?? '');
6582

@@ -212,4 +229,25 @@ private function defaultErrorHandler(): Response
212229

213230
return $response;
214231
}
232+
233+
private function handleSwaggerJson(): void
234+
{
235+
$response = new Response();
236+
$response->setCode(200);
237+
$response->setHeader('Content-Type', 'application/json');
238+
$response->setContent((new GenerateSwaggerDocs(
239+
$this->autoRoute,
240+
$this->routerOptions,
241+
))->generate());
242+
$response->send();
243+
}
244+
245+
private function handleSwaggerPage(): void
246+
{
247+
$response = new Response();
248+
$response->setCode(200);
249+
$response->setHeader('Content-Type', 'text/html');
250+
$response->setContent(file_get_contents(__DIR__ . '/../swagger/index.html'));
251+
$response->send();
252+
}
215253
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
<?php
2+
3+
namespace PhpApi\Swagger;
4+
5+
use AutoRoute\AutoRoute;
6+
use PhpApi\Model\RouterOptions;
7+
use ReflectionClass;
8+
use ReflectionException;
9+
10+
class GenerateSwaggerDocs
11+
{
12+
public function __construct(
13+
private readonly AutoRoute $autoRoute,
14+
private readonly RouterOptions $routerOptions,
15+
) {
16+
}
17+
18+
public function generate(): string
19+
{
20+
$urls = $this->autoRoute->getDumper()->dump();
21+
$swaggerDocs = $this->generateSwagger($urls);
22+
return json_encode($swaggerDocs);
23+
}
24+
25+
/**
26+
* @param array<string, array<string, string>> $urls url[path][httpMethod] = class
27+
* @return array
28+
*/
29+
private function generateSwagger(array $urls): array
30+
{
31+
$swagger = [];
32+
foreach ($urls as $path => $methods) {
33+
foreach ($methods as $method => $class) {
34+
$reflectionClass = new ReflectionClass($class);
35+
try {
36+
$reflectionMethod = $reflectionClass->getMethod($this->routerOptions->method);
37+
} catch (ReflectionException $e) {
38+
continue;
39+
}
40+
41+
echo $method . ' ' . $path . '<br>';
42+
echo 'Class: ' . $class . '<br>';
43+
echo 'Method: ' . $reflectionMethod->getName() . '<br>';
44+
}
45+
}
46+
return $swagger;
47+
}
48+
}

src/Swagger/Model/Contact.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php
2+
3+
namespace PhpApi\Swagger\Model;
4+
5+
class Contact
6+
{
7+
public function __construct(public readonly string $email)
8+
{
9+
}
10+
}

src/Swagger/Model/ContentType.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?php
2+
3+
namespace PhpApi\Swagger\Model;
4+
5+
class ContentType
6+
{
7+
/**
8+
* @param array<string, string> $schema
9+
*/
10+
public function __construct(
11+
public readonly Schema $schema,
12+
public readonly mixed $example,
13+
) {
14+
}
15+
}

src/Swagger/Model/ExternalDocs.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php
2+
3+
namespace PhpApi\Swagger\Model;
4+
5+
class ExternalDocs
6+
{
7+
public function __construct(public readonly string $description, public readonly string $url)
8+
{
9+
}
10+
}

src/Swagger/Model/Info.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
namespace PhpApi\Swagger\Model;
4+
5+
class Info
6+
{
7+
public function __construct(
8+
public readonly string $title,
9+
public readonly string $description,
10+
public readonly string $termsOfService,
11+
public readonly Contact $contact,
12+
public readonly License $license,
13+
public readonly string $version
14+
) {
15+
}
16+
}

src/Swagger/Model/License.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php
2+
3+
namespace PhpApi\Swagger\Model;
4+
5+
class License
6+
{
7+
public function __construct(public readonly string $name, public readonly string $url)
8+
{
9+
}
10+
}

src/Swagger/Model/Path.php

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?php
2+
3+
namespace PhpApi\Swagger\Model;
4+
5+
class Path
6+
{
7+
/**
8+
*
9+
* @param string[] $tags
10+
* @param Parameter[] $parameters
11+
* @param RequestBody $requestBody
12+
* @param array<int, Response> $responses
13+
* @return void
14+
*/
15+
public function __construct(
16+
public array $tags,
17+
public string $summary,
18+
public string $description,
19+
public string $operationId,
20+
public array $parameters,
21+
public RequestBody $requestBody,
22+
public array $responses,
23+
) {
24+
}
25+
}

src/Swagger/Model/RequestBody.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
namespace PhpApi\Swagger\Model;
4+
5+
class RequestBody
6+
{
7+
/**
8+
* @param array<string, ContentType> $content
9+
*/
10+
public function __construct(
11+
public string $description,
12+
public bool $required,
13+
public array $content,
14+
) {
15+
}
16+
}

src/Swagger/Model/Response.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?php
2+
3+
namespace PhpApi\Swagger\Model;
4+
5+
class Response
6+
{
7+
/**
8+
* @param array<string, ResponseContent> $content
9+
*/
10+
public function __construct(
11+
public string $description,
12+
public array $content,
13+
) {
14+
}
15+
}

0 commit comments

Comments
 (0)