Skip to content

Commit bf7c57d

Browse files
authored
Merge pull request #75 from php-api-clients/switch-to-eventsauce-object-hydrator
Switch to event sauce object hydrator
2 parents 72f80ee + e3ccdaa commit bf7c57d

File tree

11 files changed

+180
-636
lines changed

11 files changed

+180
-636
lines changed

composer.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,11 @@
2828
"ringcentral/psr7": "^1.3",
2929
"symfony/yaml": "^5.4",
3030
"wyrihaximus/composer-update-bin-autoload-path": "^1 || ^1.0.1",
31-
"wyrihaximus/hydrator": "dev-master",
3231
"league/openapi-psr7-validator": "^0.16",
3332
"react/http": "^1.8",
3433
"reactivex/rxphp": "^2.0",
35-
"api-clients/contracts": "dev-main"
34+
"api-clients/contracts": "dev-main",
35+
"eventsauce/object-hydrator": "^1.1"
3636
},
3737
"autoload": {
3838
"psr-4": {

composer.lock

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

src/File.php

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -13,22 +13,9 @@
1313

1414
final class File
1515
{
16-
private string $fqcn;
17-
private Node $contents;
18-
19-
public function __construct(string $path, Node $contents)
20-
{
21-
$this->fqcn = $path;
22-
$this->contents = $contents;
23-
}
24-
25-
public function fqcn(): string
26-
{
27-
return $this->fqcn;
28-
}
29-
30-
public function contents(): Node
31-
{
32-
return $this->contents;
16+
public function __construct(
17+
public readonly string $fqcn,
18+
public readonly Node|string $contents,
19+
){
3320
}
3421
}

src/Generator.php

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,10 @@
1313
use ApiClients\Tools\OpenApiClientGenerator\Generator\WebHooks;
1414
use cebe\openapi\Reader;
1515
use cebe\openapi\spec\OpenApi;
16+
use EventSauce\ObjectHydrator\ObjectMapperCodeGenerator;
1617
use Jawira\CaseConverter\Convert;
18+
use League\ConstructFinder\ConstructFinder;
19+
use PhpParser\Node;
1720
use PhpParser\PrettyPrinter\Standard;
1821

1922
final class Generator
@@ -31,16 +34,17 @@ public function generate(string $namespace, string $destinationPath)
3134
$namespace = self::cleanUpNamespace($namespace);
3235
$codePrinter = new Standard();
3336

34-
foreach ($this->all($namespace) as $file) {
35-
$fileName = $destinationPath . DIRECTORY_SEPARATOR . str_replace('\\', DIRECTORY_SEPARATOR, substr($file->fqcn(), strlen($namespace)));
37+
foreach ($this->all($namespace, $destinationPath . DIRECTORY_SEPARATOR) as $file) {
38+
$fileName = $destinationPath . DIRECTORY_SEPARATOR . str_replace('\\', DIRECTORY_SEPARATOR, substr($file->fqcn, strlen($namespace)));
3639
@mkdir(dirname($fileName), 0744, true);
37-
file_put_contents($fileName . '.php', $codePrinter->prettyPrintFile([$file->contents()]) . PHP_EOL);
40+
file_put_contents($fileName . '.php', ($file->contents instanceof Node ? $codePrinter->prettyPrintFile([$file->contents]) : $file->contents) . PHP_EOL);
41+
include_once $fileName . '.php';
3842
}
3943
}
4044

4145
public static function className(string $className): string
4246
{
43-
return str_replace(['{', '}', '-', '$', '_', '+'], ['Cb', 'Rcb', 'Dash', '_', '\\', 'Plus'], (new Convert($className))->toPascal()) . (self::isKeyword(self::basename($className)) ? '_' : '');
47+
return str_replace(['{', '}', '-', '$', '_', '+', '*', '.'], ['Cb', 'Rcb', 'Dash', '_', '\\', 'Plus', 'Obelix', 'Dot'], (new Convert($className))->toPascal()) . (self::isKeyword(self::basename($className)) ? '_' : '');
4448
}
4549

4650
private static function cleanUpNamespace(string $namespace): string
@@ -56,8 +60,9 @@ private static function cleanUpNamespace(string $namespace): string
5660
* @param string $destinationPath
5761
* @return iterable<File>
5862
*/
59-
private function all(string $namespace): iterable
63+
private function all(string $namespace, string $rootPath): iterable
6064
{
65+
$schemaClasses = [];
6166
$schemaRegistry = new SchemaRegistry();
6267
if (count($this->spec->components->schemas ?? []) > 0) {
6368
foreach ($this->spec->components->schemas as $name => $schema) {
@@ -73,6 +78,7 @@ private function all(string $namespace): iterable
7378
continue;
7479
}
7580

81+
$schemaClasses[] = $namespace . 'Schema/' . $schemaClassName;
7682
yield from Schema::generate(
7783
$name,
7884
self::dirname($namespace . 'Schema/' . $schemaClassName),
@@ -134,6 +140,7 @@ private function all(string $namespace): iterable
134140
yield from Clients::generate(
135141
$operationGroup,
136142
self::dirname($namespace . 'Operation/' . $operationGroup),
143+
$namespace,
137144
self::basename($namespace . 'Operation/' . $operationGroup),
138145
$operations,
139146
);
@@ -166,10 +173,6 @@ private function all(string $namespace): iterable
166173
);
167174
}
168175

169-
yield from WebHookInterface::generate(
170-
self::dirname($namespace . 'WebHookInterface'),
171-
'WebHookInterface',
172-
);
173176
yield from WebHooks::generate(
174177
self::dirname($namespace . 'WebHooks'),
175178
$namespace,
@@ -179,6 +182,7 @@ private function all(string $namespace): iterable
179182

180183
while ($schemaRegistry->hasUnknownSchemas()) {
181184
foreach ($schemaRegistry->unknownSchemas() as $schema) {
185+
$schemaClasses[] = $namespace . 'Schema/' . $schema['className'];
182186
yield from Schema::generate(
183187
$schema['name'],
184188
self::dirname($namespace . 'Schema/' . $schema['className']),
@@ -189,6 +193,14 @@ private function all(string $namespace): iterable
189193
);
190194
}
191195
}
196+
197+
yield new File(
198+
$namespace . 'OptimizedHydratorMapper',
199+
(new ObjectMapperCodeGenerator())->dump(
200+
array_unique(array_filter(array_map(static fn (string $className): string => str_replace('/', '\\', $className), $schemaClasses), static fn (string $className): bool => count((new \ReflectionMethod($className, '__construct'))->getParameters()) > 0)),
201+
$namespace . 'OptimizedHydratorMapper'
202+
)
203+
);
192204
}
193205

194206
private static function fqcn(string $fqcn): string
@@ -212,6 +224,6 @@ public static function basename(string $fqcn): string
212224

213225
private static function isKeyword(string $name): bool
214226
{
215-
return in_array(strtolower($name), array('__halt_compiler', 'abstract', 'and', 'array', 'as', 'break', 'callable', 'case', 'catch', 'class', 'clone', 'const', 'continue', 'declare', 'default', 'die', 'do', 'echo', 'else', 'elseif', 'empty', 'enddeclare', 'endfor', 'endforeach', 'endif', 'endswitch', 'endwhile', 'eval', 'exit', 'extends', 'final', 'for', 'foreach', 'function', 'global', 'goto', 'if', 'implements', 'include', 'include_once', 'instanceof', 'insteadof', 'interface', 'isset', 'list', 'namespace', 'new', 'or', 'print', 'private', 'protected', 'public', 'require', 'require_once', 'return', 'static', 'switch', 'throw', 'trait', 'try', 'unset', 'use', 'var', 'while', 'xor', 'self'), false);
227+
return in_array(strtolower($name), array('__halt_compiler', 'abstract', 'and', 'array', 'as', 'break', 'callable', 'case', 'catch', 'class', 'clone', 'const', 'continue', 'declare', 'default', 'die', 'do', 'echo', 'else', 'elseif', 'empty', 'enddeclare', 'endfor', 'endforeach', 'endif', 'endswitch', 'endwhile', 'eval', 'exit', 'extends', 'final', 'for', 'foreach', 'function', 'global', 'goto', 'if', 'implements', 'include', 'include_once', 'instanceof', 'insteadof', 'interface', 'isset', 'list', 'namespace', 'new', 'or', 'print', 'private', 'protected', 'public', 'require', 'require_once', 'return', 'static', 'switch', 'throw', 'trait', 'try', 'unset', 'use', 'var', 'while', 'xor', 'self', 'parent', 'object'), false);
216228
}
217229
}

src/Generator/Client.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ public static function generate(string $namespace, array $clients, SchemaRegistr
4242
$factory->property('requestSchemaValidator')->setType('\League\OpenAPIValidation\Schema\SchemaValidator')->makeReadonly()->makePrivate()
4343
)->addStmt(
4444
$factory->property('responseSchemaValidator')->setType('\League\OpenAPIValidation\Schema\SchemaValidator')->makeReadonly()->makePrivate()
45+
)->addStmt(
46+
$factory->property('hydrator')->setType('\\' . $namespace . 'OptimizedHydratorMapper')->makeReadonly()->makePrivate()
4547
)->addStmt(
4648
$factory->method('__construct')->makePublic()->addParam(
4749
(new Param('authentication'))->setType('\\' . AuthenticationInterface::class)
@@ -98,6 +100,18 @@ public static function generate(string $namespace, array $clients, SchemaRegistr
98100
]
99101
),
100102
)
103+
)->addStmt(
104+
new Node\Expr\Assign(
105+
new Node\Expr\PropertyFetch(
106+
new Node\Expr\Variable('this'),
107+
'hydrator'
108+
),
109+
new Node\Expr\New_(
110+
new Node\Name('\\' . $namespace . 'OptimizedHydratorMapper'),
111+
[
112+
]
113+
),
114+
)
101115
)
102116
);
103117

@@ -149,6 +163,10 @@ public static function generate(string $namespace, array $clients, SchemaRegistr
149163
new Node\Expr\Variable('this'),
150164
'responseSchemaValidator'
151165
)),
166+
new Node\Arg(new Node\Expr\PropertyFetch(
167+
new Node\Expr\Variable('this'),
168+
'hydrator'
169+
)),
152170
]
153171
)
154172
)

