DoctrineEnumBundle icon indicating copy to clipboard operation
DoctrineEnumBundle copied to clipboard

Invalid value "" for ENUM

Open TZK- opened this issue 3 years ago • 11 comments

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
    ];
}

TZK- avatar Sep 23 '20 14:09 TZK-

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.

fre5h avatar Sep 24 '20 07:09 fre5h

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)

TZK- avatar Sep 24 '20 08:09 TZK-

Please add config for Doctrine in your project

fre5h avatar Sep 24 '20 08:09 fre5h

# 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- avatar Sep 24 '20 08:09 TZK-

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.

TZK- avatar Sep 24 '20 08:09 TZK-

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

fre5h avatar Sep 24 '20 09:09 fre5h

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.

TZK- avatar Sep 24 '20 09:09 TZK-

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?

fre5h avatar Sep 24 '20 13:09 fre5h

  • 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() ?

TZK- avatar Sep 24 '20 13:09 TZK-

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

fre5h avatar Sep 25 '20 13:09 fre5h

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.

COil avatar Mar 17 '21 07:03 COil