From 81c80305dff1c8022c364d2f42ed1b4c57d351b0 Mon Sep 17 00:00:00 2001 From: Bozhidar Hristov Date: Mon, 17 Feb 2025 21:32:00 +0200 Subject: [PATCH 1/5] Transfer config in schema extender. --- src/Utils/SchemaExtender.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Utils/SchemaExtender.php b/src/Utils/SchemaExtender.php index 91345c68b..ed3e6c5d3 100644 --- a/src/Utils/SchemaExtender.php +++ b/src/Utils/SchemaExtender.php @@ -497,6 +497,7 @@ protected function extendFieldMap(Type $type): array $field = $oldFieldMap[$fieldName]; $newFieldMap[$fieldName] = [ + ...$field->config, 'name' => $fieldName, 'description' => $field->description, 'deprecationReason' => $field->deprecationReason, From 1cebf292f53df78a8c34f9f6895912d7008087be Mon Sep 17 00:00:00 2001 From: Warxcell <3340882+Warxcell@users.noreply.github.com> Date: Mon, 17 Feb 2025 19:32:55 +0000 Subject: [PATCH 2/5] Apply php-cs-fixer changes --- benchmarks/HugeSchemaBench.php | 4 +-- benchmarks/Utils/SchemaGenerator.php | 2 +- examples/00-hello-world/graphql.php | 4 +-- examples/03-standard-server/graphql.php | 4 +-- src/Executor/ReferenceExecutor.php | 26 +++----------- src/Executor/Values.php | 20 +++-------- src/Language/Lexer.php | 48 +++++-------------------- src/Language/Parser.php | 12 ++----- src/Type/Definition/EnumType.php | 5 +-- src/Utils/ASTDefinitionBuilder.php | 9 +---- src/Utils/BuildClientSchema.php | 12 +++---- src/Utils/BuildSchema.php | 32 ++++++++--------- src/Validator/Rules/QueryComplexity.php | 16 ++------- tests/Executor/ExecutorTest.php | 10 +----- tests/GraphQLTest.php | 22 ++++++------ 15 files changed, 64 insertions(+), 162 deletions(-) diff --git a/benchmarks/HugeSchemaBench.php b/benchmarks/HugeSchemaBench.php index 858d8cd81..fe6bb1821 100644 --- a/benchmarks/HugeSchemaBench.php +++ b/benchmarks/HugeSchemaBench.php @@ -70,8 +70,8 @@ private function createLazySchema(): Schema { return new Schema( (new SchemaConfig()) - ->setQuery($this->schemaGenerator->buildQueryType()) - ->setTypeLoader(fn (string $name): Type => $this->schemaGenerator->loadType($name)) + ->setQuery($this->schemaGenerator->buildQueryType()) + ->setTypeLoader(fn (string $name): Type => $this->schemaGenerator->loadType($name)) ); } } diff --git a/benchmarks/Utils/SchemaGenerator.php b/benchmarks/Utils/SchemaGenerator.php index 71809a58d..298dce943 100644 --- a/benchmarks/Utils/SchemaGenerator.php +++ b/benchmarks/Utils/SchemaGenerator.php @@ -35,7 +35,7 @@ public function buildSchema(): Schema { return new Schema( (new SchemaConfig()) - ->setQuery($this->buildQueryType()) + ->setQuery($this->buildQueryType()) ); } diff --git a/examples/00-hello-world/graphql.php b/examples/00-hello-world/graphql.php index 953571f22..d678a35dd 100644 --- a/examples/00-hello-world/graphql.php +++ b/examples/00-hello-world/graphql.php @@ -49,8 +49,8 @@ // https://webonyx.github.io/graphql-php/schema-definition/#configuration-options $schema = new Schema( (new SchemaConfig()) - ->setQuery($queryType) - ->setMutation($mutationType) + ->setQuery($queryType) + ->setMutation($mutationType) ); $rawInput = file_get_contents('php://input'); diff --git a/examples/03-standard-server/graphql.php b/examples/03-standard-server/graphql.php index 12aaff40d..7937275d6 100644 --- a/examples/03-standard-server/graphql.php +++ b/examples/03-standard-server/graphql.php @@ -48,8 +48,8 @@ // https://webonyx.github.io/graphql-php/schema-definition/#configuration-options $schema = new Schema( (new SchemaConfig()) - ->setQuery($queryType) - ->setMutation($mutationType) + ->setQuery($queryType) + ->setMutation($mutationType) ); $rootValue = ['prefix' => 'You said: ']; diff --git a/src/Executor/ReferenceExecutor.php b/src/Executor/ReferenceExecutor.php index e0b9bc682..c9c8ad202 100644 --- a/src/Executor/ReferenceExecutor.php +++ b/src/Executor/ReferenceExecutor.php @@ -355,10 +355,7 @@ protected function getOperationRootType(Schema $schema, OperationDefinitionNode case 'query': $queryType = $schema->getQueryType(); if ($queryType === null) { - throw new Error( - 'Schema does not define the required query root type.', - [$operation] - ); + throw new Error('Schema does not define the required query root type.', [$operation]); } return $queryType; @@ -366,10 +363,7 @@ protected function getOperationRootType(Schema $schema, OperationDefinitionNode case 'mutation': $mutationType = $schema->getMutationType(); if ($mutationType === null) { - throw new Error( - 'Schema is not configured for mutations.', - [$operation] - ); + throw new Error('Schema is not configured for mutations.', [$operation]); } return $mutationType; @@ -377,19 +371,13 @@ protected function getOperationRootType(Schema $schema, OperationDefinitionNode case 'subscription': $subscriptionType = $schema->getSubscriptionType(); if ($subscriptionType === null) { - throw new Error( - 'Schema is not configured for subscriptions.', - [$operation] - ); + throw new Error('Schema is not configured for subscriptions.', [$operation]); } return $subscriptionType; default: - throw new Error( - 'Can only execute queries, mutations and subscriptions.', - [$operation] - ); + throw new Error('Can only execute queries, mutations and subscriptions.', [$operation]); } } @@ -1075,11 +1063,7 @@ protected function completeLeafValue(LeafType $returnType, &$result) } catch (\Throwable $error) { $safeReturnType = Utils::printSafe($returnType); $safeResult = Utils::printSafe($result); - throw new InvariantViolation( - "Expected a value of type {$safeReturnType} but received: {$safeResult}. {$error->getMessage()}", - 0, - $error - ); + throw new InvariantViolation("Expected a value of type {$safeReturnType} but received: {$safeResult}. {$error->getMessage()}", 0, $error); } } diff --git a/src/Executor/Values.php b/src/Executor/Values.php index bca9a43f0..0e7b0bf98 100644 --- a/src/Executor/Values.php +++ b/src/Executor/Values.php @@ -238,23 +238,14 @@ public static function getArgumentValuesForMap($def, array $argumentValueMap, ?a $safeArgType = Utils::printSafe($argType); if ($isNull) { - throw new Error( - "Argument \"{$name}\" of non-null type \"{$safeArgType}\" must not be null.", - $referenceNode - ); + throw new Error("Argument \"{$name}\" of non-null type \"{$safeArgType}\" must not be null.", $referenceNode); } if ($argumentValueNode instanceof VariableNode) { - throw new Error( - "Argument \"{$name}\" of required type \"{$safeArgType}\" was provided the variable \"\${$argumentValueNode->name->value}\" which was not provided a runtime value.", - [$argumentValueNode] - ); + throw new Error("Argument \"{$name}\" of required type \"{$safeArgType}\" was provided the variable \"\${$argumentValueNode->name->value}\" which was not provided a runtime value.", [$argumentValueNode]); } - throw new Error( - "Argument \"{$name}\" of required type \"{$safeArgType}\" was not provided.", - $referenceNode - ); + throw new Error("Argument \"{$name}\" of required type \"{$safeArgType}\" was not provided.", $referenceNode); } elseif ($hasValue) { assert($argumentValueNode instanceof Node); @@ -275,10 +266,7 @@ public static function getArgumentValuesForMap($def, array $argumentValueMap, ?a // execution. This is a runtime check to ensure execution does not // continue with an invalid argument value. $invalidValue = Printer::doPrint($argumentValueNode); - throw new Error( - "Argument \"{$name}\" has invalid value {$invalidValue}.", - [$argumentValueNode] - ); + throw new Error("Argument \"{$name}\" has invalid value {$invalidValue}.", [$argumentValueNode]); } $coercedValues[$name] = $coercedValue; diff --git a/src/Language/Lexer.php b/src/Language/Lexer.php index cec753d85..93991e22a 100644 --- a/src/Language/Lexer.php +++ b/src/Language/Lexer.php @@ -244,11 +244,7 @@ private function readToken(Token $prev): Token ->readString($line, $col, $prev); } - throw new SyntaxError( - $this->source, - $position, - $this->unexpectedCharacterMessage($code) - ); + throw new SyntaxError($this->source, $position, $this->unexpectedCharacterMessage($code)); } /** @throws \JsonException */ @@ -329,11 +325,7 @@ private function readNumber(int $line, int $col, Token $prev): Token [$char, $code] = $this->moveStringCursor(1, 1)->readChar(); if ($code >= 48 && $code <= 57) { - throw new SyntaxError( - $this->source, - $this->position, - 'Invalid number, unexpected digit after 0: ' . Utils::printCharCode($code) - ); + throw new SyntaxError($this->source, $this->position, 'Invalid number, unexpected digit after 0: ' . Utils::printCharCode($code)); } } else { $value .= $this->readDigits(); @@ -398,11 +390,7 @@ private function readDigits(): string $code = null; } - throw new SyntaxError( - $this->source, - $this->position, - 'Invalid number, expected digit but got: ' . Utils::printCharCode($code) - ); + throw new SyntaxError($this->source, $this->position, 'Invalid number, expected digit but got: ' . Utils::printCharCode($code)); } /** @@ -477,11 +465,7 @@ private function readString(int $line, int $col, Token $prev): Token $position = $this->position; [$hex] = $this->readChars(4); if (\preg_match('/[0-9a-fA-F]{4}/', $hex) !== 1) { - throw new SyntaxError( - $this->source, - $position - 1, - "Invalid character escape sequence: \\u{$hex}" - ); + throw new SyntaxError($this->source, $position - 1, "Invalid character escape sequence: \\u{$hex}"); } $code = \hexdec($hex); @@ -492,11 +476,7 @@ private function readString(int $line, int $col, Token $prev): Token if ($highOrderByte >= 0xD8 && $highOrderByte <= 0xDF) { [$utf16Continuation] = $this->readChars(6); if (\preg_match('/^\\\u[0-9a-fA-F]{4}$/', $utf16Continuation) !== 1) { - throw new SyntaxError( - $this->source, - $this->position - 5, - 'Invalid UTF-16 trailing surrogate: ' . $utf16Continuation - ); + throw new SyntaxError($this->source, $this->position - 5, 'Invalid UTF-16 trailing surrogate: ' . $utf16Continuation); } $surrogatePairHex = $hex . \substr($utf16Continuation, 2, 4); @@ -513,11 +493,7 @@ private function readString(int $line, int $col, Token $prev): Token continue 2; default: $chr = Utils::chr($code); - throw new SyntaxError( - $this->source, - $this->position - 1, - "Invalid character escape sequence: \\{$chr}" - ); + throw new SyntaxError($this->source, $this->position - 1, "Invalid character escape sequence: \\{$chr}"); } $chunk = ''; @@ -528,11 +504,7 @@ private function readString(int $line, int $col, Token $prev): Token [$char, $code, $bytes] = $this->readChar(); } - throw new SyntaxError( - $this->source, - $this->position, - 'Unterminated string.' - ); + throw new SyntaxError($this->source, $this->position, 'Unterminated string.'); } /** @@ -612,11 +584,7 @@ private function readBlockString(int $line, int $col, Token $prev): Token [$char, $code, $bytes] = $this->readChar(); } - throw new SyntaxError( - $this->source, - $this->position, - 'Unterminated string.' - ); + throw new SyntaxError($this->source, $this->position, 'Unterminated string.'); } /** diff --git a/src/Language/Parser.php b/src/Language/Parser.php index 5186fa69e..e387ca06d 100644 --- a/src/Language/Parser.php +++ b/src/Language/Parser.php @@ -379,11 +379,7 @@ private function expect(string $kind): Token return $token; } - throw new SyntaxError( - $this->lexer->source, - $token->start, - "Expected {$kind}, found {$token->getDescription()}" - ); + throw new SyntaxError($this->lexer->source, $token->start, "Expected {$kind}, found {$token->getDescription()}"); } /** @@ -397,11 +393,7 @@ private function expectKeyword(string $value): void { $token = $this->lexer->token; if ($token->kind !== Token::NAME || $token->value !== $value) { - throw new SyntaxError( - $this->lexer->source, - $token->start, - "Expected \"{$value}\", found {$token->getDescription()}" - ); + throw new SyntaxError($this->lexer->source, $token->start, "Expected \"{$value}\", found {$token->getDescription()}"); } $this->lexer->advance(); diff --git a/src/Type/Definition/EnumType.php b/src/Type/Definition/EnumType.php index 567abed8f..4d780862e 100644 --- a/src/Type/Definition/EnumType.php +++ b/src/Type/Definition/EnumType.php @@ -197,10 +197,7 @@ public function parseLiteral(Node $valueNode, ?array $variables = null) { if (! $valueNode instanceof EnumValueNode) { $valueStr = Printer::doPrint($valueNode); - throw new Error( - "Enum \"{$this->name}\" cannot represent non-enum value: {$valueStr}.{$this->didYouMean($valueStr)}", - $valueNode - ); + throw new Error("Enum \"{$this->name}\" cannot represent non-enum value: {$valueStr}.{$this->didYouMean($valueStr)}", $valueNode); } $name = $valueNode->value; diff --git a/src/Utils/ASTDefinitionBuilder.php b/src/Utils/ASTDefinitionBuilder.php index 7dfd7a571..886c4c8b3 100644 --- a/src/Utils/ASTDefinitionBuilder.php +++ b/src/Utils/ASTDefinitionBuilder.php @@ -275,14 +275,7 @@ private function internalBuildType(string $typeName, ?Node $typeNode = null): Ty ); } catch (\Throwable $e) { $class = static::class; - throw new Error( - "Type config decorator passed to {$class} threw an error when building {$typeName} type: {$e->getMessage()}", - null, - null, - [], - null, - $e - ); + throw new Error("Type config decorator passed to {$class} threw an error when building {$typeName} type: {$e->getMessage()}", null, null, [], null, $e); } // @phpstan-ignore-next-line should not happen, but function types are not enforced by PHP diff --git a/src/Utils/BuildClientSchema.php b/src/Utils/BuildClientSchema.php index 231702e40..54b78b7a5 100644 --- a/src/Utils/BuildClientSchema.php +++ b/src/Utils/BuildClientSchema.php @@ -151,12 +151,12 @@ public function buildSchema(): Schema return new Schema( (new SchemaConfig()) - ->setQuery($queryType) - ->setMutation($mutationType) - ->setSubscription($subscriptionType) - ->setTypes($this->typeMap) - ->setDirectives($directives) - ->setAssumeValid($this->options['assumeValid'] ?? false) + ->setQuery($queryType) + ->setMutation($mutationType) + ->setSubscription($subscriptionType) + ->setTypes($this->typeMap) + ->setDirectives($directives) + ->setAssumeValid($this->options['assumeValid'] ?? false) ); } diff --git a/src/Utils/BuildSchema.php b/src/Utils/BuildSchema.php index 87f7d73b9..2d04e4d03 100644 --- a/src/Utils/BuildSchema.php +++ b/src/Utils/BuildSchema.php @@ -245,24 +245,24 @@ static function (string $typeName): Type { return new Schema( (new SchemaConfig()) // @phpstan-ignore-next-line - ->setQuery(isset($operationTypes['query']) - ? $definitionBuilder->maybeBuildType($operationTypes['query']) - : null) + ->setQuery(isset($operationTypes['query']) + ? $definitionBuilder->maybeBuildType($operationTypes['query']) + : null) // @phpstan-ignore-next-line - ->setMutation(isset($operationTypes['mutation']) - ? $definitionBuilder->maybeBuildType($operationTypes['mutation']) - : null) + ->setMutation(isset($operationTypes['mutation']) + ? $definitionBuilder->maybeBuildType($operationTypes['mutation']) + : null) // @phpstan-ignore-next-line - ->setSubscription(isset($operationTypes['subscription']) - ? $definitionBuilder->maybeBuildType($operationTypes['subscription']) - : null) - ->setTypeLoader(static fn (string $name): ?Type => $definitionBuilder->maybeBuildType($name)) - ->setDirectives($directives) - ->setAstNode($schemaDef) - ->setTypes(fn (): array => \array_map( - static fn (TypeDefinitionNode $def): Type => $definitionBuilder->buildType($def->getName()->value), - $typeDefinitionsMap, - )) + ->setSubscription(isset($operationTypes['subscription']) + ? $definitionBuilder->maybeBuildType($operationTypes['subscription']) + : null) + ->setTypeLoader(static fn (string $name): ?Type => $definitionBuilder->maybeBuildType($name)) + ->setDirectives($directives) + ->setAstNode($schemaDef) + ->setTypes(fn (): array => \array_map( + static fn (TypeDefinitionNode $def): Type => $definitionBuilder->buildType($def->getName()->value), + $typeDefinitionsMap, + )) ); } diff --git a/src/Validator/Rules/QueryComplexity.php b/src/Validator/Rules/QueryComplexity.php index 02736ea21..6b00e36c7 100644 --- a/src/Validator/Rules/QueryComplexity.php +++ b/src/Validator/Rules/QueryComplexity.php @@ -179,13 +179,7 @@ protected function directiveExcludesField(FieldNode $node): bool $this->getRawVariableValues() ); if ($errors !== null && $errors !== []) { - throw new Error(\implode( - "\n\n", - \array_map( - static fn (Error $error): string => $error->getMessage(), - $errors - ) - )); + throw new Error(\implode("\n\n", \array_map(static fn (Error $error): string => $error->getMessage(), $errors))); } if ($directiveNode->name->value === Directive::INCLUDE_NAME) { @@ -248,13 +242,7 @@ protected function buildFieldArguments(FieldNode $node): array ); if (is_array($errors) && $errors !== []) { - throw new Error(\implode( - "\n\n", - \array_map( - static fn ($error) => $error->getMessage(), - $errors - ) - )); + throw new Error(\implode("\n\n", \array_map(static fn ($error) => $error->getMessage(), $errors))); } $args = Values::getArgumentValues($fieldDef, $node, $variableValues); diff --git a/tests/Executor/ExecutorTest.php b/tests/Executor/ExecutorTest.php index e8f5be331..4538f41f7 100644 --- a/tests/Executor/ExecutorTest.php +++ b/tests/Executor/ExecutorTest.php @@ -463,15 +463,7 @@ public function testNullsOutErrorSubtrees(): void throw new UserError('Error getting asyncReturnError'); }), 'asyncReturnErrorWithExtensions' => static fn (): Deferred => new Deferred(static function (): void { - throw new Error( - 'Error getting asyncReturnErrorWithExtensions', - null, - null, - [], - null, - null, - ['foo' => 'bar'] - ); + throw new Error('Error getting asyncReturnErrorWithExtensions', null, null, [], null, null, ['foo' => 'bar']); }), ]; diff --git a/tests/GraphQLTest.php b/tests/GraphQLTest.php index bb5ec9e72..04c869f99 100644 --- a/tests/GraphQLTest.php +++ b/tests/GraphQLTest.php @@ -18,20 +18,20 @@ public function testPromiseToExecute(): void $promiseAdapter = new SyncPromiseAdapter(); $schema = new Schema( (new SchemaConfig()) - ->setQuery(new ObjectType([ - 'name' => 'Query', - 'fields' => [ - 'sayHi' => [ - 'type' => Type::nonNull(Type::string()), - 'args' => [ - 'name' => [ - 'type' => Type::nonNull(Type::string()), + ->setQuery(new ObjectType([ + 'name' => 'Query', + 'fields' => [ + 'sayHi' => [ + 'type' => Type::nonNull(Type::string()), + 'args' => [ + 'name' => [ + 'type' => Type::nonNull(Type::string()), + ], ], + 'resolve' => static fn ($rootValue, array $args): Promise => $promiseAdapter->createFulfilled("Hi {$args['name']}!"), ], - 'resolve' => static fn ($rootValue, array $args): Promise => $promiseAdapter->createFulfilled("Hi {$args['name']}!"), ], - ], - ])) + ])) ); $promise = GraphQL::promiseToExecute($promiseAdapter, $schema, '{ sayHi(name: "John") }'); From 5be031f21de955d7f2d0c10ed6fb7de866dea07b Mon Sep 17 00:00:00 2001 From: Bozhidar Hristov Date: Mon, 17 Feb 2025 21:32:00 +0200 Subject: [PATCH 3/5] Transfer config in schema extender. --- tests/Utils/SchemaExtenderTest.php | 55 ++++++++++++++++++++++++++---- 1 file changed, 48 insertions(+), 7 deletions(-) diff --git a/tests/Utils/SchemaExtenderTest.php b/tests/Utils/SchemaExtenderTest.php index 140924ac3..37f04654c 100644 --- a/tests/Utils/SchemaExtenderTest.php +++ b/tests/Utils/SchemaExtenderTest.php @@ -11,7 +11,10 @@ use GraphQL\Language\AST\DocumentNode; use GraphQL\Language\AST\FieldDefinitionNode; use GraphQL\Language\AST\IntValueNode; +use GraphQL\Language\AST\Node; use GraphQL\Language\AST\NodeList; +use GraphQL\Language\AST\ObjectTypeDefinitionNode; +use GraphQL\Language\AST\ObjectTypeExtensionNode; use GraphQL\Language\AST\SchemaDefinitionNode; use GraphQL\Language\Parser; use GraphQL\Language\Printer; @@ -1663,7 +1666,8 @@ public function testOriginalResolversArePreserved(): void $helloResolveFn = $extendedQueryType->getField('hello')->resolveFn; self::assertIsCallable($helloResolveFn); - $query = /** @lang GraphQL */ '{ hello }'; + $query /** @lang GraphQL */ + = '{ hello }'; $result = GraphQL::executeQuery($extendedSchema, $query); self::assertSame(['data' => ['hello' => $value]], $result->toArray()); } @@ -1697,7 +1701,8 @@ public function testOriginalResolveFieldIsPreserved(): void $queryResolveFieldFn = $extendedQueryType->resolveFieldFn; self::assertIsCallable($queryResolveFieldFn); - $query = /** @lang GraphQL */ '{ hello }'; + $query /** @lang GraphQL */ + = '{ hello }'; $result = GraphQL::executeQuery($extendedSchema, $query); self::assertSame(['data' => ['hello' => $value]], $result->toArray()); } @@ -1705,7 +1710,8 @@ public function testOriginalResolveFieldIsPreserved(): void /** @see https://github.com/webonyx/graphql-php/issues/180 */ public function testShouldBeAbleToIntroduceNewTypesThroughExtension(): void { - $sdl = /** @lang GraphQL */ ' + $sdl /** @lang GraphQL */ + = ' type Query { defaultValue: String } @@ -1718,7 +1724,8 @@ public function testShouldBeAbleToIntroduceNewTypesThroughExtension(): void $documentNode = Parser::parse($sdl); $schema = BuildSchema::build($documentNode); - $extensionSdl = /** @lang GraphQL */ ' + $extensionSdl /** @lang GraphQL */ + = ' type Bar { foo: Foo } @@ -1766,6 +1773,37 @@ public function testPreservesRepeatableInDirective(): void self::assertTrue($extendedDirective->isRepeatable); } + public function testCustomConfigIsTransferred(): void + { + $fieldConfigDecorator = function ( + array $typeConfig, + FieldDefinitionNode $fieldDefinitionNode, + Node $node + ) { + if (($node instanceof ObjectTypeDefinitionNode || $node instanceof ObjectTypeExtensionNode) && $node->name->value === 'Test' && $fieldDefinitionNode->name->value === 'field1') { + $typeConfig['customAttr'] = true; + } + + return $typeConfig; + }; + $schema = BuildSchema::build(/** @lang GraphQL */ ' + type Test { + field1: String! + } + ', null, [], $fieldConfigDecorator); + + $type = $schema->getType('Test'); + assert($type instanceof ObjectType); + $field1 = $type->getField('field1'); + self::assertArrayHasKey('customAttr', $field1->config); + + $extendedSchema = SchemaExtender::extend($schema, Parser::parse('scalar Foo'), [], null, $fieldConfigDecorator); + $type = $extendedSchema->getType('Test'); + assert($type instanceof ObjectType); + $field1 = $type->getField('field1'); + self::assertArrayHasKey('customAttr', $field1->config); + } + public function testSupportsTypeConfigDecorator(): void { $helloValue = 'Hello World!'; @@ -1814,7 +1852,8 @@ public function testSupportsTypeConfigDecorator(): void $extendedSchema = SchemaExtender::extend($schema, $documentNode, [], $typeConfigDecorator, $fieldConfigDecorator); - $query = /** @lang GraphQL */ ' + $query /** @lang GraphQL */ + = ' { hello foo { @@ -1918,7 +1957,8 @@ public function testPreservesResolveTypeMethod(): void $SomeInterfaceClassType->concrete = $ExtendedFooType; $SomeUnionClassType->concrete = $ExtendedFooType; - $query = /** @lang GraphQL */ ' + $query /** @lang GraphQL */ + = ' { someUnion { __typename @@ -1976,7 +2016,8 @@ public function testPreservesIsTypeOfMethod(): void $extendedSchema = SchemaExtender::extend($schema, $documentNode); - $query = /** @lang GraphQL */ ' + $query /** @lang GraphQL */ + = ' { someInterface { __typename From 4d66e457bcd95c6627ba26394ee5b1f72cb5ab34 Mon Sep 17 00:00:00 2001 From: Bozhidar Hristov Date: Mon, 17 Feb 2025 21:45:36 +0200 Subject: [PATCH 4/5] Transfer config in schema extender. --- tests/Utils/SchemaExtenderTest.php | 32 ++++++++++++++++-------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/tests/Utils/SchemaExtenderTest.php b/tests/Utils/SchemaExtenderTest.php index 37f04654c..4e751a374 100644 --- a/tests/Utils/SchemaExtenderTest.php +++ b/tests/Utils/SchemaExtenderTest.php @@ -57,13 +57,13 @@ private function printExtensionNodes($obj): string } /** - * @throws \JsonException + * @return array * @throws Error * @throws InvariantViolation * @throws SerializationError * @throws SyntaxError * - * @return array + * @throws \JsonException */ private static function schemaDefinitions(Schema $schema): array { @@ -1095,8 +1095,8 @@ interface AnotherNewInterface { self::assertEmpty($extendedSchema->validate()); self::assertSame( - // TODO see https://github.com/webonyx/graphql-php/issues/1140 - // scalar SomeScalar @specifiedBy(url: \"http://example.com/foo_spec\") + // TODO see https://github.com/webonyx/graphql-php/issues/1140 + // scalar SomeScalar @specifiedBy(url: \"http://example.com/foo_spec\") << [ 'hello' => [ 'type' => Type::string(), - 'resolve' => static fn (): string => $value, + 'resolve' => static fn(): string => $value, ], ], ]); @@ -1683,7 +1683,7 @@ public function testOriginalResolveFieldIsPreserved(): void 'type' => Type::string(), ], ], - 'resolveField' => static fn (): string => $value, + 'resolveField' => static fn(): string => $value, ]); $schema = new Schema(['query' => $queryType]); @@ -1776,11 +1776,11 @@ public function testPreservesRepeatableInDirective(): void public function testCustomConfigIsTransferred(): void { $fieldConfigDecorator = function ( - array $typeConfig, + array $typeConfig, FieldDefinitionNode $fieldDefinitionNode, - Node $node + Node $node ) { - if (($node instanceof ObjectTypeDefinitionNode || $node instanceof ObjectTypeExtensionNode) && $node->name->value === 'Test' && $fieldDefinitionNode->name->value === 'field1') { + if (($node instanceof ObjectTypeDefinitionNode || $node instanceof ObjectTypeExtensionNode) && $node->name->value === 'Test' && ($fieldDefinitionNode->name->value === 'field1' || $fieldDefinitionNode->name->value === 'field2')) { $typeConfig['customAttr'] = true; } @@ -1797,11 +1797,13 @@ public function testCustomConfigIsTransferred(): void $field1 = $type->getField('field1'); self::assertArrayHasKey('customAttr', $field1->config); - $extendedSchema = SchemaExtender::extend($schema, Parser::parse('scalar Foo'), [], null, $fieldConfigDecorator); + $extendedSchema = SchemaExtender::extend($schema, Parser::parse(/** @lang GraphQL */ 'extend type Test { field2: String! }'), [], null, $fieldConfigDecorator); $type = $extendedSchema->getType('Test'); assert($type instanceof ObjectType); $field1 = $type->getField('field1'); self::assertArrayHasKey('customAttr', $field1->config); + $field2 = $type->getField('field2'); + self::assertArrayHasKey('customAttr', $field2->config); } public function testSupportsTypeConfigDecorator(): void @@ -1815,7 +1817,7 @@ public function testSupportsTypeConfigDecorator(): void 'type' => Type::string(), ], ], - 'resolveField' => static fn (): string => $helloValue, + 'resolveField' => static fn(): string => $helloValue, ]); $schema = new Schema(['query' => $queryType]); @@ -1834,13 +1836,13 @@ public function testSupportsTypeConfigDecorator(): void $fooValue = 'bar'; $typeConfigDecorator = static function ($typeConfig) use ($fooValue) { if ($typeConfig['name'] === 'Foo') { - $typeConfig['resolveField'] = static fn (): string => $fooValue; + $typeConfig['resolveField'] = static fn(): string => $fooValue; } return $typeConfig; }; - $resolveFn = static fn (): string => 'coming from field decorated resolver'; + $resolveFn = static fn(): string => 'coming from field decorated resolver'; $fieldConfigDecorator = static function (array $typeConfig, FieldDefinitionNode $fieldDefinitionNode) use ($resolveFn) { /** @var UnnamedFieldDefinitionConfig $typeConfig */ if ($fieldDefinitionNode->name->value === 'fieldDecorated') { @@ -1938,7 +1940,7 @@ public function testPreservesResolveTypeMethod(): void 'someUnion' => ['type' => $SomeUnionClassType], 'someInterface' => ['type' => $SomeInterfaceClassType], ], - 'resolveField' => static fn (): \stdClass => new \stdClass(), + 'resolveField' => static fn(): \stdClass => new \stdClass(), ]); $schema = new Schema(['query' => $QueryType]); @@ -2000,7 +2002,7 @@ public function testPreservesIsTypeOfMethod(): void 'fields' => [ 'someInterface' => ['type' => $SomeInterfaceType], ], - 'resolveField' => static fn (): \stdClass => new \stdClass(), + 'resolveField' => static fn(): \stdClass => new \stdClass(), ]); $schema = new Schema([ From 6fb409e7d225a1b433a5148b27bf47630217f319 Mon Sep 17 00:00:00 2001 From: Warxcell <3340882+Warxcell@users.noreply.github.com> Date: Mon, 17 Feb 2025 19:46:27 +0000 Subject: [PATCH 5/5] Apply php-cs-fixer changes --- tests/Utils/SchemaExtenderTest.php | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/tests/Utils/SchemaExtenderTest.php b/tests/Utils/SchemaExtenderTest.php index 4e751a374..aab35a69e 100644 --- a/tests/Utils/SchemaExtenderTest.php +++ b/tests/Utils/SchemaExtenderTest.php @@ -57,13 +57,13 @@ private function printExtensionNodes($obj): string } /** - * @return array + * @throws \JsonException * @throws Error * @throws InvariantViolation * @throws SerializationError * @throws SyntaxError * - * @throws \JsonException + * @return array */ private static function schemaDefinitions(Schema $schema): array { @@ -1095,8 +1095,8 @@ interface AnotherNewInterface { self::assertEmpty($extendedSchema->validate()); self::assertSame( - // TODO see https://github.com/webonyx/graphql-php/issues/1140 - // scalar SomeScalar @specifiedBy(url: \"http://example.com/foo_spec\") + // TODO see https://github.com/webonyx/graphql-php/issues/1140 + // scalar SomeScalar @specifiedBy(url: \"http://example.com/foo_spec\") << [ 'hello' => [ 'type' => Type::string(), - 'resolve' => static fn(): string => $value, + 'resolve' => static fn (): string => $value, ], ], ]); @@ -1683,7 +1683,7 @@ public function testOriginalResolveFieldIsPreserved(): void 'type' => Type::string(), ], ], - 'resolveField' => static fn(): string => $value, + 'resolveField' => static fn (): string => $value, ]); $schema = new Schema(['query' => $queryType]); @@ -1776,9 +1776,9 @@ public function testPreservesRepeatableInDirective(): void public function testCustomConfigIsTransferred(): void { $fieldConfigDecorator = function ( - array $typeConfig, + array $typeConfig, FieldDefinitionNode $fieldDefinitionNode, - Node $node + Node $node ) { if (($node instanceof ObjectTypeDefinitionNode || $node instanceof ObjectTypeExtensionNode) && $node->name->value === 'Test' && ($fieldDefinitionNode->name->value === 'field1' || $fieldDefinitionNode->name->value === 'field2')) { $typeConfig['customAttr'] = true; @@ -1817,7 +1817,7 @@ public function testSupportsTypeConfigDecorator(): void 'type' => Type::string(), ], ], - 'resolveField' => static fn(): string => $helloValue, + 'resolveField' => static fn (): string => $helloValue, ]); $schema = new Schema(['query' => $queryType]); @@ -1836,13 +1836,13 @@ public function testSupportsTypeConfigDecorator(): void $fooValue = 'bar'; $typeConfigDecorator = static function ($typeConfig) use ($fooValue) { if ($typeConfig['name'] === 'Foo') { - $typeConfig['resolveField'] = static fn(): string => $fooValue; + $typeConfig['resolveField'] = static fn (): string => $fooValue; } return $typeConfig; }; - $resolveFn = static fn(): string => 'coming from field decorated resolver'; + $resolveFn = static fn (): string => 'coming from field decorated resolver'; $fieldConfigDecorator = static function (array $typeConfig, FieldDefinitionNode $fieldDefinitionNode) use ($resolveFn) { /** @var UnnamedFieldDefinitionConfig $typeConfig */ if ($fieldDefinitionNode->name->value === 'fieldDecorated') { @@ -1940,7 +1940,7 @@ public function testPreservesResolveTypeMethod(): void 'someUnion' => ['type' => $SomeUnionClassType], 'someInterface' => ['type' => $SomeInterfaceClassType], ], - 'resolveField' => static fn(): \stdClass => new \stdClass(), + 'resolveField' => static fn (): \stdClass => new \stdClass(), ]); $schema = new Schema(['query' => $QueryType]); @@ -2002,7 +2002,7 @@ public function testPreservesIsTypeOfMethod(): void 'fields' => [ 'someInterface' => ['type' => $SomeInterfaceType], ], - 'resolveField' => static fn(): \stdClass => new \stdClass(), + 'resolveField' => static fn (): \stdClass => new \stdClass(), ]); $schema = new Schema([