I have an enum (thanks php 8.1) that I want to record in database. The field is of type Enum. With a SQL query via Adminer, there is no problem.
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)
But with Doctrine and a symfony form, the data is not persisted (on this field only). I have no error.
if ($form->isSubmitted() && $form->isValid()){
$entityManager = $this->getDoctrine()->getManager();
$entityManager->persist($user);
$entityManager->flush();
This the "add" in 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?
CodePudding user response:
Yes doctrine does not support php Enum from version 8.1 but you can create your own Doctrine type. Defining a custom Doctrine type
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
doctrine:
dbal:
types:
grade: App\DBAL\GradeType
mapping_types:
enum: string
grade: grade
Have a good day !