Skip to content

Commit b8fa502

Browse files
committed
Introduce representation layer for reduced complexity
This is a rewrite
1 parent 0db383c commit b8fa502

37 files changed

+2138
-1219
lines changed

bin/openapi-client-generator.source

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use Symfony\Component\Yaml\Yaml;
1717
*/
1818
exit((function (string $configuration): int {
1919
$yaml = Yaml::parseFile($configuration);
20-
(new Generator($yaml['spec']))->generate($yaml['namespace'] . '\\', $yaml['destination']);
20+
(new Generator($yaml['spec']))->generate($yaml['namespace'] . '\\', dirname($configuration) . DIRECTORY_SEPARATOR . $yaml['destination']);
2121

2222
return 0;
2323
})($configuration));

composer.lock

Lines changed: 24 additions & 27 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Files.php

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
<?php
2+
3+
namespace ApiClients\Tools\OpenApiClientGenerator;
4+
5+
use ApiClients\Tools\OpenApiClientGenerator\Generator\Client;
6+
use ApiClients\Tools\OpenApiClientGenerator\Generator\ClientInterface;
7+
use ApiClients\Tools\OpenApiClientGenerator\Generator\Hydrator;
8+
use ApiClients\Tools\OpenApiClientGenerator\Generator\Operation;
9+
use ApiClients\Tools\OpenApiClientGenerator\Generator\Path;
10+
use ApiClients\Tools\OpenApiClientGenerator\Generator\Schema;
11+
use ApiClients\Tools\OpenApiClientGenerator\Generator\WebHook;
12+
use ApiClients\Tools\OpenApiClientGenerator\Generator\WebHooks;
13+
use ApiClients\Tools\OpenApiClientGenerator\Registry\Schema as SchemaRegistry;
14+
use cebe\openapi\Reader;
15+
use cebe\openapi\spec\OpenApi;
16+
use EventSauce\ObjectHydrator\ObjectMapperCodeGenerator;
17+
use Jawira\CaseConverter\Convert;
18+
use PhpParser\Node;
19+
use PhpParser\PrettyPrinter\Standard;
20+
21+
final class Files
22+
{
23+
/**
24+
* @param string $path
25+
* @return iterable<string, string>
26+
*/
27+
public static function listExistingFiles(string $path): iterable
28+
{
29+
if (!file_exists($path)) {
30+
yield from [];
31+
return;
32+
}
33+
34+
foreach (scandir($path) as $node) {
35+
if ($node === '.' || $node === '..') {
36+
continue;
37+
}
38+
39+
if (is_file($path . $node)) {
40+
yield $path . $node => md5_file($path . $node);
41+
}
42+
43+
if (is_dir($path . $node)) {
44+
yield from self::listExistingFiles($path . $node . DIRECTORY_SEPARATOR);
45+
}
46+
}
47+
}
48+
}

src/Gatherer/Client.php

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<?php
2+
3+
namespace ApiClients\Tools\OpenApiClientGenerator\Gatherer;
4+
5+
use ApiClients\Tools\OpenApiClientGenerator\Utils;
6+
use ApiClients\Tools\OpenApiClientGenerator\Registry\Schema as SchemaRegistry;
7+
use ApiClients\Tools\OpenApiClientGenerator\Representation\OperationRequestBody;
8+
use ApiClients\Tools\OpenApiClientGenerator\Representation\OperationResponse;
9+
use ApiClients\Tools\OpenApiClientGenerator\Representation\Parameter;
10+
use cebe\openapi\spec\OpenApi;
11+
use cebe\openapi\spec\Operation as openAPIOperation;
12+
use cebe\openapi\spec\PathItem;
13+
use cebe\openapi\spec\Server;
14+
use Jawira\CaseConverter\Convert;
15+
use Psr\Http\Message\ResponseInterface;
16+
17+
final class Client
18+
{
19+
public static function gather(
20+
OpenApi $spec,
21+
\ApiClients\Tools\OpenApiClientGenerator\Representation\Path ...$paths,
22+
): \ApiClients\Tools\OpenApiClientGenerator\Representation\Client {
23+
$baseUrl = null;
24+
foreach ($spec->servers ?? [] as $server) {
25+
if (!($server instanceof Server)) {
26+
continue;
27+
}
28+
29+
if (strlen($server->url) === 0) {
30+
continue;
31+
}
32+
33+
$baseUrl = $server->url;
34+
break;
35+
}
36+
37+
return new \ApiClients\Tools\OpenApiClientGenerator\Representation\Client(
38+
$baseUrl,
39+
$paths,
40+
);
41+
}
42+
}

src/Gatherer/Hydrator.php

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?php
2+
3+
namespace ApiClients\Tools\OpenApiClientGenerator\Gatherer;
4+
5+
use ApiClients\Tools\OpenApiClientGenerator\Utils;
6+
use ApiClients\Tools\OpenApiClientGenerator\Registry\Schema as SchemaRegistry;
7+
use ApiClients\Tools\OpenApiClientGenerator\Representation\OperationRequestBody;
8+
use ApiClients\Tools\OpenApiClientGenerator\Representation\OperationResponse;
9+
use ApiClients\Tools\OpenApiClientGenerator\Representation\Parameter;
10+
use cebe\openapi\spec\Operation as openAPIOperation;
11+
use cebe\openapi\spec\PathItem;
12+
use Jawira\CaseConverter\Convert;
13+
use Psr\Http\Message\ResponseInterface;
14+
15+
final class Hydrator
16+
{
17+
public static function gather(
18+
string $className,
19+
\ApiClients\Tools\OpenApiClientGenerator\Representation\Schema ...$schemaClasses,
20+
): \ApiClients\Tools\OpenApiClientGenerator\Representation\Hydrator {
21+
return new \ApiClients\Tools\OpenApiClientGenerator\Representation\Hydrator(
22+
$className,
23+
str_replace(['\\', '/'], ['/', '🌀'], lcfirst($className)),
24+
$schemaClasses,
25+
);
26+
}
27+
}

