Skip to content

Commit 0431801

Browse files
authored
Merge pull request #1 from Epiconcept-Paris/feature/add-interface-type-schema-introspection
Add support for INTERFACE object type
2 parents 2b451e3 + 52b76da commit 0431801

File tree

6 files changed

+224
-12
lines changed

6 files changed

+224
-12
lines changed

src/Enumeration/FieldTypeKindEnum.php

+8-7
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,12 @@
99
*/
1010
class FieldTypeKindEnum
1111
{
12-
const SCALAR = 'SCALAR';
13-
const LIST = 'LIST';
14-
const NON_NULL = 'NON_NULL';
15-
const OBJECT = 'OBJECT';
16-
const INPUT_OBJECT = 'INPUT_OBJECT';
17-
const ENUM_OBJECT = 'ENUM';
18-
const UNION_OBJECT = 'UNION';
12+
const SCALAR = 'SCALAR';
13+
const LIST = 'LIST';
14+
const NON_NULL = 'NON_NULL';
15+
const OBJECT = 'OBJECT';
16+
const INPUT_OBJECT = 'INPUT_OBJECT';
17+
const ENUM_OBJECT = 'ENUM';
18+
const UNION_OBJECT = 'UNION';
19+
const INTERFACE_OBJECT = 'INTERFACE';
1920
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
<?php
2+
3+
namespace GraphQL\SchemaGenerator\CodeGenerator;
4+
5+
use GraphQL\Enumeration\FieldTypeKindEnum;
6+
use GraphQL\SchemaGenerator\CodeGenerator\CodeFile\ClassFile;
7+
use GraphQL\Util\StringLiteralFormatter;
8+
9+
/**
10+
* Class InterfaceObjectClassBuilder
11+
*
12+
* @package GraphQL\SchemaManager\CodeGenerator
13+
*/
14+
class InterfaceObjectClassBuilder extends ObjectClassBuilder
15+
{
16+
/**
17+
* InterfaceObjectClassBuilder constructor.
18+
*
19+
* @param string $writeDir
20+
* @param string $objectName
21+
* @param string $namespace
22+
*/
23+
public function __construct(string $writeDir, string $objectName, string $namespace = self::DEFAULT_NAMESPACE)
24+
{
25+
$className = $objectName . 'QueryObject';
26+
27+
$this->classFile = new ClassFile($writeDir, $className);
28+
$this->classFile->setNamespace($namespace);
29+
if ($namespace !== self::DEFAULT_NAMESPACE) {
30+
$this->classFile->addImport('GraphQL\\SchemaObject\\UnionObject');
31+
}
32+
$this->classFile->extendsClass('UnionObject');
33+
34+
$this->classFile->addConstant('OBJECT_NAME', $objectName);
35+
}
36+
37+
/**
38+
* @param string $fieldName
39+
*/
40+
public function addScalarField(string $fieldName, bool $isDeprecated, ?string $deprecationReason)
41+
{
42+
$upperCamelCaseProp = StringLiteralFormatter::formatUpperCamelCase($fieldName);
43+
$this->addSimpleSelector($fieldName, $upperCamelCaseProp, $isDeprecated, $deprecationReason);
44+
}
45+
46+
/**
47+
* @param string $fieldName
48+
* @param string $typeName
49+
* @param string $typeKind
50+
* @param string $argsObjectName
51+
* @param bool $isDeprecated
52+
* @param string|null $deprecationReason
53+
*/
54+
public function addObjectField(string $fieldName, string $typeName, string $typeKind, string $argsObjectName, bool $isDeprecated, ?string $deprecationReason)
55+
{
56+
$upperCamelCaseProp = StringLiteralFormatter::formatUpperCamelCase($fieldName);
57+
$this->addObjectSelector($fieldName, $upperCamelCaseProp, $typeName, $typeKind, $argsObjectName, $isDeprecated, $deprecationReason);
58+
}
59+
60+
/**
61+
* @param string $propertyName
62+
* @param string $upperCamelName
63+
* @param bool $isDeprecated
64+
* @param string|null $deprecationReason
65+
*/
66+
protected function addSimpleSelector(string $propertyName, string $upperCamelName, bool $isDeprecated, ?string $deprecationReason)
67+
{
68+
$method = "public function select$upperCamelName()
69+
{
70+
\$this->selectField(\"$propertyName\");
71+
72+
return \$this;
73+
}";
74+
$this->classFile->addMethod($method, $isDeprecated, $deprecationReason);
75+
}
76+
77+
/**
78+
* @param string $fieldName
79+
* @param string $upperCamelName
80+
* @param string $fieldTypeName
81+
* @param string $fieldTypeKind
82+
* @param string $argsObjectName
83+
* @param bool $isDeprecated
84+
* @param string|null $deprecationReason
85+
*/
86+
protected function addObjectSelector(string $fieldName, string $upperCamelName, string $fieldTypeName, string $fieldTypeKind, string $argsObjectName, bool $isDeprecated, ?string $deprecationReason)
87+
{
88+
$objectClass = $fieldTypeName . ($fieldTypeKind === FieldTypeKindEnum::UNION_OBJECT ? 'UnionObject' : 'QueryObject');
89+
$method = "public function select$upperCamelName($argsObjectName \$argsObject = null)
90+
{
91+
\$object = new $objectClass(\"$fieldName\");
92+
if (\$argsObject !== null) {
93+
\$object->appendArguments(\$argsObject->toArray());
94+
}
95+
\$this->selectField(\$object);
96+
97+
return \$object;
98+
}";
99+
$this->classFile->addMethod($method, $isDeprecated, $deprecationReason);
100+
}
101+
102+
103+
/**
104+
* @param string $typeName
105+
*/
106+
public function addPossibleType(string $typeName)
107+
{
108+
$upperCamelCaseTypeName = StringLiteralFormatter::formatUpperCamelCase($typeName);
109+
$objectClassName = $typeName . 'QueryObject';
110+
$method = "public function on$upperCamelCaseTypeName()
111+
{
112+
\$object = new $objectClassName();
113+
\$this->addPossibleType(\$object);
114+
115+
return \$object;
116+
}";
117+
$this->classFile->addMethod($method);
118+
}
119+
120+
/**
121+
* This method builds the class and writes it to the file system
122+
*/
123+
public function build(): void
124+
{
125+
$this->classFile->writeFile();
126+
}
127+
}

src/SchemaGenerator/CodeGenerator/QueryObjectClassBuilder.php

+17
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,23 @@ protected function addObjectSelector(string $fieldName, string $upperCamelName,
104104
$this->classFile->addMethod($method, $isDeprecated, $deprecationReason);
105105
}
106106

107+
/**
108+
* @param string $typeName
109+
*/
110+
public function addPossibleType(string $typeName)
111+
{
112+
$upperCamelCaseTypeName = StringLiteralFormatter::formatUpperCamelCase($typeName);
113+
$objectClassName = $typeName . 'QueryObject';
114+
$method = "public function on$upperCamelCaseTypeName()
115+
{
116+
\$object = new $objectClassName();
117+
\$this->addPossibleType(\$object);
118+
119+
return \$object;
120+
}";
121+
$this->classFile->addMethod($method);
122+
}
123+
107124
/**
108125
* This method builds the class and writes it to the file system
109126
*/

src/SchemaGenerator/SchemaClassGenerator.php

+37-4
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@
77
use GraphQL\SchemaGenerator\CodeGenerator\ArgumentsObjectClassBuilder;
88
use GraphQL\SchemaGenerator\CodeGenerator\EnumObjectBuilder;
99
use GraphQL\SchemaGenerator\CodeGenerator\InputObjectClassBuilder;
10+
use GraphQL\SchemaGenerator\CodeGenerator\InterfaceObjectClassBuilder;
1011
use GraphQL\SchemaGenerator\CodeGenerator\ObjectBuilderInterface;
12+
use GraphQL\SchemaGenerator\CodeGenerator\ObjectClassBuilder;
1113
use GraphQL\SchemaGenerator\CodeGenerator\QueryObjectClassBuilder;
1214
use GraphQL\SchemaGenerator\CodeGenerator\UnionObjectBuilder;
1315
use GraphQL\SchemaObject\QueryObject;
@@ -88,11 +90,11 @@ public function generateRootQueryObject(): bool
8890
/**
8991
* This method receives the array of object fields as an input and adds the fields to the query object building
9092
*
91-
* @param QueryObjectClassBuilder $queryObjectBuilder
92-
* @param string $currentTypeName
93-
* @param array $fieldsArray
93+
* @param ObjectClassBuilder $queryObjectBuilder
94+
* @param string $currentTypeName
95+
* @param array $fieldsArray
9496
*/
95-
private function appendQueryObjectFields(QueryObjectClassBuilder $queryObjectBuilder, string $currentTypeName, array $fieldsArray)
97+
private function appendQueryObjectFields(ObjectClassBuilder $queryObjectBuilder, string $currentTypeName, array $fieldsArray)
9698
{
9799
foreach ($fieldsArray as $fieldArray) {
98100
$name = $fieldArray['name'];
@@ -143,6 +145,8 @@ protected function generateObject(string $objectName, string $objectKind): bool
143145
return $this->generateEnumObject($objectName);
144146
case FieldTypeKindEnum::UNION_OBJECT:
145147
return $this->generateUnionObject($objectName);
148+
case FieldTypeKindEnum::INTERFACE_OBJECT:
149+
return $this->generateInterfaceObject($objectName);
146150
default:
147151
print "Couldn't generate type $objectName: generating $objectKind kind is not supported yet" . PHP_EOL;
148152
return false;
@@ -269,6 +273,35 @@ protected function generateUnionObject(string $objectName): bool
269273
return true;
270274
}
271275

276+
/**
277+
* @param string $objectName
278+
*
279+
* @return bool
280+
*/
281+
protected function generateInterfaceObject(string $objectName): bool
282+
{
283+
if (array_key_exists($objectName, $this->generatedObjects)) {
284+
return true;
285+
}
286+
287+
$this->generatedObjects[$objectName] = true;
288+
289+
$objectArray = $this->schemaInspector->getInterfaceObjectSchema($objectName);
290+
$objectName = $objectArray['name'];
291+
$objectBuilder = new InterfaceObjectClassBuilder($this->writeDir, $objectName, $this->generationNamespace);
292+
293+
$this->appendQueryObjectFields($objectBuilder, $objectName, $objectArray['fields']);
294+
295+
foreach ($objectArray['possibleTypes'] as $possibleType) {
296+
$this->generateObject($possibleType['name'], $possibleType['kind']);
297+
$objectBuilder->addPossibleType($possibleType['name']);
298+
}
299+
300+
$objectBuilder->build();
301+
302+
return true;
303+
}
304+
272305
/**
273306
* @param string $argsObjectName
274307
* @param array $arguments

src/SchemaGenerator/SchemaInspector.php

+35
Original file line numberDiff line numberDiff line change
@@ -183,4 +183,39 @@ public function getUnionObjectSchema(string $objectName): array
183183

184184
return $response->getData()['__type'];
185185
}
186+
187+
/**
188+
* @param string $objectName
189+
*
190+
* @return array
191+
*/
192+
public function getInterfaceObjectSchema(string $objectName): array
193+
{
194+
$schemaQuery = "{
195+
__type(name: \"$objectName\") {
196+
name
197+
kind
198+
fields(includeDeprecated: true){
199+
name
200+
description
201+
isDeprecated
202+
deprecationReason
203+
" . static::TYPE_SUB_QUERY . "
204+
args{
205+
name
206+
description
207+
defaultValue
208+
" . static::TYPE_SUB_QUERY . "
209+
}
210+
}
211+
possibleTypes {
212+
kind
213+
name
214+
}
215+
}
216+
}";
217+
$response = $this->client->runRawQuery($schemaQuery, true);
218+
219+
return $response->getData()['__type'];
220+
}
186221
}

src/SchemaObject/UnionObject.php

-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
namespace GraphQL\SchemaObject;
44

55
use GraphQL\InlineFragment;
6-
use GraphQL\Query;
76

87
/**
98
* Class UnionObject

0 commit comments

Comments
 (0)