src/Generator/Clients.php

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ final class Clients
1717
* @param array<string, string> $operations
1818
* @return iterable<Node>
1919
*/
20-
public static function generate(string $operationGroup, string $namespace, string $className, array $operations): iterable
20+
public static function generate(string $operationGroup, string $namespace, string $rootNamespace, string $className, array $operations): iterable
2121
{
2222
$factory = new BuilderFactory();
2323
$stmt = $factory->namespace($namespace);
@@ -26,6 +26,8 @@ public static function generate(string $operationGroup, string $namespace, strin
2626
$factory->property('requestSchemaValidator')->setType('\League\OpenAPIValidation\Schema\SchemaValidator')->makeReadonly()->makePrivate()
2727
)->addStmt(
2828
$factory->property('responseSchemaValidator')->setType('\League\OpenAPIValidation\Schema\SchemaValidator')->makeReadonly()->makePrivate()
29+
)->addStmt(
30+
$factory->property('hydrator')->setType('\\' . $rootNamespace . 'OptimizedHydratorMapper')->makeReadonly()->makePrivate()
2931
)->addStmt(
3032
$factory->method('__construct')->makePublic()->addParam(
3133
(new Param('requestSchemaValidator'))->setType('\League\OpenAPIValidation\Schema\SchemaValidator')
@@ -47,6 +49,16 @@ public static function generate(string $operationGroup, string $namespace, strin
4749
),
4850
new Node\Expr\Variable('responseSchemaValidator'),
4951
)
52+
)->addParam(
53+
(new Param('hydrator'))->setType('\\' . $rootNamespace . 'OptimizedHydratorMapper')
54+
)->addStmt(
55+
new Node\Expr\Assign(
56+
new Node\Expr\PropertyFetch(
57+
new Node\Expr\Variable('this'),
58+
'hydrator'
59+
),
60+
new Node\Expr\Variable('hydrator'),
61+
)
5062
)
5163
);
5264

