Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BUG] GraphQL Uses Enum Case Names Instead of Backing Values, Breaking Filters #6996

Open
lcottingham opened this issue Mar 4, 2025 · 3 comments

Comments

@lcottingham
Copy link

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

  1. 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";
}
  1. Use this enum in an API Platform resource and database entity
#[ORM\Column(length: 255, enumType: CategoryTypeEnum::class)]
private ?CategoryTypeEnum $category = null;
  1. 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
        }
    ]
}
  1. 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:

  1. The GraphQL schema should use the backing values as enum values, matching how they're stored in the database
  2. 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.

@lcottingham
Copy link
Author

Interestingly - I did just spot this release addressing this issue here in graphql-php, creating this disconnect.

What may be a solution here to firm up the disconnect is to resolve the enum in the BackedEnumFilter slightly differently for graphQL.

Perhaps using reflection to resolve by key, instead of value if it is a string?

$reflection = new ReflectionEnum(CategoryTypeEnum::class);
if ($reflection->hasCase($name)) {
    $enumCase = constant(CategoryTypeEnum::class . '::' . $name);
}

@soyuka
Copy link
Member

soyuka commented Mar 7, 2025

there are many issues on the subject, I don't know what's best feel free to open a PR but please check on our issues/pull-request if we already have something pending.

@lcottingham
Copy link
Author

You're right - looks like #6864 solves this to me

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants