Skip to content

Commit 9aa1dd1

Browse files
committed
[ISSUE-36] Allow to configure how deep the schema inspector should go for type/ofType sub-queries
1 parent 2b451e3 commit 9aa1dd1

8 files changed

+280
-71
lines changed

.gitignore

+2-1
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,5 @@ schema_object/*
55
!schema_object/.gitkeep
66
.phpunit.result.cache
77
/build/
8-
composer.lock
8+
composer.lock
9+
composer.phar

README.md

+7
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,13 @@ php vendor/bin/generate_schema_objects \
5151
--namespace "Vendor\Custom\Namespace"
5252
```
5353

54+
## Notes
55+
56+
### Dealing with `PHP Fatal error: Uncaught RuntimeException: Reached the limit of nesting in type info in ...SchemaGenerator\SchemaClassGenerator.php`
57+
You might encounter this error when the schema is deeply nested for the types.
58+
You can increase the depth of "type / ofType" by providing the `-D` option
59+
(or `--type-of-type-depth`) when running the command. The default value is 4.
60+
5461
# Usage
5562
In all the examples below I'm going to use the super cool public Pokemon GraphQL API as an illustration.
5663

bin/generate_schema_objects

+24-5
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,24 @@ use GraphQL\SchemaGenerator\SchemaClassGenerator;
77

88
$autoLoadFiles = [__DIR__ . '/../vendor/autoload.php', __DIR__ . '/../../../autoload.php'];
99

10-
function readConfig()
10+
/**
11+
* @return array{
12+
* 0: string,
13+
* 1: string,
14+
* 2: array<string, string>,
15+
* 3: string,
16+
* 4: int,
17+
* }
18+
*/
19+
function readConfig(): array
1120
{
1221
$shortOptions = implode("", [
1322
'u:',
1423
'h:',
1524
'v:',
1625
'd:',
17-
'n:'
26+
'n:',
27+
'D:',
1828
]);
1929

2030
$longOptions = [
@@ -23,6 +33,7 @@ function readConfig()
2333
'authorization-header-value:',
2434
'directory:',
2535
'namespace:',
36+
'type-of-type-depth:',
2637
];
2738

2839
$options = getopt($shortOptions, $longOptions);
@@ -32,14 +43,21 @@ function readConfig()
3243
$authHeaderName = $options['authorization-header-name'] ?? $options['h'] ?? readline('Authorization header name: ');
3344
$authHeaderValue = $options['authorization-header-value'] ?? $options['v'] ?? readline('Authorization header value: ');
3445
$namespace = $options['n'] ?? $options['namespace'] ?? trim(readline('Custom namespace (optional): '));
46+
$typeOfTypeDepth = $options['type-of-type-depth'] ?? $options['D'] ?? 4;
3547

3648
$authHeaders = [];
3749

3850
if (!empty($authHeaderName)) {
3951
$authHeaders = [$authHeaderName => $authHeaderValue];
4052
}
4153

42-
return [$url, empty($customWriteDir) ? "" : $customWriteDir, $authHeaders, empty($namespace) ? ObjectBuilderInterface::DEFAULT_NAMESPACE : $namespace];
54+
return [
55+
$url,
56+
empty($customWriteDir) ? "" : $customWriteDir,
57+
$authHeaders,
58+
empty($namespace) ? ObjectBuilderInterface::DEFAULT_NAMESPACE: $namespace,
59+
(int) $typeOfTypeDepth,
60+
];
4361
}
4462

4563
// Require autoload.php depending on environment
@@ -55,16 +73,17 @@ if (!$autoLoadFound) {
5573
throw new RuntimeException('Could not find vendor/autoload.php');
5674
}
5775

58-
[$endpointUrl, $customWriteDir, $authHeaders, $namespace] = readConfig();
76+
[$endpointUrl, $customWriteDir, $authHeaders, $namespace, $typeOfTypeDepth] = readConfig();
5977

6078
$client = new Client($endpointUrl, $authHeaders);
6179
$scanner = new SchemaClassGenerator($client, $customWriteDir, $namespace);
6280

6381
print "-------------------------------------------\n";
6482
print "Generating schema objects from schema types\n";
83+
print "Using \"type / ofType\" depth: $typeOfTypeDepth\n";
6584
print "-------------------------------------------\n";
6685

67-
$scanner->generateRootQueryObject();
86+
$scanner->generateRootQueryObject($typeOfTypeDepth);
6887

6988
print "-------------------------------------------\n";
7089
print "Schema objects generation complete\n";

src/SchemaGenerator/SchemaClassGenerator.php

