【问题标题】:How to persist enum with Symfony Doctrine (entity field type:"enum")如何使用 Symfony Doctrine 持久化枚举(实体字段类型:“枚举”)
【发布时间】:2021-10-20 09:47:38
【问题描述】:

我有一个要记录在数据库中的枚举(感谢 php 8.1)。该字段是枚举类型。通过Adminer进行SQL查询,没有问题。

UPDATE `users` SET `grade` = 1, WHERE `id` = '51';

在这种情况下,在 Adminer 中,我可以在成绩列中看到“A5”(值为 1 的枚举名称)

但是使用 Doctrine 和 symfony 表单,数据不会被持久化(仅在这个字段上)。 我没有错误。

if ($form->isSubmitted() && $form->isValid()){

        $entityManager = $this->getDoctrine()->getManager();
        $entityManager->persist($user);
        $entityManager->flush();

这是 ProfileType 中的“添加”

            ->add('grade', ChoiceType::class, [
            'data' => $user ? $user->getGrade() : GradeEnum::D1,
            'placeholder' => 'Choose an option',
            'required' => false,
            'choices' => [
                GradeEnum::D1->name => GradeEnum::D1,
                GradeEnum::D2->name => GradeEnum::D2,
                GradeEnum::C1->name => GradeEnum::C1,
                GradeEnum::C2->name => GradeEnum::C2,
                GradeEnum::B1->name => GradeEnum::B1,
                GradeEnum::B2->name => GradeEnum::B2,
                GradeEnum::A1->name => GradeEnum::A1,
                GradeEnum::A2->name => GradeEnum::A2,
                GradeEnum::A3->name => GradeEnum::A3,
                GradeEnum::A4->name => GradeEnum::A4,
                GradeEnum::A5->name => GradeEnum::A5,
                GradeEnum::A5plus->name => GradeEnum::A5plus,
            ],
            'attr' => [
                'class' => 'mb-3'
            ],
            'label' => 'Grade'
        ])

我做了一个表格的转储。我得到一个枚举。

App\Enum\GradeEnum {#332
 +name: "A5"
 +value: 1
}

如果我尝试使用另一种类型(如整数)在此字段中保存数据,我会出错。这很正常。但是为什么教义不坚持枚举呢?

【问题讨论】:

  • Doctrine 还不支持 PHP 8.1 枚举。

标签: php enums doctrine


【解决方案1】:

从 2.11 版本开始,ORM 支持 php 8 枚举

enum Suit: string {
    case Hearts = 'H';
    case Diamonds = 'D';
    case Clubs = 'C';
    case Spades = 'S';
}

#[Entity]
class Card
{
    /** ... */

    #[Column(type: 'string', enumType: Suit::class)]
    public $suit;
} 

您可以在offical blog post 中了解更多信息。 官方文档应该很快就会出现。

【讨论】:

    【解决方案2】:

    是的,从 8.1 版本开始,doctrine 不支持 php Enum,但您可以创建自己的 Doctrine 类型。 Defining a custom Doctrine type

    在你的情况下,它应该是这样的链接:

    <?php
    
    namespace App\DBAL;
    
    use Doctrine\DBAL\Platforms\AbstractPlatform;
    use Doctrine\DBAL\Types\Type;
    use App\Enum\GradeEnum;
    use InvalidArgumentException;
    use JetBrains\PhpStorm\Pure;
    
    class GradeType extends Type
    {
        protected string $name;
        protected array $values = [
            GradeEnum::A5plus,
            GradeEnum::A5,
            GradeEnum::A4,
            GradeEnum::A3,
            GradeEnum::A2,
            GradeEnum::A1,
            GradeEnum::B2,
            GradeEnum::B1,
            GradeEnum::C2,
            GradeEnum::C1,
            GradeEnum::D2,
            GradeEnum::D1,
        ];
    
        const GRADE = 'grade';
    
        public function getName(): string
        {
            return self::GRADE;
        }
    
        public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform): string
        {
            $values = array_map(function ($val) {
                /** @var GradeEnum $val */
                return "'{$val->name}'";
            }, $this->values);
    
            return 'ENUM(' . implode(', ', $values) . ')';
        }
    
        #[Pure]
        public function convertToPHPValue($value, AbstractPlatform $platform): ?GradeEnum
        {
            if (null === $value) {
                return null;
            }
            return GradeEnum::getGradeFromString($value);
        }
    
        public function convertToDatabaseValue($value, AbstractPlatform $platform)
        {
            /** @var GradeEnum $value */
            if ($value !== null) {
                if (!in_array($value, $this->values)) {
                    throw new InvalidArgumentException("Invalid '" . $this->name . "' value.");
                } else {
                    return $value->name;
                }
            }
    
            return null;
        }
    
        public function canRequireSQLConversion(): bool
        {
            return true;
        }
    
        public function requiresSQLCommentHint(AbstractPlatform $platform): bool
        {
            return true;
        }
    }
    
    <?php
    
    namespace App\Enum;
    
    enum GradeEnum: int
    {
        case A5plus = 0;
        case A5 = 1;
        case A4 = 2;
        case A3 = 3;
        case A2 = 4;
        case A1 = 5;
        case B2 = 6;
        case B1 = 7;
        case C2 = 8;
        case C1 = 9;
        case D2 = 10;
        case D1 = 11;
    
        public static function getGradeFromString(string $grade): GradeEnum {
            return match ($grade) {
                self::A5plus->name => self::A5plus,
                self::A5->name => self::A5,
                self::A4->name => self::A4,
                self::A3->name => self::A3,
                self::A2->name => self::A2,
                self::A1->name => self::A1,
                self::B1->name => self::B1,
                self::B2->name => self::B2,
                self::C1->name => self::C1,
                self::C2->name => self::C2,
                self::D1->name => self::D1,
                self::D2->name => self::D2,
            };
        }
    }
    

    不要忘记将你的类型添加到你的学说.yaml

    doctrine:
        dbal:
            types:
                grade: App\DBAL\GradeType
            mapping_types:
                enum: string
                grade: grade
    

    祝你有美好的一天!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-22
      • 1970-01-01
      • 2011-05-13
      • 2014-07-23
      相关资源
      最近更新 更多