Skip to content

Commit 5d8684d

Browse files
committed
Add support for mutations
1 parent 17d9a75 commit 5d8684d

File tree

6 files changed

+136
-45
lines changed

6 files changed

+136
-45
lines changed

src/SchemaGenerator/CodeGenerator/QueryObjectClassBuilder.php

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@
1414
*/
1515
class QueryObjectClassBuilder extends ObjectClassBuilder
1616
{
17+
/**
18+
* @var bool
19+
*/
20+
private $isRootMutation = false;
21+
1722
/**
1823
* QueryObjectClassBuilder constructor.
1924
*
@@ -23,7 +28,13 @@ class QueryObjectClassBuilder extends ObjectClassBuilder
2328
*/
2429
public function __construct(string $writeDir, string $objectName, string $namespace = self::DEFAULT_NAMESPACE)
2530
{
26-
$className = $objectName . 'QueryObject';
31+
if ($objectName === QueryObject::ROOT_MUTATION_OBJECT_NAME) {
32+
$objectName = '';
33+
$className = 'RootMutationObject';
34+
$this->isRootMutation = true;
35+
} else {
36+
$className = $objectName . 'QueryObject';
37+
}
2738

2839
$this->classFile = new ClassFile($writeDir, $className);
2940
$this->classFile->setNamespace($namespace);
@@ -68,11 +79,12 @@ public function addObjectField(string $fieldName, string $typeName, string $type
6879
* @param bool $isDeprecated
6980
* @param string|null $deprecationReason
7081
*/
71-
protected function addSimpleSelector(string $propertyName, string $upperCamelName, bool $isDeprecated, ?string $deprecationReason)
82+
protected function addSimpleSelector(string $fieldName, string $upperCamelName, bool $isDeprecated, ?string $deprecationReason)
7283
{
73-
$method = "public function select$upperCamelName()
84+
$methodName = $this->isRootMutation ? $fieldName : 'select'.$upperCamelName;
85+
$method = "public function $methodName()
7486
{
75-
\$this->selectField(\"$propertyName\");
87+
\$this->selectField(\"$fieldName\");
7688
7789
return \$this;
7890
}";
@@ -90,18 +102,19 @@ protected function addSimpleSelector(string $propertyName, string $upperCamelNam
90102
*/
91103
protected function addObjectSelector(string $fieldName, string $upperCamelName, string $fieldTypeName, string $fieldTypeKind, ?string $argsObjectName, bool $isDeprecated, ?string $deprecationReason)
92104
{
105+
$methodName = $this->isRootMutation ? $fieldName : 'select'.$upperCamelName;
93106
$objectClass = $fieldTypeName . ($fieldTypeKind === FieldTypeKindEnum::UNION_OBJECT ? 'UnionObject' : 'QueryObject');
94107

95108
if ($argsObjectName === null) {
96-
$method = "public function select$upperCamelName()
109+
$method = "public function $methodName()
97110
{
98111
\$object = new $objectClass(\"$fieldName\");
99112
\$this->selectField(\$object);
100113
101114
return \$object;
102115
}";
103116
} else {
104-
$method = "public function select$upperCamelName($argsObjectName \$argsObject = null)
117+
$method = "public function $methodName($argsObjectName \$argsObject = null)
105118
{
106119
\$object = new $objectClass(\"$fieldName\");
107120
if (\$argsObject !== null) {

src/SchemaGenerator/SchemaClassGenerator.php

Lines changed: 62 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
use GraphQL\SchemaGenerator\CodeGenerator\InputObjectClassBuilder;
1010
use GraphQL\SchemaGenerator\CodeGenerator\InterfaceObjectBuilder;
1111
use GraphQL\SchemaGenerator\CodeGenerator\ObjectBuilderInterface;
12+
use GraphQL\SchemaGenerator\CodeGenerator\ObjectClassBuilder;
1213
use GraphQL\SchemaGenerator\CodeGenerator\QueryObjectClassBuilder;
1314
use GraphQL\SchemaGenerator\CodeGenerator\UnionObjectBuilder;
1415
use GraphQL\SchemaObject\QueryObject;
@@ -32,12 +33,12 @@ class SchemaClassGenerator
3233
/**
3334
* @var string
3435
*/
35-
private $writeDir;
36+
private $writeDir;
3637

3738
/**
3839
* @var string
3940
*/
40-
private $generationNamespace;
41+
private $generationNamespace;
4142

4243
/**
4344
* This array is used as a set to store the already generated objects
@@ -54,24 +55,53 @@ class SchemaClassGenerator
5455
* @param string $writeDir
5556
* @param string $namespace
5657
*/
57-
public function __construct(Client $client, string $writeDir = '', string $namespace = ObjectBuilderInterface::DEFAULT_NAMESPACE)
58+
public function __construct(Client $client, string $writeDir = '', string $namespace = ObjectBuilderInterface::DEFAULT_NAMESPACE)
5859
{
59-
$this->schemaInspector = new SchemaInspector($client);
60-
$this->generatedObjects = [];
61-
$this->writeDir = $writeDir;
60+
$this->schemaInspector = new SchemaInspector($client);
61+
$this->generatedObjects = [];
62+
$this->writeDir = $writeDir;
6263
$this->generationNamespace = $namespace;
6364
$this->setWriteDir();
6465
}
6566

67+
public function generateRootObjects(): bool
68+
{
69+
$this->generateRootQueryObject();
70+
$this->generateRootMutationObject();
71+
72+
return true;
73+
}
74+
6675
/**
6776
* @return bool
6877
*/
69-
public function generateRootQueryObject(): bool
70-
{
71-
$objectArray = $this->schemaInspector->getQueryTypeSchema();
78+
public function generateRootQueryObject(): bool
79+
{
80+
$objectArray = $this->schemaInspector->getRootSchema('query');
7281
$rootObjectName = QueryObject::ROOT_QUERY_OBJECT_NAME;
73-
$queryTypeName = $objectArray['name'];
74-
//$rootObjectDescr = $objectArray['description'];
82+
$queryTypeName = $objectArray['name'];
83+
84+
if (array_key_exists($queryTypeName, $this->generatedObjects)) {
85+
return true;
86+
}
87+
88+
$this->generatedObjects[$queryTypeName] = true;
89+
90+
$queryObjectBuilder = new QueryObjectClassBuilder($this->writeDir, $rootObjectName, $this->generationNamespace);
91+
$this->appendObjectFields($queryObjectBuilder, $rootObjectName, $objectArray['fields']);
92+
$queryObjectBuilder->build();
93+
94+
return true;
95+
}
96+
97+
/**
98+
* @return bool
99+
*/
100+
public function generateRootMutationObject(): bool
101+
{
102+
$objectArray = $this->schemaInspector->getRootSchema('mutation');
103+
$rootObjectName = QueryObject::ROOT_MUTATION_OBJECT_NAME;
104+
$queryTypeName = $objectArray['name'];
75105

76106
if (array_key_exists($queryTypeName, $this->generatedObjects)) {
77107
return true;
@@ -80,7 +110,7 @@ public function generateRootQueryObject(): bool
80110
$this->generatedObjects[$queryTypeName] = true;
81111

82112
$queryObjectBuilder = new QueryObjectClassBuilder($this->writeDir, $rootObjectName, $this->generationNamespace);
83-
$this->appendQueryObjectFields($queryObjectBuilder, $rootObjectName, $objectArray['fields']);
113+
$this->appendObjectFields($queryObjectBuilder, $rootObjectName, $objectArray['fields']);
84114
$queryObjectBuilder->build();
85115

86116
return true;
@@ -89,18 +119,17 @@ public function generateRootQueryObject(): bool
89119
/**
90120
* This method receives the array of object fields as an input and adds the fields to the query object building
91121
*
92-
* @param QueryObjectClassBuilder $queryObjectBuilder
93-
* @param string $currentTypeName
94-
* @param array $fieldsArray
122+
* @param ObjectClassBuilder $queryObjectBuilder
123+
* @param string $currentTypeName
124+
* @param array $fieldsArray
95125
*/
96-
private function appendQueryObjectFields(QueryObjectClassBuilder $queryObjectBuilder, string $currentTypeName, array $fieldsArray)
126+
private function appendObjectFields(ObjectClassBuilder $queryObjectBuilder, string $currentTypeName, array $fieldsArray)
97127
{
98128
foreach ($fieldsArray as $fieldArray) {
99129
$name = $fieldArray['name'];
100-
// Skip fields with name "query"
101-
if ($name === 'query') continue;
130+
// Skip fields with name "query" or "field"
131+
if ($name === 'query' || $name === 'field') continue;
102132

103-
//$description = $fieldArray['description'];
104133
[$typeName, $typeKind] = $this->getTypeInfo($fieldArray);
105134

106135
if ($typeKind === FieldTypeKindEnum::SCALAR) {
@@ -168,8 +197,8 @@ protected function generateQueryObject(string $objectName): bool
168197
}
169198

170199
$this->generatedObjects[$objectName] = true;
171-
$objectArray = $this->schemaInspector->getObjectSchema($objectName);
172-
$objectName = $objectArray['name'];
200+
$objectArray = $this->schemaInspector->getObjectSchema($objectName);
201+
$objectName = $objectArray['name'];
173202

174203
if ($objectArray['kind'] === FieldTypeKindEnum::INTERFACE_OBJECT) {
175204
$objectBuilder = new InterfaceObjectBuilder($this->writeDir, $objectName, $this->generationNamespace);
@@ -180,7 +209,7 @@ protected function generateQueryObject(string $objectName): bool
180209
$objectBuilder = new QueryObjectClassBuilder($this->writeDir, $objectName, $this->generationNamespace);
181210
}
182211

183-
$this->appendQueryObjectFields($objectBuilder, $objectName, $objectArray['fields']);
212+
$this->appendObjectFields($objectBuilder, $objectName, $objectArray['fields']);
184213
$objectBuilder->build();
185214

186215
return true;
@@ -198,8 +227,8 @@ protected function generateInputObject(string $objectName): bool
198227
}
199228

200229
$this->generatedObjects[$objectName] = true;
201-
$objectArray = $this->schemaInspector->getInputObjectSchema($objectName);
202-
$objectName = $objectArray['name'];
230+
$objectArray = $this->schemaInspector->getInputObjectSchema($objectName);
231+
$objectName = $objectArray['name'];
203232
$objectBuilder = new InputObjectClassBuilder($this->writeDir, $objectName, $this->generationNamespace);
204233

205234
foreach ($objectArray['inputFields'] as $inputFieldArray) {
@@ -244,12 +273,12 @@ protected function generateEnumObject(string $objectName): bool
244273

245274
$this->generatedObjects[$objectName] = true;
246275

247-
$objectArray = $this->schemaInspector->getEnumObjectSchema($objectName);
248-
$objectName = $objectArray['name'];
276+
$objectArray = $this->schemaInspector->getEnumObjectSchema($objectName);
277+
$objectName = $objectArray['name'];
249278
$objectBuilder = new EnumObjectBuilder($this->writeDir, $objectName, $this->generationNamespace);
250279

251280
foreach ($objectArray['enumValues'] as $enumValue) {
252-
$name = $enumValue['name'];
281+
$name = $enumValue['name'];
253282
//$description = $enumValue['description'];
254283
$objectBuilder->addEnumValue($name);
255284
}
@@ -271,8 +300,8 @@ protected function generateUnionObject(string $objectName): bool
271300

272301
$this->generatedObjects[$objectName] = true;
273302

274-
$objectArray = $this->schemaInspector->getUnionObjectSchema($objectName);
275-
$objectName = $objectArray['name'];
303+
$objectArray = $this->schemaInspector->getUnionObjectSchema($objectName);
304+
$objectName = $objectArray['name'];
276305
$objectBuilder = new UnionObjectBuilder($this->writeDir, $objectName, $this->generationNamespace);
277306

278307
foreach ($objectArray['possibleTypes'] as $possibleType) {
@@ -297,8 +326,8 @@ protected function generateInterfaceObject(string $objectName): bool
297326

298327
$this->generatedObjects[$objectName] = true;
299328

300-
$objectArray = $this->schemaInspector->getObjectSchema($objectName);
301-
$objectName = $objectArray['name'];
329+
$objectArray = $this->schemaInspector->getObjectSchema($objectName);
330+
$objectName = $objectArray['name'];
302331
$objectBuilder = new UnionObjectBuilder($this->writeDir, $objectName, $this->generationNamespace);
303332

304333
foreach ($objectArray['possibleTypes'] as $possibleType) {
@@ -312,7 +341,7 @@ protected function generateInterfaceObject(string $objectName): bool
312341

313342
/**
314343
* @param string $argsObjectName
315-
* @param array $arguments
344+
* @param array $arguments
316345
*
317346
* @return bool
318347
*/
@@ -382,7 +411,7 @@ protected function getTypeInfo(array $dataArray): array
382411
/**
383412
* Sets the write directory if it's not set for the class
384413
*/
385-
private function setWriteDir(): void
414+
private function setWriteDir(): void
386415
{
387416
if ($this->writeDir !== '') return;
388417

src/SchemaGenerator/SchemaInspector.php

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,13 +54,14 @@ public function __construct(Client $client)
5454
}
5555

5656
/**
57+
* @param string $type query or mutation
5758
* @return array
5859
*/
59-
public function getQueryTypeSchema(): array
60+
public function getRootSchema(string $type): array
6061
{
6162
$schemaQuery = "{
6263
__schema{
63-
queryType{
64+
${type}Type{
6465
name
6566
kind
6667
description
@@ -82,7 +83,7 @@ public function getQueryTypeSchema(): array
8283
}";
8384
$response = $this->client->runRawQuery($schemaQuery, true);
8485

85-
return $response->getData()['__schema']['queryType'];
86+
return $response->getData()['__schema'][$type.'Type'];
8687
}
8788

8889
/**

src/SchemaObject/QueryObject.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,13 @@ abstract class QueryObject extends AbstractQueryBuilder
2121
*/
2222
public const ROOT_QUERY_OBJECT_NAME = 'Root';
2323

24+
/**
25+
* This constant stores the name to be given to the root query object
26+
*
27+
* @var string
28+
*/
29+
public const ROOT_MUTATION_OBJECT_NAME = 'RootMutation';
30+
2431
/**
2532
* This constant stores the name of the object name in the API definition
2633
*

tests/SchemaClassGeneratorTest.php

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -616,7 +616,7 @@ public function testGenerateArgumentsObjectWithInputObjectArgs()
616616

617617
/**
618618
* @covers \GraphQL\SchemaGenerator\SchemaClassGenerator::generateQueryObject
619-
* @covers \GraphQL\SchemaGenerator\SchemaClassGenerator::appendQueryObjectFields
619+
* @covers \GraphQL\SchemaGenerator\SchemaClassGenerator::appendObjectFields
620620
* @covers \GraphQL\SchemaGenerator\SchemaClassGenerator::generateObject
621621
*/
622622
public function testGenerateQueryObjectWithScalarFields()
@@ -703,7 +703,7 @@ public function testGenerateQueryObjectWithScalarFields()
703703

704704
/**
705705
* @covers \GraphQL\SchemaGenerator\SchemaClassGenerator::generateQueryObject
706-
* @covers \GraphQL\SchemaGenerator\SchemaClassGenerator::appendQueryObjectFields
706+
* @covers \GraphQL\SchemaGenerator\SchemaClassGenerator::appendObjectFields
707707
* @covers \GraphQL\SchemaGenerator\SchemaClassGenerator::generateObject
708708
*/
709709
public function testGenerateQueryObjectWithObjectFields()
@@ -790,7 +790,7 @@ public function testGenerateQueryObjectWithObjectFields()
790790
/**
791791
* @covers \GraphQL\SchemaGenerator\SchemaClassGenerator::generateRootQueryObject
792792
*/
793-
public function testGenerateRootObject()
793+
public function testGenerateRootQueryObject()
794794
{
795795
$this->mockHandler->append(new Response(200, [], json_encode([
796796
'data' => [
@@ -813,6 +813,32 @@ public function testGenerateRootObject()
813813
);
814814
}
815815

816+
/**
817+
* @covers \GraphQL\SchemaGenerator\SchemaClassGenerator::generateRootQueryObject
818+
*/
819+
public function testGenerateRootMutationObject()
820+
{
821+
$this->mockHandler->append(new Response(200, [], json_encode([
822+
'data' => [
823+
'__schema' => [
824+
'mutationType' => [
825+
'name' => 'Mutation',
826+
'kind' => FieldTypeKindEnum::OBJECT,
827+
'description' => null,
828+
'fields' => []
829+
]
830+
]
831+
]
832+
])));
833+
$this->classGenerator->generateRootMutationObject();
834+
835+
$objectName = 'RootMutationObject';
836+
$this->assertFileEquals(
837+
static::getExpectedFilesDir() . "/mutation_objects/$objectName.php",
838+
static::getGeneratedFilesDir() . "/$objectName.php"
839+
);
840+
}
841+
816842
/**
817843
* @covers \GraphQL\SchemaGenerator\SchemaClassGenerator::generateUnionObject
818844
*/
@@ -1010,6 +1036,11 @@ public function generateRootQueryObject(): bool
10101036
return parent::generateRootQueryObject();
10111037
}
10121038

1039+
public function generateRootMutationObject(): bool
1040+
{
1041+
return parent::generateRootMutationObject();
1042+
}
1043+
10131044
public function generateQueryObject(string $objectName): bool
10141045
{
10151046
return parent::generateQueryObject($objectName);
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php
2+
3+
namespace GraphQL\Tests\SchemaObject;
4+
5+
use GraphQL\SchemaObject\QueryObject;
6+
7+
class RootMutationObject extends QueryObject
8+
{
9+
const OBJECT_NAME = "";
10+
}

0 commit comments

Comments
 (0)