diff --git a/CHANGELOG.md b/CHANGELOG.md index f9ef7b98d..aa01d7e67 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,12 @@ You can find and compare releases at the [GitHub release page](https://github.co ## Unreleased +## v15.25.1 + +### Changed + +- Call `AbstractType::resolveValue` before `AbstractType::resolveType` https://github.com/webonyx/graphql-php/pull/1781 + ## v15.25.0 ### Added diff --git a/src/Executor/ReferenceExecutor.php b/src/Executor/ReferenceExecutor.php index 93ba8ce80..d75b9a62d 100644 --- a/src/Executor/ReferenceExecutor.php +++ b/src/Executor/ReferenceExecutor.php @@ -1082,8 +1082,8 @@ protected function completeAbstractValue( &$result, $contextValue ) { - $typeCandidate = $returnType->resolveType($result, $contextValue, $info); $result = $returnType->resolveValue($result, $contextValue, $info); + $typeCandidate = $returnType->resolveType($result, $contextValue, $info); if ($typeCandidate === null) { $runtimeType = static::defaultTypeResolver($result, $contextValue, $info, $returnType); diff --git a/src/Type/Definition/AbstractType.php b/src/Type/Definition/AbstractType.php index 5da106fe6..a44d31b5a 100644 --- a/src/Type/Definition/AbstractType.php +++ b/src/Type/Definition/AbstractType.php @@ -12,24 +12,28 @@ interface AbstractType { /** - * Resolves the concrete ObjectType for the given value. + * Receives the original resolved value and transforms it if necessary. + * + * This will be called before `resolveType`. * * @param mixed $objectValue The resolved value for the object type * @param mixed $context The context that was passed to GraphQL::execute() * - * @return ObjectType|string|callable|Deferred|null - * - * @phpstan-return ResolveTypeReturn + * @return mixed The possibly transformed value */ - public function resolveType($objectValue, $context, ResolveInfo $info); + public function resolveValue($objectValue, $context, ResolveInfo $info); /** - * Receives the original resolved value and transforms it if necessary. + * Resolves the concrete ObjectType for the given value. + * + * This will be called after `resolveValue`. * * @param mixed $objectValue The resolved value for the object type * @param mixed $context The context that was passed to GraphQL::execute() * - * @return mixed The possibly transformed value + * @return ObjectType|string|callable|Deferred|null + * + * @phpstan-return ResolveTypeReturn */ - public function resolveValue($objectValue, $context, ResolveInfo $info); + public function resolveType($objectValue, $context, ResolveInfo $info); } diff --git a/src/Type/Definition/InterfaceType.php b/src/Type/Definition/InterfaceType.php index 601493156..d65e6053c 100644 --- a/src/Type/Definition/InterfaceType.php +++ b/src/Type/Definition/InterfaceType.php @@ -69,22 +69,22 @@ public static function assertInterfaceType($type): self return $type; } - public function resolveType($objectValue, $context, ResolveInfo $info) + public function resolveValue($objectValue, $context, ResolveInfo $info) { - if (isset($this->config['resolveType'])) { - return ($this->config['resolveType'])($objectValue, $context, $info); + if (isset($this->config['resolveValue'])) { + return ($this->config['resolveValue'])($objectValue, $context, $info); } - return null; + return $objectValue; } - public function resolveValue($objectValue, $context, ResolveInfo $info) + public function resolveType($objectValue, $context, ResolveInfo $info) { - if (isset($this->config['resolveValue'])) { - return ($this->config['resolveValue'])($objectValue, $context, $info); + if (isset($this->config['resolveType'])) { + return ($this->config['resolveType'])($objectValue, $context, $info); } - return $objectValue; + return null; } /** diff --git a/src/Type/Definition/UnionType.php b/src/Type/Definition/UnionType.php index 2d1e40f4d..8dd15d837 100644 --- a/src/Type/Definition/UnionType.php +++ b/src/Type/Definition/UnionType.php @@ -108,22 +108,22 @@ public function getTypes(): array return $this->types; } - public function resolveType($objectValue, $context, ResolveInfo $info) + public function resolveValue($objectValue, $context, ResolveInfo $info) { - if (isset($this->config['resolveType'])) { - return ($this->config['resolveType'])($objectValue, $context, $info); + if (isset($this->config['resolveValue'])) { + return ($this->config['resolveValue'])($objectValue, $context, $info); } - return null; + return $objectValue; } - public function resolveValue($objectValue, $context, ResolveInfo $info) + public function resolveType($objectValue, $context, ResolveInfo $info) { - if (isset($this->config['resolveValue'])) { - return ($this->config['resolveValue'])($objectValue, $context, $info); + if (isset($this->config['resolveType'])) { + return ($this->config['resolveType'])($objectValue, $context, $info); } - return $objectValue; + return null; } public function assertValid(): void diff --git a/tests/Executor/AbstractTest.php b/tests/Executor/AbstractTest.php index 6ad655ae7..097074e42 100644 --- a/tests/Executor/AbstractTest.php +++ b/tests/Executor/AbstractTest.php @@ -188,7 +188,7 @@ public function testResolveTypeOnInterfaceYieldsUsefulError(): void return null; }, 'fields' => [ - 'name' => ['type' => Type::string()], + 'name' => Type::string(), ], ]); @@ -273,23 +273,23 @@ public function testResolveTypeOnUnionYieldsUsefulError(): void $HumanType = new ObjectType([ 'name' => 'Human', 'fields' => [ - 'name' => ['type' => Type::string()], + 'name' => Type::string(), ], ]); $DogType = new ObjectType([ 'name' => 'Dog', 'fields' => [ - 'name' => ['type' => Type::string()], - 'woofs' => ['type' => Type::boolean()], + 'name' => Type::string(), + 'woofs' => Type::boolean(), ], ]); $CatType = new ObjectType([ 'name' => 'Cat', 'fields' => [ - 'name' => ['type' => Type::string()], - 'meows' => ['type' => Type::boolean()], + 'name' => Type::string(), + 'meows' => Type::boolean(), ], ]); @@ -792,13 +792,6 @@ public function testResolveValueAllowsModifyingObjectValueForInterfaceType(): vo { $PetType = new InterfaceType([ 'name' => 'Pet', - 'resolveType' => static function (PetEntity $objectValue): string { - if ($objectValue->type === 'dog') { - return 'Dog'; - } - - return 'Cat'; - }, 'resolveValue' => static function (PetEntity $objectValue): object { if ($objectValue->type === 'dog') { return new Dog($objectValue->name, $objectValue->vocalizes); @@ -806,6 +799,13 @@ public function testResolveValueAllowsModifyingObjectValueForInterfaceType(): vo return new Cat($objectValue->name, $objectValue->vocalizes); }, + 'resolveType' => static function (object $objectValue): string { + if ($objectValue instanceof Dog) { + return 'Dog'; + } + + return 'Cat'; + }, 'fields' => [ 'name' => Type::string(), ], @@ -916,13 +916,6 @@ public function testResolveValueAllowsModifyingObjectValueForUnionType(): void $PetType = new UnionType([ 'name' => 'Pet', 'types' => [$DogType, $CatType], - 'resolveType' => static function (PetEntity $objectValue): string { - if ($objectValue->type === 'dog') { - return 'Dog'; - } - - return 'Cat'; - }, 'resolveValue' => static function (PetEntity $objectValue): object { if ($objectValue->type === 'dog') { return new Dog($objectValue->name, $objectValue->vocalizes); @@ -930,6 +923,13 @@ public function testResolveValueAllowsModifyingObjectValueForUnionType(): void return new Cat($objectValue->name, $objectValue->vocalizes); }, + 'resolveType' => static function (object $objectValue): string { + if ($objectValue instanceof Dog) { + return 'Dog'; + } + + return 'Cat'; + }, ]); $schema = new Schema([