From a1f9a1b90c59fc5bf31fbfad2c8fd78d5d2d0224 Mon Sep 17 00:00:00 2001 From: Jorrit Schippers Date: Fri, 23 Aug 2024 15:02:08 +0200 Subject: [PATCH] Add support for mutations --- .../CodeGenerator/QueryObjectClassBuilder.php | 7 +- src/SchemaGenerator/SchemaClassGenerator.php | 95 ++++++++++++------- src/SchemaGenerator/SchemaInspector.php | 7 +- src/SchemaObject/QueryObject.php | 7 ++ tests/SchemaClassGeneratorTest.php | 37 +++++++- .../mutation_objects/RootMutationObject.php | 10 ++ 6 files changed, 123 insertions(+), 40 deletions(-) create mode 100644 tests/files_expected/mutation_objects/RootMutationObject.php diff --git a/src/SchemaGenerator/CodeGenerator/QueryObjectClassBuilder.php b/src/SchemaGenerator/CodeGenerator/QueryObjectClassBuilder.php index 087d01f..3b97a07 100644 --- a/src/SchemaGenerator/CodeGenerator/QueryObjectClassBuilder.php +++ b/src/SchemaGenerator/CodeGenerator/QueryObjectClassBuilder.php @@ -23,7 +23,12 @@ class QueryObjectClassBuilder extends ObjectClassBuilder */ public function __construct(string $writeDir, string $objectName, string $namespace = self::DEFAULT_NAMESPACE) { - $className = $objectName . 'QueryObject'; + if ($objectName === QueryObject::ROOT_MUTATION_OBJECT_NAME) { + $objectName = ''; + $className = 'RootMutationObject'; + } else { + $className = $objectName . 'QueryObject'; + } $this->classFile = new ClassFile($writeDir, $className); $this->classFile->setNamespace($namespace); diff --git a/src/SchemaGenerator/SchemaClassGenerator.php b/src/SchemaGenerator/SchemaClassGenerator.php index c37348d..be4a0bd 100644 --- a/src/SchemaGenerator/SchemaClassGenerator.php +++ b/src/SchemaGenerator/SchemaClassGenerator.php @@ -9,6 +9,7 @@ use GraphQL\SchemaGenerator\CodeGenerator\InputObjectClassBuilder; use GraphQL\SchemaGenerator\CodeGenerator\InterfaceObjectBuilder; use GraphQL\SchemaGenerator\CodeGenerator\ObjectBuilderInterface; +use GraphQL\SchemaGenerator\CodeGenerator\ObjectClassBuilder; use GraphQL\SchemaGenerator\CodeGenerator\QueryObjectClassBuilder; use GraphQL\SchemaGenerator\CodeGenerator\UnionObjectBuilder; use GraphQL\SchemaObject\QueryObject; @@ -32,12 +33,12 @@ class SchemaClassGenerator /** * @var string */ - private $writeDir; + private $writeDir; /** * @var string */ - private $generationNamespace; + private $generationNamespace; /** * This array is used as a set to store the already generated objects @@ -54,24 +55,53 @@ class SchemaClassGenerator * @param string $writeDir * @param string $namespace */ - public function __construct(Client $client, string $writeDir = '', string $namespace = ObjectBuilderInterface::DEFAULT_NAMESPACE) + public function __construct(Client $client, string $writeDir = '', string $namespace = ObjectBuilderInterface::DEFAULT_NAMESPACE) { - $this->schemaInspector = new SchemaInspector($client); - $this->generatedObjects = []; - $this->writeDir = $writeDir; + $this->schemaInspector = new SchemaInspector($client); + $this->generatedObjects = []; + $this->writeDir = $writeDir; $this->generationNamespace = $namespace; $this->setWriteDir(); } + public function generateRootObjects(): bool + { + $this->generateRootQueryObject(); + $this->generateRootMutationObject(); + + return true; + } + /** * @return bool */ - public function generateRootQueryObject(): bool - { - $objectArray = $this->schemaInspector->getQueryTypeSchema(); + public function generateRootQueryObject(): bool + { + $objectArray = $this->schemaInspector->getRootSchema('query'); $rootObjectName = QueryObject::ROOT_QUERY_OBJECT_NAME; - $queryTypeName = $objectArray['name']; - //$rootObjectDescr = $objectArray['description']; + $queryTypeName = $objectArray['name']; + + if (array_key_exists($queryTypeName, $this->generatedObjects)) { + return true; + } + + $this->generatedObjects[$queryTypeName] = true; + + $queryObjectBuilder = new QueryObjectClassBuilder($this->writeDir, $rootObjectName, $this->generationNamespace); + $this->appendObjectFields($queryObjectBuilder, $rootObjectName, $objectArray['fields']); + $queryObjectBuilder->build(); + + return true; + } + + /** + * @return bool + */ + public function generateRootMutationObject(): bool + { + $objectArray = $this->schemaInspector->getRootSchema('mutation'); + $rootObjectName = QueryObject::ROOT_MUTATION_OBJECT_NAME; + $queryTypeName = $objectArray['name']; if (array_key_exists($queryTypeName, $this->generatedObjects)) { return true; @@ -80,7 +110,7 @@ public function generateRootQueryObject(): bool $this->generatedObjects[$queryTypeName] = true; $queryObjectBuilder = new QueryObjectClassBuilder($this->writeDir, $rootObjectName, $this->generationNamespace); - $this->appendQueryObjectFields($queryObjectBuilder, $rootObjectName, $objectArray['fields']); + $this->appendObjectFields($queryObjectBuilder, $rootObjectName, $objectArray['fields']); $queryObjectBuilder->build(); return true; @@ -89,18 +119,17 @@ public function generateRootQueryObject(): bool /** * This method receives the array of object fields as an input and adds the fields to the query object building * - * @param QueryObjectClassBuilder $queryObjectBuilder - * @param string $currentTypeName - * @param array $fieldsArray + * @param ObjectClassBuilder $queryObjectBuilder + * @param string $currentTypeName + * @param array $fieldsArray */ - private function appendQueryObjectFields(QueryObjectClassBuilder $queryObjectBuilder, string $currentTypeName, array $fieldsArray) + private function appendObjectFields(ObjectClassBuilder $queryObjectBuilder, string $currentTypeName, array $fieldsArray) { foreach ($fieldsArray as $fieldArray) { $name = $fieldArray['name']; - // Skip fields with name "query" - if ($name === 'query') continue; + // Skip fields with name "query" or "field" + if ($name === 'query' || $name === 'field') continue; - //$description = $fieldArray['description']; [$typeName, $typeKind] = $this->getTypeInfo($fieldArray); if ($typeKind === FieldTypeKindEnum::SCALAR) { @@ -168,8 +197,8 @@ protected function generateQueryObject(string $objectName): bool } $this->generatedObjects[$objectName] = true; - $objectArray = $this->schemaInspector->getObjectSchema($objectName); - $objectName = $objectArray['name']; + $objectArray = $this->schemaInspector->getObjectSchema($objectName); + $objectName = $objectArray['name']; if ($objectArray['kind'] === FieldTypeKindEnum::INTERFACE_OBJECT) { $objectBuilder = new InterfaceObjectBuilder($this->writeDir, $objectName, $this->generationNamespace); @@ -180,7 +209,7 @@ protected function generateQueryObject(string $objectName): bool $objectBuilder = new QueryObjectClassBuilder($this->writeDir, $objectName, $this->generationNamespace); } - $this->appendQueryObjectFields($objectBuilder, $objectName, $objectArray['fields']); + $this->appendObjectFields($objectBuilder, $objectName, $objectArray['fields']); $objectBuilder->build(); return true; @@ -198,8 +227,8 @@ protected function generateInputObject(string $objectName): bool } $this->generatedObjects[$objectName] = true; - $objectArray = $this->schemaInspector->getInputObjectSchema($objectName); - $objectName = $objectArray['name']; + $objectArray = $this->schemaInspector->getInputObjectSchema($objectName); + $objectName = $objectArray['name']; $objectBuilder = new InputObjectClassBuilder($this->writeDir, $objectName, $this->generationNamespace); foreach ($objectArray['inputFields'] as $inputFieldArray) { @@ -244,12 +273,12 @@ protected function generateEnumObject(string $objectName): bool $this->generatedObjects[$objectName] = true; - $objectArray = $this->schemaInspector->getEnumObjectSchema($objectName); - $objectName = $objectArray['name']; + $objectArray = $this->schemaInspector->getEnumObjectSchema($objectName); + $objectName = $objectArray['name']; $objectBuilder = new EnumObjectBuilder($this->writeDir, $objectName, $this->generationNamespace); foreach ($objectArray['enumValues'] as $enumValue) { - $name = $enumValue['name']; + $name = $enumValue['name']; //$description = $enumValue['description']; $objectBuilder->addEnumValue($name); } @@ -271,8 +300,8 @@ protected function generateUnionObject(string $objectName): bool $this->generatedObjects[$objectName] = true; - $objectArray = $this->schemaInspector->getUnionObjectSchema($objectName); - $objectName = $objectArray['name']; + $objectArray = $this->schemaInspector->getUnionObjectSchema($objectName); + $objectName = $objectArray['name']; $objectBuilder = new UnionObjectBuilder($this->writeDir, $objectName, $this->generationNamespace); foreach ($objectArray['possibleTypes'] as $possibleType) { @@ -297,8 +326,8 @@ protected function generateInterfaceObject(string $objectName): bool $this->generatedObjects[$objectName] = true; - $objectArray = $this->schemaInspector->getObjectSchema($objectName); - $objectName = $objectArray['name']; + $objectArray = $this->schemaInspector->getObjectSchema($objectName); + $objectName = $objectArray['name']; $objectBuilder = new UnionObjectBuilder($this->writeDir, $objectName, $this->generationNamespace); foreach ($objectArray['possibleTypes'] as $possibleType) { @@ -312,7 +341,7 @@ protected function generateInterfaceObject(string $objectName): bool /** * @param string $argsObjectName - * @param array $arguments + * @param array $arguments * * @return bool */ @@ -382,7 +411,7 @@ protected function getTypeInfo(array $dataArray): array /** * Sets the write directory if it's not set for the class */ - private function setWriteDir(): void + private function setWriteDir(): void { if ($this->writeDir !== '') return; diff --git a/src/SchemaGenerator/SchemaInspector.php b/src/SchemaGenerator/SchemaInspector.php index 9c80e32..d9fb815 100644 --- a/src/SchemaGenerator/SchemaInspector.php +++ b/src/SchemaGenerator/SchemaInspector.php @@ -54,13 +54,14 @@ public function __construct(Client $client) } /** + * @param string $type query or mutation * @return array */ - public function getQueryTypeSchema(): array + public function getRootSchema(string $type): array { $schemaQuery = "{ __schema{ - queryType{ + ${type}Type{ name kind description @@ -82,7 +83,7 @@ public function getQueryTypeSchema(): array }"; $response = $this->client->runRawQuery($schemaQuery, true); - return $response->getData()['__schema']['queryType']; + return $response->getData()['__schema'][$type.'Type']; } /** diff --git a/src/SchemaObject/QueryObject.php b/src/SchemaObject/QueryObject.php index 42b54b4..d1adcd3 100644 --- a/src/SchemaObject/QueryObject.php +++ b/src/SchemaObject/QueryObject.php @@ -21,6 +21,13 @@ abstract class QueryObject extends AbstractQueryBuilder */ public const ROOT_QUERY_OBJECT_NAME = 'Root'; + /** + * This constant stores the name to be given to the root query object + * + * @var string + */ + public const ROOT_MUTATION_OBJECT_NAME = 'RootMutation'; + /** * This constant stores the name of the object name in the API definition * diff --git a/tests/SchemaClassGeneratorTest.php b/tests/SchemaClassGeneratorTest.php index b2d6568..7198fd5 100644 --- a/tests/SchemaClassGeneratorTest.php +++ b/tests/SchemaClassGeneratorTest.php @@ -616,7 +616,7 @@ public function testGenerateArgumentsObjectWithInputObjectArgs() /** * @covers \GraphQL\SchemaGenerator\SchemaClassGenerator::generateQueryObject - * @covers \GraphQL\SchemaGenerator\SchemaClassGenerator::appendQueryObjectFields + * @covers \GraphQL\SchemaGenerator\SchemaClassGenerator::appendObjectFields * @covers \GraphQL\SchemaGenerator\SchemaClassGenerator::generateObject */ public function testGenerateQueryObjectWithScalarFields() @@ -703,7 +703,7 @@ public function testGenerateQueryObjectWithScalarFields() /** * @covers \GraphQL\SchemaGenerator\SchemaClassGenerator::generateQueryObject - * @covers \GraphQL\SchemaGenerator\SchemaClassGenerator::appendQueryObjectFields + * @covers \GraphQL\SchemaGenerator\SchemaClassGenerator::appendObjectFields * @covers \GraphQL\SchemaGenerator\SchemaClassGenerator::generateObject */ public function testGenerateQueryObjectWithObjectFields() @@ -790,7 +790,7 @@ public function testGenerateQueryObjectWithObjectFields() /** * @covers \GraphQL\SchemaGenerator\SchemaClassGenerator::generateRootQueryObject */ - public function testGenerateRootObject() + public function testGenerateRootQueryObject() { $this->mockHandler->append(new Response(200, [], json_encode([ 'data' => [ @@ -813,6 +813,32 @@ public function testGenerateRootObject() ); } + /** + * @covers \GraphQL\SchemaGenerator\SchemaClassGenerator::generateRootQueryObject + */ + public function testGenerateRootMutationObject() + { + $this->mockHandler->append(new Response(200, [], json_encode([ + 'data' => [ + '__schema' => [ + 'mutationType' => [ + 'name' => 'Mutation', + 'kind' => FieldTypeKindEnum::OBJECT, + 'description' => null, + 'fields' => [] + ] + ] + ] + ]))); + $this->classGenerator->generateRootMutationObject(); + + $objectName = 'RootMutationObject'; + $this->assertFileEquals( + static::getExpectedFilesDir() . "/mutation_objects/$objectName.php", + static::getGeneratedFilesDir() . "/$objectName.php" + ); + } + /** * @covers \GraphQL\SchemaGenerator\SchemaClassGenerator::generateUnionObject */ @@ -1010,6 +1036,11 @@ public function generateRootQueryObject(): bool return parent::generateRootQueryObject(); } + public function generateRootMutationObject(): bool + { + return parent::generateRootMutationObject(); + } + public function generateQueryObject(string $objectName): bool { return parent::generateQueryObject($objectName); diff --git a/tests/files_expected/mutation_objects/RootMutationObject.php b/tests/files_expected/mutation_objects/RootMutationObject.php new file mode 100644 index 0000000..0d036bf --- /dev/null +++ b/tests/files_expected/mutation_objects/RootMutationObject.php @@ -0,0 +1,10 @@ +