@@ -60,6 +72,10 @@ public static function generate(string $operationGroup, string $namespace, strin
6072
new Node\Expr\Variable('this'),
6173
'responseSchemaValidator'
6274
);
75+
$params[] = new Node\Expr\PropertyFetch(
76+
new Node\Expr\Variable('this'),
77+
'hydrator'
78+
);
6379
$cn = str_replace('/', '\\', '\\' . $namespace . '\\' . $operationDetails['class']);
6480
$method = $factory->method(lcfirst($operationOperation))->setReturnType($cn)->makePublic();
6581
foreach ($operationDetails['operation']->parameters as $parameter) {

src/Generator/Operation.php

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ public static function generate(string $path, string $method, string $namespace,
7272
$factory->property('requestSchemaValidator')->setType('\League\OpenAPIValidation\Schema\SchemaValidator')->makeReadonly()->makePrivate()
7373
)->addStmt(
7474
$factory->property('responseSchemaValidator')->setType('\League\OpenAPIValidation\Schema\SchemaValidator')->makeReadonly()->makePrivate()
75+
)->addStmt(
76+
$factory->property('hydrator')->setType('\\' . $rootNamespace . 'OptimizedHydratorMapper')->makeReadonly()->makePrivate()
7577
);
7678

7779
$constructor = $factory->method('__construct')->makePublic()->addParam(
@@ -94,6 +96,16 @@ public static function generate(string $path, string $method, string $namespace,
9496
),
9597
new Node\Expr\Variable('responseSchemaValidator'),
9698
)
99+
)->addParam(
100+
(new Param('hydrator'))->setType('\\' . $rootNamespace . 'OptimizedHydratorMapper')
101+
)->addStmt(
102+
new Node\Expr\Assign(
103+
new Node\Expr\PropertyFetch(
104+
new Node\Expr\Variable('this'),
105+
'hydrator'
106+
),
107+
new Node\Expr\Variable('hydrator'),
108+
)
97109
);
98110
$requestReplaces = [];
99111
$query = [];
@@ -113,7 +125,7 @@ public static function generate(string $path, string $method, string $namespace,
113125
'bool',
114126
], implode('|', is_array($parameter->schema->type) ? $parameter->schema->type : [$parameter->schema->type])));
115127
}
116-
$class->addStmt($paramterStmt->makeReadonly()->makePrivate());
128+
$class->addStmt($paramterStmt->makePrivate());
117129

