Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Validate enum type with [#Assert\Choice]

Tags:

php

symfony

I'm trying to validate enum type inside a custom DTO class. I'm trying to use the Symfony #[Assert\Choice] attribute but it seems that it doesn't work if I pass wrong value.

Custom DTO:

#[Assert\Choice(callback: 'getConditionTypes')]
public string $conditionType;

public static function getConditionTypes(): array
{
    return array_column(ConditionType::cases(), 'name');
}

Enum class:

enum ConditionType: string
{
    case NEW = "NEW";
    case USED = "USED";
    case CRASHED = "CRASHED";
    case BROKEN = "BROKEN";
    case FOR_PARTS = "FOR_PARTS";
}

When I try to pass a conditionType via Postman with a wrong value, for example "conditionType": "rand" it passes through the DTO without any issue and I'm trying to catch if there is wrong value. What am I missing?

like image 822
vesmihaylov Avatar asked Jul 15 '26 22:07

vesmihaylov


2 Answers

Instead of providing a callback and using Assert\Choice, I used #[Assert\Type(type: ConditionType::class)] which automatically validates if the passed value is part of this enum.

UPDATE JULY 2025
I see that my previous answer is getting some upvotes, today I had to deal with the same problem and this time I used a different approach which also worked:

    #[Assert\NotBlank]
    #[Assert\Choice(callback: [ConditionType::class, 'getValues'])]
    public string $conditionType;
    public static function getValues(): array
    {
        return array_column(self::cases(), 'value');
    }

If I pass the wrong value:

{
    "errors": "Object(App\\DTO\\DealCreateDTO).conditionType:\n    The value    you selected is not a valid choice. (code 8e179f1b-97aa-4560-a02f-2a8b42e49df7)\n"
}

I hope this updated answer helps more people.

like image 54
vesmihaylov Avatar answered Jul 17 '26 20:07

vesmihaylov


interface EnumValidate
{
    public static function validate(string $item): bool;
}

trait ValidateEnumTrait
{
    public static function validate(string $item): bool
    {
        if (!self::tryFrom($item) instanceof self) {
            throw new ValidatorException($item . ' is not a valid backing value for enum ' . self::class);
        }

        return true;
    }
}

enum MyEnum: string implements EnumValidate
{
    use ValidateEnumTrait;
    # …

In DTO

#[Assert\Callback([MyEnum::class, 'validate'])]
like image 40
zardoz Avatar answered Jul 17 '26 20:07

zardoz