src/Gatherer/Operation.php

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
<?php
2+
3+
namespace ApiClients\Tools\OpenApiClientGenerator\Gatherer;
4+
5+
use ApiClients\Tools\OpenApiClientGenerator\Representation\Hydrator;
6+
use ApiClients\Tools\OpenApiClientGenerator\Utils;
7+
use ApiClients\Tools\OpenApiClientGenerator\Registry\Schema as SchemaRegistry;
8+
use ApiClients\Tools\OpenApiClientGenerator\Representation\OperationRequestBody;
9+
use ApiClients\Tools\OpenApiClientGenerator\Representation\OperationResponse;
10+
use ApiClients\Tools\OpenApiClientGenerator\Representation\Parameter;
11+
use cebe\openapi\spec\Operation as openAPIOperation;
12+
use cebe\openapi\spec\PathItem;
13+
use Jawira\CaseConverter\Convert;
14+
use Psr\Http\Message\ResponseInterface;
15+
16+
final class Operation
17+
{
18+
public static function gather(
19+
string $className,
20+
string $method,
21+
string $path,
22+
openAPIOperation $operation,
23+
SchemaRegistry $schemaRegistry,
24+
): \ApiClients\Tools\OpenApiClientGenerator\Representation\Operation {
25+
$returnType = [];
26+
$parameters = [];
27+
$hasPerPageParameter = false;
28+
$hasPageParameter = false;
29+
foreach ($operation->parameters as $parameter) {
30+
if ($parameter->name === 'per_page') {
31+
$hasPerPageParameter = true;
32+
}
33+
if ($parameter->name === 'page') {
34+
$hasPageParameter = true;
35+
}
36+
$parameterType = str_replace([
37+
'integer',
38+
'any',
39+
'boolean',
40+
], [
41+
'int',
42+
'mixed',
43+
'bool',
44+
], implode('|', is_array($parameter->schema->type) ? $parameter->schema->type : [$parameter->schema->type]));
45+
46+
$parameters[] = new Parameter(
47+
$parameter->name,
48+
(string)$parameter->description,
49+
$parameterType,
50+
$parameter->in,
51+
$parameter->schema->default,
52+
);
53+
}
54+
55+
$classNameSanitized = str_replace('/', '\\', Utils::className($className));
56+
$requestBody = [];
57+
if ($operation->requestBody !== null) {
58+
foreach ($operation->requestBody->content as $contentType => $requestBodyDetails) {
59+
$requestBodyClassname = $schemaRegistry->get($requestBodyDetails->schema, $classNameSanitized . '\\Request\\' . Utils::className(str_replace('/', '', $contentType)));
60+
$requestBody[] = new OperationRequestBody(
61+
$contentType,
62+
Schema::gather($requestBodyClassname, $requestBodyDetails->schema, $schemaRegistry),
63+
);
64+
}
65+
}
66+
$response = [];
67+
foreach ($operation->responses as $code => $spec) {
68+
foreach ($spec->content as $contentType => $contentTypeMediaType) {
69+
$responseClassname = $schemaRegistry->get($contentTypeMediaType->schema, 'Operation\\' . $classNameSanitized . '\\Response\\' . Utils::className(str_replace('/', '', $contentType) . '\\H' . $code));
70+
$response[] = new OperationResponse(
71+
$code,
72+
$contentType,
73+
$spec->description,
74+
Schema::gather($responseClassname, $contentTypeMediaType->schema, $schemaRegistry),
75+
);
76+
$returnType[] = $responseClassname;
77+
}
78+
}
79+
80+
if (count($returnType) === 0) {
81+
$returnType[] = '\\' . ResponseInterface::class;
82+
}
83+
84+
return new \ApiClients\Tools\OpenApiClientGenerator\Representation\Operation(
85+
Utils::fixKeyword($className),
86+
$classNameSanitized,
87+
lcfirst(trim(Utils::basename($className),'\\')),
88+
trim(Utils::dirname($className),'\\'),
89+
$operation->operationId,
90+
$method,
91+
$path,
92+
$hasPageParameter === true && $hasPerPageParameter === true, // This is very GitHub specific!!!
93+
array_unique($returnType),
94+
[
95+
...array_filter($parameters, static fn (Parameter $parameter): bool => $parameter->default === null),
96+
...array_filter($parameters, static fn (Parameter $parameter): bool => $parameter->default !== null),
97+
],
98+
$requestBody,
99+
$response,
100+
);
101+
}
102+
}

src/Gatherer/OperationHydrator.php

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?php
2+
3+
namespace ApiClients\Tools\OpenApiClientGenerator\Gatherer;
4+
5+
use ApiClients\Tools\OpenApiClientGenerator\Utils;
6+
use ApiClients\Tools\OpenApiClientGenerator\Registry\Schema as SchemaRegistry;
7+
use ApiClients\Tools\OpenApiClientGenerator\Representation\OperationRequestBody;
8+
use ApiClients\Tools\OpenApiClientGenerator\Representation\OperationResponse;
9+
use ApiClients\Tools\OpenApiClientGenerator\Representation\Parameter;
10+
use cebe\openapi\spec\Operation as openAPIOperation;
11+
use cebe\openapi\spec\PathItem;
12+
use Jawira\CaseConverter\Convert;
13+
use Psr\Http\Message\ResponseInterface;
14+
15+
final class OperationHydrator
16+
{
17+
public static function gather(
18+
string $className,
19+
\ApiClients\Tools\OpenApiClientGenerator\Representation\Operation ...$operations,
20+
): \ApiClients\Tools\OpenApiClientGenerator\Representation\Hydrator {
21+
$schemaClasses = [];
22+
23+
foreach ($operations as $operation) {
24+
foreach ($operation->response as $response) {
25+
$schemaClasses[] = $response->schema;
26+
}
27+
}
28+
29+
return Hydrator::gather(
30+
'Operation\\' . $className,
31+
...$schemaClasses,
32+
);
33+
}
34+
}

0 commit comments

Comments
 (0)