Skip to content

Commit

Permalink
Serialize valid \BackedEnum values in `GraphQL\Type\Definition\PhpE…
Browse files Browse the repository at this point in the history
…numType`
  • Loading branch information
spawnia authored Aug 29, 2024
1 parent 738132c commit b3b8c5b
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 7 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@ You can find and compare releases at the [GitHub release page](https://github.co

## Unreleased

## v15.13.0

### Added

- Serialize valid `\BackedEnum` values in `GraphQL\Type\Definition\PhpEnumType` https://github.com/webonyx/graphql-php/pull/1604

## v15.12.5

### Fixed
Expand Down
23 changes: 16 additions & 7 deletions src/Type/Definition/PhpEnumType.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,7 @@
use GraphQL\Utils\PhpDoc;
use GraphQL\Utils\Utils;

/**
* @phpstan-import-type PartialEnumValueConfig from EnumType
*/
/** @phpstan-import-type PartialEnumValueConfig from EnumType */
class PhpEnumType extends EnumType
{
public const MULTIPLE_DESCRIPTIONS_DISALLOWED = 'Using more than 1 Description attribute is not supported.';
Expand Down Expand Up @@ -47,12 +45,23 @@ public function __construct(string $enum, ?string $name = null)

public function serialize($value): string
{
if (! ($value instanceof $this->enumClass)) {
$notEnum = Utils::printSafe($value);
throw new SerializationError("Cannot serialize value as enum: {$notEnum}, expected instance of {$this->enumClass}.");
if ($value instanceof $this->enumClass) {
return $value->name;
}

if (is_a($this->enumClass, \BackedEnum::class, true)) {
try {
$instance = $this->enumClass::from($value);
} catch (\ValueError|\TypeError $_) {
$notEnumInstanceOrValue = Utils::printSafe($value);
throw new SerializationError("Cannot serialize value as enum: {$notEnumInstanceOrValue}, expected instance or valid value of {$this->enumClass}.");
}

return $instance->name;
}

return $value->name;
$notEnum = Utils::printSafe($value);
throw new SerializationError("Cannot serialize value as enum: {$notEnum}, expected instance of {$this->enumClass}.");
}

public function parseValue($value)
Expand Down
43 changes: 43 additions & 0 deletions tests/Type/PhpEnumTypeTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,28 @@ public function testExecutesWithEnumTypeFromPhpEnum(): void
], GraphQL::executeQuery($schema, '{ foo(bar: A) }')->toArray());
}

public function testSerializesBackedEnumsByValue(): void
{
$enumType = new PhpEnumType(IntPhpEnum::class);
$schema = new Schema([
'query' => new ObjectType([
'name' => 'Query',
'fields' => [
'foo' => [
'type' => Type::nonNull($enumType),
'resolve' => static fn (): int => 1,
],
],
]),
]);

self::assertSame([
'data' => [
'foo' => 'A',
],
], GraphQL::executeQuery($schema, '{ foo }')->toArray());
}

public function testAcceptsEnumFromVariableValues(): void
{
$enumType = new PhpEnumType(PhpEnum::class);
Expand Down Expand Up @@ -212,4 +234,25 @@ public function testFailsToSerializeNonEnum(): void
self::expectExceptionObject(new SerializationError('Cannot serialize value as enum: "A", expected instance of GraphQL\\Tests\\Type\\PhpEnumType\\PhpEnum.'));
$result->toArray(DebugFlag::RETHROW_INTERNAL_EXCEPTIONS);
}

public function testFailsToSerializeNonEnumValue(): void
{
$enumType = new PhpEnumType(IntPhpEnum::class);
$schema = new Schema([
'query' => new ObjectType([
'name' => 'Query',
'fields' => [
'foo' => [
'type' => Type::nonNull($enumType),
'resolve' => static fn (): string => 'A',
],
],
]),
]);

$result = GraphQL::executeQuery($schema, '{ foo }');

self::expectExceptionObject(new SerializationError('Cannot serialize value as enum: "A", expected instance or valid value of GraphQL\\Tests\\Type\\PhpEnumType\\IntPhpEnum.'));
$result->toArray(DebugFlag::RETHROW_INTERNAL_EXCEPTIONS);
}
}

0 comments on commit b3b8c5b

Please sign in to comment.