fre5h/DoctrineEnumBundle

Invalid value "" for ENUM

TZK- opened this issue · 11 comments

TZK- commented

I have an error when trying to set a value in my entity which is not part of my enum.
In my entity, I set a validation constraint to ensure that values must one of the enum.

Howewer, It always throws InvalidArgumentException when it calls AbstractEnumType::convertToDatabaseValue() after I try to insert a new record in my database with a value which is not in the enum.

I do not really understand why convertToDatabaseValue() method throws an exception in this case since I want the validation constraint being called first.

Am I doing something wrong ?

declare(strict_types=1);

namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;
use Fresh\DoctrineEnumBundle\Validator\Constraints as DoctrineAssert;
use Symfony\Component\Validator\Constraints as Assert;

class Permission
{
    /**
     * @ORM\Id()
     * @ORM\Column(type="uuid", unique=true)
     *
     * @Assert\Uuid
     *
     * @var string
     */
    private $id;

    /**
     * @ORM\Column(length=255, nullable=false, type="security_permission")
     *
     * @Assert\Length(max=255)
     * @DoctrineAssert\Enum(entity="App\PermissionEnum")
     *
     *
     * @var string
     */
    private string $name;
<?php

declare(strict_types=1);

namespace App;

use Fresh\DoctrineEnumBundle\DBAL\Types\AbstractEnumType;

final class PermissionEnum extends AbstractEnumType
{
    public const VIEW = 'view';
    public const CREATE = 'create';

    protected static $choices = [
        self::VIEW => self::VIEW,
        self::CREATE => self::CREATE
    ];
}
fre5h commented

Have you added the next line into your entity?

use Fresh\DoctrineEnumBundle\Validator\Constraints as DoctrineAssert;

I see it is missed in your example. But maybe you deleted it to make your code snippet shorter. Anyway I need to clarify, that you don't forget to include this validation constraint for you entity.

TZK- commented

Indeed, I have correctly imported the right constraint and missed to add it in my previous post after cleaning up a little bit my entity. (I edited the previous message to include the missing parts)

fre5h commented

Please add config for Doctrine in your project

TZK- commented
# config/packages/doctrine.yaml
doctrine:
    dbal:
        types:
            security_permission: App\PermissionEnum
    orm:
        auto_generate_proxy_classes: true
        mappings:
            App:
                is_bundle: false
                type: annotation
                dir: '%kernel.project_dir%/src/Entity'
                prefix: 'App\Entity'
                alias: App
                
        naming_strategy: doctrine.orm.naming_strategy.underscore
        auto_mapping: true

The type is working well when bound to my entity field since it generate a good SQL migration.

TZK- commented

And if override the method convertToDatabaseValue in my Enum:

    public function convertToDatabaseValue($value, AbstractPlatform $platform)
    {
        return $value;
    }

It works as expected and my validation constraint is well executed.

fre5h commented

Can you debug EnumValidator if it is executed on validation? From your words, looks like validator is not being called.

TZK- commented

The validation process happen after the execution of Doctrine\DBAL\Types::convertToDatabaseValue.

So if the method throws an exception, which is the case in the implementation of Fresh\DoctrineEnumBundle\DBAL\Types::convertToDatabaseValue() it will stop everything and not try to validate anything.

It is the same for all validations rules bound to a field which is an ORM Column of the type Fresh\DoctrineEnumBundle\DBAL\Type.

In my opinion, it must not throw exception in convertToDatabaseValue and let the users check if the values are in the Enum set through the validation rule. Or catch the exception and handle it during the validation process.

fre5h commented

Very strange. I've checked your cases in my code. I cannot reproduce it. If I set a wrong value, it is being catched by validator. I never reach the convertToDatabaseValue() method with wrong value.
What version of Doctrine and EnumBundle do you use?

TZK- commented
  • doctrine/orm: v2.7.3
  • fresh/doctrine-enum-bundle: v6.6.2

I'm using API Platform on top of that, which could be the cause...

  • api-platform/api-pack: v1.2.2

I don't know how it is handled internally when creating entities through API Platform endpoint. Maybe it calls the type class before the validation.

ATM, my 'fix' by overriding the convertToDatabaseValue() method suits me but in which case should we normally hit the exception thrown in convertToDatabaseValue() ?

fre5h commented

@TZK- I have to reproduce this bug with api-platform/api-pack. Right now I cannot reproduce it on my own projects

COil commented

Hi, I have the same problem with API-Platform 2.6. When filtering, if the value in not correct, it throws an error instead of returning a validation error.