118130
$param = new Param($parameter->name);
119131
if ($parameter->schema->type !== null) {
@@ -225,8 +237,11 @@ public static function generate(string $path, string $method, string $namespace,
225237
$returnType[] = ($contentTypeSchema->schema->type === 'array' ? '\\' . Observable::class . '<' : '') . $object . ($contentTypeSchema->schema->type === 'array' ? '>' : '');
226238
$returnTypeRaw[] = $contentTypeSchema->schema->type === 'array' ? '\\' . Observable::class : $object;
227239
$hydrate = new Node\Expr\MethodCall(
228-
new Node\Expr\Variable('hydrator'),
229-
new Node\Name('hydrate'),
240+
new Node\Expr\PropertyFetch(
241+
new Node\Expr\Variable('this'),
242+
'hydrator'
243+
),
244+
new Node\Name('hydrateObject'),
230245
[
231246
new Node\Arg(new Node\Scalar\String_($object)),
232247
new Node\Arg(new Node\Expr\Variable('body')),
@@ -277,9 +292,6 @@ public static function generate(string $path, string $method, string $namespace,
277292
'params' => [
278293
new Node\Param(new Node\Expr\Variable('body'), null, new Node\Name('array'))
279294
],
280-
'uses' => [
281-
new Node\Expr\Variable('hydrator'),
282-
],
283295
'returnType' => $object,
284296
]))
285297
]
@@ -320,8 +332,6 @@ public static function generate(string $path, string $method, string $namespace,
320332
new Node\Expr\Assign(new Node\Expr\Variable('contentType'), new Node\Expr\MethodCall(new Node\Expr\Variable('response'), 'getHeaderLine', [new Arg(new Node\Scalar\String_('Content-Type'))]))
321333
)->addStmt(
322334
new Node\Expr\Assign(new Node\Expr\Variable('body'), new Node\Expr\FuncCall(new Node\Name('json_decode'), [new Node\Expr\MethodCall(new Node\Expr\MethodCall(new Node\Expr\Variable('response'), 'getBody'), 'getContents'), new Node\Expr\ConstFetch(new Node\Name('true'))]))
323-
)->addStmt(
324-
new Node\Expr\Assign(new Node\Expr\Variable('hydrator'), new Node\Expr\New_(new Node\Name('\\' . Hydrator::class)))
325335
)->addStmt(
326336
new Node\Stmt\Switch_(
327337
new Node\Expr\MethodCall(new Node\Expr\Variable('response'), 'getStatusCode'),

0 commit comments

Comments
 (0)