简体   繁体   English

如何使用 Symfony Doctrine 持久化枚举(实体字段类型:“枚举”)

[英]How to persist enum with Symfony Doctrine (entity field type:"enum")

I have an enum (thanks php 8.1) that I want to record in database.我有一个要记录在数据库中的枚举(感谢 php 8.1)。 The field is of type Enum .该字段的类型为 Enum With a SQL query via Adminer, there is no problem.通过Adminer 进行SQL 查询,没有问题。

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

In this case, in Adminer, I can see 'A5' in the grade column (name of enum with value 1)在这种情况下,在 Adminer 中,我可以在等级列中看到“A5”(值为 1 的枚举名称)

But with Doctrine and a symfony form, the data is not persisted (on this field only).但是使用 Doctrine 和 symfony 表单,数据不会被持久化(仅在这个字段上)。 I have no error.我没有错误。

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

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

This the "add" in ProfileType这是 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'
        ])

I made a dump of the form.我做了一个表格的转储。 I get an enum.我得到一个枚举。

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

If I try to persist data in this field with another type (like integer), I have a mistake.如果我尝试使用另一种类型(如整数)在该字段中保存数据,我有一个错误。 This is normal.这是正常的。 But why doesn't doctrine persist with an enum?但是为什么教义不坚持枚举呢?

Yes doctrine does not support php Enum from version 8.1 but you can create your own Doctrine type.是的 Doctrine 不支持 8.1 版的 php Enum,但您可以创建自己的 Doctrine 类型。 Defining a custom Doctrine type 定义自定义 Doctrine 类型

In your case it should be something link this:在你的情况下,它应该是链接这个:

<?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,
        };
    }
}

Do not forget to add your type into your doctrine.yaml不要忘记将您的类型添加到您的学说.yaml

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

Have a good day !祝你有美好的一天 !

Starting with version 2.11, the ORM supports php 8 enums从 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;
} 

You can read more about this in the offical blog post .您可以在官方博客文章中阅读更多相关信息 Official docs should follow soon.官方文档应该很快就会跟进。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM