Skip to content

Commit 9f136ad

Browse files
committed
✨ automatic search + mutate + detail endpoints
1 parent 8e6acf0 commit 9f136ad

20 files changed

+764
-81
lines changed

src/Console/Commands/DocumentationCommand.php

+2-46
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@ class DocumentationCommand extends GeneratorCommand implements PromptsForMissing
3434

3535
public function handle()
3636
{
37-
$openApi = $this->generateOpenApiSchema();
37+
$openApi = (new OpenAPI)
38+
->generate();
3839

3940
$path = $this->getPath('open-api');
4041

@@ -57,51 +58,6 @@ protected function getPath($name)
5758
return storage_path('app/documentation/'.$name.'.json');
5859
}
5960

60-
61-
62-
protected function generateOpenApiSchema(): OpenAPI
63-
{
64-
return (new OpenAPI)
65-
->withInfo(
66-
$this->generateInfoSchema()
67-
)
68-
->withPaths([])
69-
->withSecurity([])
70-
->withServers([]);
71-
}
72-
73-
protected function generateInfoSchema(): Info
74-
{
75-
return (new Info)
76-
->withTitle(config('rest.documentation.info.title'))
77-
->withSummary(config('rest.documentation.info.summary'))
78-
->withDescription(config('rest.documentation.info.description'))
79-
->withTermsOfService(config('rest.documentation.info.termsOfService'))
80-
->withContact(
81-
$this->generateContactSchema()
82-
)
83-
->withLicense(
84-
$this->generateLicense()
85-
)
86-
->withVersion(config('rest.documentation.info.version'));
87-
}
88-
89-
protected function generateContactSchema(): Contact
90-
{
91-
return (new Contact)
92-
->withName(config('rest.documentation.info.contact.name'))
93-
->withEmail(config('rest.documentation.info.contact.email'))
94-
->withUrl(config('rest.documentation.info.contact.url'));
95-
}
96-
97-
protected function generateLicense(): License
98-
{
99-
return (new License)
100-
->withUrl(config('rest.documentation.info.license.url'))
101-
->withName(config('rest.documentation.info.license.name'))
102-
->withIdentifier(config('rest.documentation.info.license.identifier'));
103-
}
104-
10561
protected function getStub()
10662
{
10763
throw new RuntimeException('Should not be here');

src/Documentation/Schemas/Contact.php

+8
Original file line numberDiff line numberDiff line change
@@ -63,4 +63,12 @@ public function jsonSerialize(): mixed
6363
'email' => $this->email()
6464
];
6565
}
66+
67+
public function generate(): Contact
68+
{
69+
return $this
70+
->withName(config('rest.documentation.info.contact.name'))
71+
->withEmail(config('rest.documentation.info.contact.email'))
72+
->withUrl(config('rest.documentation.info.contact.url'));
73+
}
6674
}

src/Documentation/Schemas/Example.php

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<?php
2+
3+
namespace Lomkit\Rest\Documentation\Schemas;
4+
5+
use Lomkit\Rest\Http\Controllers\Controller;
6+
7+
class Example extends Schema
8+
{
9+
/**
10+
* Value
11+
* @var string
12+
*/
13+
protected array $value;
14+
15+
public function jsonSerialize(): mixed
16+
{
17+
return $this->value();
18+
}
19+
20+
public function generate(): Example
21+
{
22+
return $this;
23+
}
24+
25+
public function withValue(array $value): Example
26+
{
27+
$this->value = $value;
28+
return $this;
29+
}
30+
31+
public function value(): array
32+
{
33+
return $this->value;
34+
}
35+
}
+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<?php
2+
3+
namespace Lomkit\Rest\Documentation\Schemas;
4+
5+
use Lomkit\Rest\Http\Controllers\Controller;
6+
7+
class Examples extends Schema
8+
{
9+
/**
10+
* Examples
11+
* @var array
12+
*/
13+
protected array $examples = [];
14+
15+
public function withExamples(array $examples): Examples
16+
{
17+
$this->examples = array_merge($this->examples, $examples);
18+
return $this;
19+
}
20+
21+
public function examples(): array
22+
{
23+
return $this->examples;
24+
}
25+
26+
public function jsonSerialize(): mixed
27+
{
28+
return collect($this->examples())->map->jsonSerialize()->toArray();
29+
}
30+
31+
public function generate(): Examples
32+
{
33+
return $this;
34+
}
35+
36+
public function generateDetail(Controller $controller): Examples
37+
{
38+
return $this
39+
->withExamples(
40+
[
41+
'application/json' => (new Example)
42+
->withExample(
43+
json_encode(
44+
['test1234' => 'OAZEOOEZAOEOAZ']
45+
)
46+
)
47+
]
48+
)
49+
->generate();
50+
}
51+
}

src/Documentation/Schemas/Header.php

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?php
2+
3+
namespace Lomkit\Rest\Documentation\Schemas;
4+
5+
class Header extends Parameter
6+
{
7+
public function withName(string $name): Parameter
8+
{
9+
throw new \RuntimeException('Name is forbidden on headers');
10+
}
11+
}

src/Documentation/Schemas/Info.php

+18
Original file line numberDiff line numberDiff line change
@@ -137,4 +137,22 @@ public function jsonSerialize(): mixed
137137
!is_null($this->termsOfService()) ? ['termsOfService' => $this->termsOfService()] : []
138138
);
139139
}
140+
141+
public function generate(): Info
142+
{
143+
return $this
144+
->withTitle(config('rest.documentation.info.title'))
145+
->withSummary(config('rest.documentation.info.summary'))
146+
->withDescription(config('rest.documentation.info.description'))
147+
->withTermsOfService(config('rest.documentation.info.termsOfService'))
148+
->withContact(
149+
(new Contact)
150+
->generate()
151+
)
152+
->withLicense(
153+
(new License)
154+
->generate()
155+
)
156+
->withVersion(config('rest.documentation.info.version'));
157+
}
140158
}

src/Documentation/Schemas/License.php

+8
Original file line numberDiff line numberDiff line change
@@ -65,4 +65,12 @@ public function jsonSerialize(): mixed
6565
!is_null($this->url()) ? ['url' => $this->url()] : []
6666
);
6767
}
68+
69+
public function generate(): License
70+
{
71+
return $this
72+
->withUrl(config('rest.documentation.info.license.url'))
73+
->withName(config('rest.documentation.info.license.name'))
74+
->withIdentifier(config('rest.documentation.info.license.identifier'));
75+
}
6876
}
+102
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
<?php
2+
3+
namespace Lomkit\Rest\Documentation\Schemas;
4+
5+
use Lomkit\Rest\Http\Controllers\Controller;
6+
7+
class MediaType extends Schema
8+
{
9+
protected SchemaConcrete $schemaConcrete;
10+
11+
protected Examples $examples;
12+
protected Example $example;
13+
14+
public function withSchemaConcrete(SchemaConcrete $schemaConcrete): MediaType
15+
{
16+
$this->schemaConcrete = $schemaConcrete;
17+
return $this;
18+
}
19+
20+
public function schemaConcrete(): SchemaConcrete
21+
{
22+
return $this->schemaConcrete;
23+
}
24+
25+
public function withExamples(Examples $examples): MediaType
26+
{
27+
$this->examples = $examples;
28+
return $this;
29+
}
30+
31+
public function examples(): Examples
32+
{
33+
return $this->examples;
34+
}
35+
36+
public function withExample(Example $example): MediaType
37+
{
38+
$this->example = $example;
39+
return $this;
40+
}
41+
42+
public function example(): Example
43+
{
44+
return $this->example;
45+
}
46+
47+
public function generate(): MediaType
48+
{
49+
return $this;
50+
}
51+
52+
public function jsonSerialize(): mixed
53+
{
54+
return array_merge(
55+
isset($this->schema) ? ['schema' => $this->schema()->jsonSerialize()] : [],
56+
isset($this->examples) ? ['examples' => $this->examples()->jsonSerialize()] : [],
57+
isset($this->example) ? ['example' => $this->example()->jsonSerialize()] : []
58+
);
59+
}
60+
61+
public function generateDetail(Controller $controller): MediaType
62+
{
63+
return $this
64+
->withExample(
65+
(new Example)
66+
->withValue(
67+
['data' => $controller::newResource()->jsonSerialize()]
68+
)
69+
)
70+
->generate();
71+
}
72+
73+
public function generateSearch(Controller $controller): MediaType
74+
{
75+
return $this
76+
->withExample(
77+
(new Example)
78+
->withValue(
79+
$controller::newResource()::newResponse()
80+
->resource($controller::newResource())
81+
->responsable(
82+
$controller::newResource()::newModel()::factory()->makeOne()
83+
->withoutRelations()
84+
)
85+
->toResponse(request())
86+
)
87+
)
88+
->generate();
89+
}
90+
91+
public function generateMutate(Controller $controller): MediaType
92+
{
93+
return $this
94+
->withExample(
95+
(new Example)
96+
->withValue(
97+
['created' => [1], 'updated' => [2,3]]
98+
)
99+
)
100+
->generate();
101+
}
102+
}

src/Documentation/Schemas/OpenAPI.php

+49
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@
22

33
namespace Lomkit\Rest\Documentation\Schemas;
44

5+
use Illuminate\Routing\Router;
6+
use Illuminate\Support\Facades\Route;
7+
use Illuminate\Support\Str;
8+
use Lomkit\Rest\Http\Controllers\Controller;
9+
510
class OpenAPI extends Schema
611
{
712
/**
@@ -108,4 +113,48 @@ public function jsonSerialize(): mixed
108113
'security' => collect($this->security())->map->jsonSerialize()->toArray()
109114
];
110115
}
116+
117+
public function generate(): OpenAPI
118+
{
119+
return $this
120+
->withInfo(
121+
(new Info)
122+
->generate()
123+
)
124+
->withPaths(
125+
$this->generatePaths()
126+
)
127+
->withSecurity([])
128+
->withServers([]);
129+
}
130+
131+
public function generatePaths() {
132+
$paths = [];
133+
134+
foreach (Route::getRoutes() as $route) {
135+
/** @var \Illuminate\Routing\Route $route */
136+
137+
if (is_null($route->getName()))
138+
{
139+
continue;
140+
}
141+
142+
$controller = $route->getController();
143+
144+
if ($controller instanceof Controller) {
145+
$path = match (Str::afterLast($route->getName(), '.')) {
146+
'detail' => (new Path)->generateDetail($controller),
147+
'search' => (new Path)->generateSearch($controller),
148+
'mutate' => (new Path)->generateMutate($controller),
149+
default => null
150+
};
151+
152+
if (!is_null($path)) {
153+
$paths['/'.$route->uri()] = $path;
154+
}
155+
}
156+
}
157+
158+
return $paths;
159+
}
111160
}

0 commit comments

Comments
 (0)