Description
API Platform version(s) affected: 4.x
Description
When using backed enums with API Platform's GraphQL integration, there's a disconnect between how Doctrine persists the enum (using the backing value) and how the GraphQL schema represents the enum (using the case name).
This creates issues when filtering with backed enums, as the values expected by GraphQL queries don't match what's stored in the database.
How to reproduce
- Create a PHP backed enum:
enum CategoryTypeEnum: string
{
case MAIN_TYPE = "category.main_type";
case SUB_TYPE = "category.sub_type";
case OTHER_TYPE = "category.other_type";
}
- Use this enum in an API Platform resource and database entity
#[ORM\Column(length: 255, enumType: CategoryTypeEnum::class)]
private ?CategoryTypeEnum $category = null;
- Check the GraphQL schema introspection, which shows:
{
"kind": "ENUM",
"name": "CategoryTypeEnum",
"enumValues": [
{
"name": "MAIN_TYPE",
"description": null
},
{
"name": "SUB_TYPE",
"description": null
},
{
"name": "OTHER_TYPE",
"description": null
}
]
}
- When attempting to filter using these enum values in GraphQL, the filter fails because it expects the backing value but receives the case name.
Looking at the GraphQL\Type\Definition\EnumType object:
GraphQL\Type\Definition\EnumType Object
(
[config] => Array
(
[name] => CategoryTypeEnum
[values] => Array
(
[MAIN_TYPE] => Array
(
[value] => MAIN_TYPE // Should be "category.main_type"
)
[SUB_TYPE] => Array
(
[value] => SUB_TYPE // Should be "category.sub_type"
)
[OTHER_TYPE] => Array
(
[value] => OTHER_TYPE // Should be "category.other_type"
)
)
)
)
The issue is that while FieldsBuilder::getEnumFields()
correctly retrieves backing values with $rCase->getBackingValue()
, somehow these values are being replaced with case names in the final EnumType object.
Possible Solution
One of two approaches could be taken:
- The GraphQL schema should use the backing values as enum values, matching how they're stored in the database
- Or, API Platform could provide a configuration option to choose between using case names or backing values for GraphQL enum representations
This would ensure consistency with Doctrine's behavior, where backed enums are persisted using their backing values.
Additional Context
The backed enum filter fails because it uses tryFrom()
with the value from GraphQL, which doesn't match the backing value:
private function resolveEnum(string $resourceClass, string|int $id): ?\BackedEnum
{
// ...
$enum = $resourceClass::tryFrom($id); // Fails when $id is "MAIN_TYPE" instead of "category.main_type"
// ...
return $enum;
}
It's important to note that this appears to be a disconnect created from the webonyx/graphql-php package integration. REST endpoints resolve correctly with the proper enum backing values, and the issue is only created once we pass the enum config into the webonyx's EnumType() class. The problem seems to occur at this boundary between API Platform and the underlying GraphQL library.