Skip to content

Commit 133865f

Browse files
authored
Merge pull request #208 from php-api-clients/make-as-many-unit-tests-as-possible-pass
Make as many unit tests as possible pass
2 parents a355c03 + bbfcb6b commit 133865f

File tree

154 files changed

+7944
-1504
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

154 files changed

+7944
-1504
lines changed

composer.json

+4-3
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
"jawira/case-converter": "^3.5",
2222
"kwn/number-to-words": "^2.6",
2323
"league/openapi-psr7-validator": "^0.21",
24+
"league/uri": "^6.8 || ^7.3",
2425
"nikic/php-parser": "^4.15",
2526
"nunomaduro/termwind": "^1.15",
2627
"ondram/ci-detector": "^4.1",
@@ -55,10 +56,10 @@
5556
],
5657
"config": {
5758
"allow-plugins": {
58-
"wyrihaximus/composer-update-bin-autoload-path": true,
59-
"infection/extension-installer": true,
6059
"dealerdirect/phpcodesniffer-composer-installer": true,
61-
"ergebnis/composer-normalize": true
60+
"ergebnis/composer-normalize": true,
61+
"infection/extension-installer": true,
62+
"wyrihaximus/composer-update-bin-autoload-path": true
6263
},
6364
"platform": {
6465
"php": "8.2.13"

composer.lock

+360-286
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

example/templates/composer.json

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
"devizzent/cebe-php-openapi": "^1",
2121
"eventsauce/object-hydrator": "^1.1",
2222
"league/openapi-psr7-validator": "^0.21",
23+
"league/uri": "^7.3 || ^6.8",
2324
"psr/http-message": "^1.0",
2425
"react/http": "^1.8",
2526
"react/async": "^4.0",

src/Gatherer/CompositSchema.php

+97
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace ApiClients\Tools\OpenApiClientGenerator\Gatherer;
6+
7+
use ApiClients\Tools\OpenApiClientGenerator\ClassString;
8+
use ApiClients\Tools\OpenApiClientGenerator\Configuration\Namespace_;
9+
use ApiClients\Tools\OpenApiClientGenerator\Registry\CompositSchema as CompositSchemaRegistry;
10+
use ApiClients\Tools\OpenApiClientGenerator\Registry\Contract as ContractRegistry;
11+
use ApiClients\Tools\OpenApiClientGenerator\Registry\Schema as SchemaRegistry;
12+
use ApiClients\Tools\OpenApiClientGenerator\Representation\Schema;
13+
use ApiClients\Tools\OpenApiClientGenerator\Utils;
14+
use cebe\openapi\spec\Schema as baseSchema;
15+
16+
use function array_key_exists;
17+
use function in_array;
18+
use function is_array;
19+
use function property_exists;
20+
21+
final class CompositSchema
22+
{
23+
public static function gather(
24+
Namespace_ $baseNamespace,
25+
string $className,
26+
baseSchema $schema,
27+
SchemaRegistry $schemaRegistry,
28+
ContractRegistry $contractRegistry,
29+
CompositSchemaRegistry $compositSchemaRegistry,
30+
): Schema {
31+
$className = Utils::className($className);
32+
$isArray = $schema->type === 'array';
33+
$properties = [];
34+
$example = [];
35+
36+
if ($isArray) {
37+
$schema = $schema->items;
38+
}
39+
40+
foreach ($schema->properties as $propertyName => $property) {
41+
$gatheredProperty = Property::gather(
42+
$baseNamespace,
43+
$className,
44+
(string) $propertyName,
45+
in_array(
46+
(string) $propertyName,
47+
$schema->required ?? [],
48+
false,
49+
),
50+
$property,
51+
$schemaRegistry,
52+
$contractRegistry,
53+
$compositSchemaRegistry,
54+
);
55+
$properties[] = $gatheredProperty;
56+
57+
$example[$gatheredProperty->sourceName] = $gatheredProperty->example->raw;
58+
59+
foreach (['examples', 'example'] as $examplePropertyName) {
60+
if (array_key_exists($gatheredProperty->sourceName, $example)) {
61+
break;
62+
}
63+
64+
if (! property_exists($schema, $examplePropertyName) || ! is_array($schema->$examplePropertyName) || ! array_key_exists($gatheredProperty->sourceName, $schema->$examplePropertyName)) {
65+
continue;
66+
}
67+
68+
$example[$gatheredProperty->sourceName] = $schema->$examplePropertyName[$gatheredProperty->sourceName];
69+
}
70+
71+
foreach ($property->enum ?? [] as $value) {
72+
$example[$gatheredProperty->sourceName] = $value;
73+
break;
74+
}
75+
76+
if ($example[$gatheredProperty->sourceName] !== null || $schema->required) {
77+
continue;
78+
}
79+
80+
unset($example[$gatheredProperty->sourceName]);
81+
}
82+
83+
return new Schema(
84+
ClassString::factory($baseNamespace, 'Schema\\' . $className),
85+
ClassString::factory($baseNamespace, 'Contract\\' . $className),
86+
ClassString::factory($baseNamespace, 'Error\\' . $className),
87+
ClassString::factory($baseNamespace, 'ErrorSchemas\\' . $className),
88+
$schema->title ?? '',
89+
$schema->description ?? '',
90+
$example,
91+
$properties,
92+
$schema,
93+
$isArray,
94+
($schema->type === null ? ['object'] : (is_array($schema->type) ? $schema->type : [$schema->type])),
95+
);
96+
}
97+
}

src/Gatherer/ExampleData.php

+30-1
Original file line numberDiff line numberDiff line change
@@ -14,18 +14,24 @@
1414
use ReverseRegex\Lexer;
1515
use ReverseRegex\Parser;
1616

17+
use function explode;
1718
use function gettype;
1819
use function is_array;
1920
use function is_string;
2021
use function Safe\date;
2122
use function Safe\json_encode;
2223
use function strlen;
24+
use function strpos;
2325

2426
final class ExampleData
2527
{
2628
public static function gather(mixed $exampleData, PropertyType $type, string $propertyName): Representation\ExampleData
2729
{
28-
if ($type->type === 'array') {
30+
if ($exampleData instanceof Representation\ExampleData) {
31+
return $exampleData;
32+
}
33+
34+
if ($type->type === 'array' || $type->type === 'union') {
2935
if ($type->payload instanceof Schema) {
3036
$exampleData = ArrayMerger::doMerge(
3137
$type->payload->example,
@@ -90,6 +96,12 @@ public static function determiteType(mixed $exampleData): Representation\Example
9096
/** @phpstan-ignore-next-line */
9197
public static function scalarData(int $seed, string $type, string|null $format, string|null $pattern = null): Representation\ExampleData
9298
{
99+
if (strpos($type, '|') !== false) {
100+
[$firstType] = explode('|', $type);
101+
102+
return self::scalarData($seed, $firstType, $format, $pattern);
103+
}
104+
93105
if ($type === 'int' || $type === '?int') {
94106
return new Representation\ExampleData($seed, new Node\Scalar\LNumber($seed));
95107
}
@@ -149,6 +161,23 @@ public static function scalarData(int $seed, string $type, string|null $format,
149161
return new Representation\ExampleData('generated', new Node\Scalar\String_('generated'));
150162
}
151163

164+
if ($type === 'array' || $type === '?array') {
165+
$string = self::scalarData($seed, 'string', $format, $pattern);
166+
167+
return new Representation\ExampleData(
168+
[
169+
$string->raw,
170+
],
171+
new Node\Expr\Array_(
172+
[
173+
new Node\Expr\ArrayItem(
174+
$string->node,
175+
),
176+
],
177+
),
178+
);
179+
}
180+
152181
return new Representation\ExampleData(
153182
null,
154183
new Node\Expr\ConstFetch(

src/Gatherer/IntersectionSchema.php

+106
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace ApiClients\Tools\OpenApiClientGenerator\Gatherer;
6+
7+
use ApiClients\Tools\OpenApiClientGenerator\ClassString;
8+
use ApiClients\Tools\OpenApiClientGenerator\Configuration\Namespace_;
9+
use ApiClients\Tools\OpenApiClientGenerator\Registry\CompositSchema as CompositSchemaRegistry;
10+
use ApiClients\Tools\OpenApiClientGenerator\Registry\Contract as ContractRegistry;
11+
use ApiClients\Tools\OpenApiClientGenerator\Registry\Schema as SchemaRegistry;
12+
use ApiClients\Tools\OpenApiClientGenerator\Representation\Contract;
13+
use ApiClients\Tools\OpenApiClientGenerator\Representation\Schema;
14+
use ApiClients\Tools\OpenApiClientGenerator\Utils;
15+
use cebe\openapi\spec\Schema as baseSchema;
16+
17+
use function array_key_exists;
18+
use function in_array;
19+
use function is_array;
20+
use function property_exists;
21+
22+
final class IntersectionSchema
23+
{
24+
public static function gather(
25+
Namespace_ $baseNamespace,
26+
string $className,
27+
baseSchema $baseProperty,
28+
SchemaRegistry $schemaRegistry,
29+
ContractRegistry $contractRegistry,
30+
CompositSchemaRegistry $compositSchemaRegistry,
31+
): Schema {
32+
$className = Utils::className($className);
33+
$contracts = [];
34+
$properties = [];
35+
$example = [];
36+
37+
foreach ($baseProperty->allOf as $schema) {
38+
$gatheredProperties = [];
39+
foreach ($schema->properties as $propertyName => $property) {
40+
$gatheredProperty = $gatheredProperties[(string) $propertyName] = Property::gather(
41+
$baseNamespace,
42+
$className,
43+
(string) $propertyName,
44+
in_array(
45+
(string) $propertyName,
46+
$schema->required ?? [],
47+
false,
48+
),
49+
$property,
50+
$schemaRegistry,
51+
$contractRegistry,
52+
$compositSchemaRegistry,
53+
);
54+
55+
$example[$gatheredProperty->sourceName] = $gatheredProperty->example->raw;
56+
57+
foreach (['examples', 'example'] as $examplePropertyName) {
58+
if (array_key_exists($gatheredProperty->sourceName, $example)) {
59+
break;
60+
}
61+
62+
if (! property_exists($schema, $examplePropertyName) || ! is_array($schema->$examplePropertyName) || ! array_key_exists($gatheredProperty->sourceName, $schema->$examplePropertyName)) {
63+
continue;
64+
}
65+
66+
$example[$gatheredProperty->sourceName] = $schema->$examplePropertyName[$gatheredProperty->sourceName];
67+
}
68+
69+
foreach ($property->enum ?? [] as $value) {
70+
$example[$gatheredProperty->sourceName] = $value;
71+
break;
72+
}
73+
74+
if ($example[$gatheredProperty->sourceName] !== null || $property->required || $baseProperty->required) {
75+
continue;
76+
}
77+
78+
unset($example[$gatheredProperty->sourceName]);
79+
}
80+
81+
$contracts[] = new Contract(
82+
ClassString::factory(
83+
$baseNamespace,
84+
$contractRegistry->get($schema, 'Contract\\' . $className . '\\' . $schema->title),
85+
),
86+
$gatheredProperties,
87+
);
88+
89+
$properties = [...$properties, ...$gatheredProperties];
90+
}
91+
92+
return new Schema(
93+
ClassString::factory($baseNamespace, 'Schema\\' . $className),
94+
$contracts,
95+
ClassString::factory($baseNamespace, 'Error\\' . $className),
96+
ClassString::factory($baseNamespace, 'ErrorSchemas\\' . $className),
97+
$baseProperty->title ?? '',
98+
$baseProperty->description ?? '',
99+
$example,
100+
$properties,
101+
$baseProperty,
102+
false,
103+
($baseProperty->type === null ? ['object'] : (is_array($baseProperty->type) ? $baseProperty->type : [$baseProperty->type])),
104+
);
105+
}
106+
}

src/Gatherer/Operation.php

+18-2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66

77
use ApiClients\Tools\OpenApiClientGenerator\ClassString;
88
use ApiClients\Tools\OpenApiClientGenerator\Configuration\Namespace_;
9+
use ApiClients\Tools\OpenApiClientGenerator\Registry\CompositSchema as CompositSchemaRegistry;
10+
use ApiClients\Tools\OpenApiClientGenerator\Registry\Contract as ContractRegistry;
911
use ApiClients\Tools\OpenApiClientGenerator\Registry\Schema as SchemaRegistry;
1012
use ApiClients\Tools\OpenApiClientGenerator\Registry\ThrowableSchema;
1113
use ApiClients\Tools\OpenApiClientGenerator\Representation\Header;
@@ -45,11 +47,21 @@ public static function gather(
4547
openAPIOperation $operation,
4648
ThrowableSchema $throwableSchemaRegistry,
4749
SchemaRegistry $schemaRegistry,
50+
ContractRegistry $contractRegistry,
51+
CompositSchemaRegistry $compositSchemaRegistry,
4852
): \ApiClients\Tools\OpenApiClientGenerator\Representation\Operation {
4953
$returnType = [];
5054
$parameters = [];
5155
$empties = [];
5256
foreach ($operation->parameters as $parameter) {
57+
$types = is_array($parameter->schema->type) ? $parameter->schema->type : [$parameter->schema->type];
58+
if (count($parameter->schema->oneOf ?? []) > 0) {
59+
$types = [];
60+
foreach ($parameter->schema->oneOf as $oneOfSchema) {
61+
$types[] = $oneOfSchema->type;
62+
}
63+
}
64+
5365
$parameterType = str_replace([
5466
'integer',
5567
'any',
@@ -58,7 +70,7 @@ public static function gather(
5870
'int',
5971
'string|object',
6072
'bool',
61-
], implode('|', is_array($parameter->schema->type) ? $parameter->schema->type : [$parameter->schema->type]));
73+
], implode('|', $types));
6274

6375
$parameters[] = new Parameter(
6476
(new Convert($parameter->name))->toCamel(),
@@ -82,7 +94,7 @@ public static function gather(
8294
);
8395
$requestBody[] = new OperationRequestBody(
8496
$contentType,
85-
Schema::gather($baseNamespace, $requestBodyClassname, $requestBodyDetails->schema, $schemaRegistry),
97+
Schema::gather($baseNamespace, $requestBodyClassname, $requestBodyDetails->schema, $schemaRegistry, $contractRegistry, $compositSchemaRegistry),
8698
);
8799
}
88100
}
@@ -115,6 +127,8 @@ public static function gather(
115127
$contentTypeMediaType->schema,
116128
true,
117129
$schemaRegistry,
130+
$contractRegistry,
131+
$compositSchemaRegistry,
118132
),
119133
);
120134
if ($isError) {
@@ -139,6 +153,8 @@ public static function gather(
139153
),
140154
$headerSpec->schema,
141155
$schemaRegistry,
156+
$contractRegistry,
157+
$compositSchemaRegistry,
142158
), ExampleData::determiteType($headerSpec->example));
143159
}
144160

0 commit comments

Comments
 (0)