如何使用 Symfony Doctrine 持久化枚举(实体字段类型:"enum")
How to persist enum with Symfony Doctrine (entity field type:"enum")
我有一个要记录在数据库中的枚举(感谢 php 8.1)。该字段的类型为 Enum。通过管理员 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
}
如果我尝试将此字段中的数据保存为另一种类型(如整数),则会出错。这个是正常的。但为什么学说不坚持枚举?
是的,从 8.1 版开始,学说不支持 php 枚举,但您可以创建自己的学说类型。
Defining a custom Doctrine type
在你的情况下,它应该是 link 这个:
<?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,
};
}
}
不要忘记将您的类型添加到 doctrine.yaml
doctrine:
dbal:
types:
grade: App\DBAL\GradeType
mapping_types:
enum: string
grade: grade
祝你有个愉快的一天!
从 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 中阅读更多相关信息。
官方文档应该很快就会跟进。
我有一个要记录在数据库中的枚举(感谢 php 8.1)。该字段的类型为 Enum。通过管理员 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
}
如果我尝试将此字段中的数据保存为另一种类型(如整数),则会出错。这个是正常的。但为什么学说不坚持枚举?
是的,从 8.1 版开始,学说不支持 php 枚举,但您可以创建自己的学说类型。 Defining a custom Doctrine type
在你的情况下,它应该是 link 这个:
<?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,
};
}
}
不要忘记将您的类型添加到 doctrine.yaml
doctrine:
dbal:
types:
grade: App\DBAL\GradeType
mapping_types:
enum: string
grade: grade
祝你有个愉快的一天!
从 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 中阅读更多相关信息。 官方文档应该很快就会跟进。