+29-20
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
use GraphQL\SchemaGenerator\CodeGenerator\ObjectBuilderInterface;
1111
use GraphQL\SchemaGenerator\CodeGenerator\QueryObjectClassBuilder;
1212
use GraphQL\SchemaGenerator\CodeGenerator\UnionObjectBuilder;
13+
use GraphQL\SchemaGenerator\SchemaInspector\TypeSubQueryGenerator;
1314
use GraphQL\SchemaObject\QueryObject;
1415
use GraphQL\Util\StringLiteralFormatter;
1516
use RuntimeException;
@@ -55,19 +56,21 @@ class SchemaClassGenerator
5556
*/
5657
public function __construct(Client $client, string $writeDir = '', string $namespace = ObjectBuilderInterface::DEFAULT_NAMESPACE)
5758
{
58-
$this->schemaInspector = new SchemaInspector($client);
59+
$this->schemaInspector = new SchemaInspector($client, new TypeSubQueryGenerator());
5960
$this->generatedObjects = [];
6061
$this->writeDir = $writeDir;
6162
$this->generationNamespace = $namespace;
6263
$this->setWriteDir();
6364
}
6465

6566
/**
67+
* @param int $typeOfTypeDepth
68+
*
6669
* @return bool
6770
*/
68-
public function generateRootQueryObject(): bool
71+
public function generateRootQueryObject(int $typeOfTypeDepth = 4): bool
6972
{
70-
$objectArray = $this->schemaInspector->getQueryTypeSchema();
73+
$objectArray = $this->schemaInspector->getQueryTypeSchema($typeOfTypeDepth);
7174
$rootObjectName = QueryObject::ROOT_QUERY_OBJECT_NAME;
7275
$queryTypeName = $objectArray['name'];
7376
//$rootObjectDescr = $objectArray['description'];
@@ -79,7 +82,7 @@ public function generateRootQueryObject(): bool
7982
$this->generatedObjects[$queryTypeName] = true;
8083

8184
$queryObjectBuilder = new QueryObjectClassBuilder($this->writeDir, $rootObjectName, $this->generationNamespace);
82-
$this->appendQueryObjectFields($queryObjectBuilder, $rootObjectName, $objectArray['fields']);
85+
$this->appendQueryObjectFields($queryObjectBuilder, $rootObjectName, $objectArray['fields'], $typeOfTypeDepth);
8386
$queryObjectBuilder->build();
8487

8588
return true;
@@ -91,8 +94,9 @@ public function generateRootQueryObject(): bool
9194
* @param QueryObjectClassBuilder $queryObjectBuilder
9295
* @param string $currentTypeName
9396
* @param array $fieldsArray
97+
* @param int $typeOfTypeDepth
9498
*/
95-
private function appendQueryObjectFields(QueryObjectClassBuilder $queryObjectBuilder, string $currentTypeName, array $fieldsArray)
99+
private function appendQueryObjectFields(QueryObjectClassBuilder $queryObjectBuilder, string $currentTypeName, array $fieldsArray, int $typeOfTypeDepth = 4): void
96100
{
97101
foreach ($fieldsArray as $fieldArray) {
98102
$name = $fieldArray['name'];
@@ -110,7 +114,7 @@ private function appendQueryObjectFields(QueryObjectClassBuilder $queryObjectBui
110114
} else {
111115

112116
// Generate nested type object if it wasn't generated
113-
$objectGenerated = $this->generateObject($typeName, $typeKind);
117+
$objectGenerated = $this->generateObject($typeName, $typeKind, $typeOfTypeDepth);
114118
if ($objectGenerated) {
115119

116120
// Generate nested type arguments object if it wasn't generated
@@ -129,20 +133,21 @@ private function appendQueryObjectFields(QueryObjectClassBuilder $queryObjectBui
129133
/**
130134
* @param string $objectName
131135
* @param string $objectKind
136+
* @param int $typeOfTypeDepth
132137
*
133138
* @return bool
134139
*/
135-
protected function generateObject(string $objectName, string $objectKind): bool
140+
protected function generateObject(string $objectName, string $objectKind, int $typeOfTypeDepth = 4): bool
136141
{
137142
switch ($objectKind) {
138143
case FieldTypeKindEnum::OBJECT:
139-
return $this->generateQueryObject($objectName);
144+
return $this->generateQueryObject($objectName, $typeOfTypeDepth);
140145
case FieldTypeKindEnum::INPUT_OBJECT:
141-
return $this->generateInputObject($objectName);
146+
return $this->generateInputObject($objectName, $typeOfTypeDepth);
142147
case FieldTypeKindEnum::ENUM_OBJECT:
143148
return $this->generateEnumObject($objectName);
144149
case FieldTypeKindEnum::UNION_OBJECT:
145-
return $this->generateUnionObject($objectName);
150+
return $this->generateUnionObject($objectName, $typeOfTypeDepth);
146151
default:
147152
print "Couldn't generate type $objectName: generating $objectKind kind is not supported yet" . PHP_EOL;
148153
return false;
@@ -151,39 +156,41 @@ protected function generateObject(string $objectName, string $objectKind): bool
151156

152157
/**
153158
* @param string $objectName
159+
* @param int $typeOfTypeDepth
154160
*
155161
* @return bool
156162
*/
157-
protected function generateQueryObject(string $objectName): bool
163+
protected function generateQueryObject(string $objectName, int $typeOfTypeDepth = 4): bool
158164
{
159165
if (array_key_exists($objectName, $this->generatedObjects)) {
160166
return true;
161167
}
162168

163169
$this->generatedObjects[$objectName] = true;
164-
$objectArray = $this->schemaInspector->getObjectSchema($objectName);
170+
$objectArray = $this->schemaInspector->getObjectSchema($objectName, $typeOfTypeDepth);
165171
$objectName = $objectArray['name'];
166172
$objectBuilder = new QueryObjectClassBuilder($this->writeDir, $objectName, $this->generationNamespace);
167173

168-
$this->appendQueryObjectFields($objectBuilder, $objectName, $objectArray['fields']);
174+
$this->appendQueryObjectFields($objectBuilder, $objectName, $objectArray['fields'], $typeOfTypeDepth);
169175
$objectBuilder->build();
170176

171177
return true;
172178
}
173179

174180
/**
175181
* @param string $objectName
182+
* @param int $typeOfTypeDepth
176183
*
177184
* @return bool
178185
*/
179-
protected function generateInputObject(string $objectName): bool
186+
protected function generateInputObject(string $objectName, int $typeOfTypeDepth = 4): bool
180187
{
181188
if (array_key_exists($objectName, $this->generatedObjects)) {
182189
return true;
183190
}
184191

185192
$this->generatedObjects[$objectName] = true;
186-
$objectArray = $this->schemaInspector->getInputObjectSchema($objectName);
193+
$objectArray = $this->schemaInspector->getInputObjectSchema($objectName, $typeOfTypeDepth);
187194
$objectName = $objectArray['name'];
188195
$objectBuilder = new InputObjectClassBuilder($this->writeDir, $objectName, $this->generationNamespace);
189196

@@ -195,7 +202,7 @@ protected function generateInputObject(string $objectName): bool
195202

196203
$objectGenerated = true;
197204
if ($typeKind !== FieldTypeKindEnum::SCALAR) {
198-
$objectGenerated = $this->generateObject($typeName, $typeKind);
205+
$objectGenerated = $this->generateObject($typeName, $typeKind, $typeOfTypeDepth);
199206
}
200207

201208
if ($objectGenerated) {
@@ -245,10 +252,11 @@ protected function generateEnumObject(string $objectName): bool
245252

246253
/**
247254
* @param string $objectName
255+
* @param int $typeOfTypeDepth
248256
*
249257
* @return bool
250258
*/
251-
protected function generateUnionObject(string $objectName): bool
259+
protected function generateUnionObject(string $objectName, int $typeOfTypeDepth = 4): bool
252260
{
253261
if (array_key_exists($objectName, $this->generatedObjects)) {
254262
return true;
@@ -261,7 +269,7 @@ protected function generateUnionObject(string $objectName): bool
261269
$objectBuilder = new UnionObjectBuilder($this->writeDir, $objectName, $this->generationNamespace);
262270

263271
foreach ($objectArray['possibleTypes'] as $possibleType) {
264-
$this->generateObject($possibleType['name'], $possibleType['kind']);
272+
$this->generateObject($possibleType['name'], $possibleType['kind'], $typeOfTypeDepth);
265273
$objectBuilder->addPossibleType($possibleType['name']);
266274
}
267275
$objectBuilder->build();
@@ -272,10 +280,11 @@ protected function generateUnionObject(string $objectName): bool
272280
/**
273281
* @param string $argsObjectName
274282
* @param array $arguments
283+
* @param int $typeOfTypeDepth
275284
*
276285
* @return bool
277286
*/
278-
protected function generateArgumentsObject(string $argsObjectName, array $arguments): bool
287+
protected function generateArgumentsObject(string $argsObjectName, array $arguments, int $typeOfTypeDepth = 4): bool
279288
{
280289
if (array_key_exists($argsObjectName, $this->generatedObjects)) {
281290
return true;
@@ -293,7 +302,7 @@ protected function generateArgumentsObject(string $argsObjectName, array $argume
293302

294303
$objectGenerated = true;
295304
if ($typeKind !== FieldTypeKindEnum::SCALAR) {
296-
$objectGenerated = $this->generateObject($typeName, $typeKind);
305+
$objectGenerated = $this->generateObject($typeName, $typeKind, $typeOfTypeDepth);
297306
}
298307

299308
if ($objectGenerated) {

0 commit comments

Comments
 (0)