diff --git a/src/Maker/MakeEntity.php b/src/Maker/MakeEntity.php
index f8825610f..a093f290b 100644
--- a/src/Maker/MakeEntity.php
+++ b/src/Maker/MakeEntity.php
@@ -393,7 +393,7 @@ private function askForNextField(ConsoleStyle $io, array $fields, string $entity
$allValidTypes = array_merge(
array_keys($types),
EntityRelation::getValidRelationTypes(),
- ['relation']
+ ['relation', 'enum']
);
while (null === $type) {
$question = new Question('Field type (enter ? to see all types)', $defaultType);
@@ -430,6 +430,12 @@ private function askForNextField(ConsoleStyle $io, array $fields, string $entity
// 0 is the default value given in \Doctrine\DBAL\Schema\Column::$_scale
$classProperty->scale = $io->ask('Scale (number of decimals to store: 100.00 would be 2)', '0', Validator::validateScale(...));
+ } elseif ('enum' === $type) {
+ // ask for valid backed enum class
+ $classProperty->enumType = $io->ask('Enum class', null, Validator::classIsBackedEnum(...));
+
+ // set type according to user decision
+ $classProperty->type = $io->confirm('Can this field store multiple enum values', false) ? 'simple_array' : 'string';
}
if ($io->confirm('Can this field be null in the database (nullable)', false)) {
@@ -465,6 +471,9 @@ private function printAvailableTypes(ConsoleStyle $io): void
'time' => ['time_immutable'],
'dateinterval' => [],
],
+ 'other' => [
+ 'enum' => [],
+ ],
];
$printSection = static function (array $sectionTypes) use ($io, &$allTypes) {
@@ -535,6 +544,7 @@ private function printAvailableTypes(ConsoleStyle $io): void
$io->writeln('Other Types');
// empty the values
$allTypes = array_map(static fn () => [], $allTypes);
+ $allTypes = [...$typesTable['other'], ...$allTypes];
$printSection($allTypes);
}
diff --git a/src/Util/ClassSource/Model/ClassProperty.php b/src/Util/ClassSource/Model/ClassProperty.php
index 220c42029..a57406d63 100644
--- a/src/Util/ClassSource/Model/ClassProperty.php
+++ b/src/Util/ClassSource/Model/ClassProperty.php
@@ -33,6 +33,7 @@ public function __construct(
public ?int $scale = null,
public bool $needsTypeHint = true,
public bool $unique = false,
+ public ?string $enumType = null,
) {
}
@@ -52,6 +53,10 @@ public function getAttributes(): array
$attributes['unique'] = true;
}
+ if ($this->enumType) {
+ $attributes['enumType'] = $this->enumType;
+ }
+
foreach (['length', 'id', 'nullable', 'precision', 'scale'] as $property) {
if (null !== $this->$property) {
$attributes[$property] = $this->$property;
@@ -74,6 +79,7 @@ public static function createFromObject(FieldMapping|array $data): self
precision: $data->precision,
scale: $data->scale,
unique: $data->unique ?? false,
+ enumType: $data->enumType,
);
}
@@ -93,6 +99,7 @@ public static function createFromObject(FieldMapping|array $data): self
precision: $data['precision'] ?? null,
scale: $data['scale'] ?? null,
unique: $data['unique'] ?? false,
+ enumType: $data['enumType'] ?? null,
);
}
}
diff --git a/src/Util/ClassSourceManipulator.php b/src/Util/ClassSourceManipulator.php
index e93aae2ca..a19d1626f 100644
--- a/src/Util/ClassSourceManipulator.php
+++ b/src/Util/ClassSourceManipulator.php
@@ -120,8 +120,14 @@ public function addEntityField(ClassProperty $mapping): void
$attributes[] = $this->buildAttributeNode(Column::class, $mapping->getAttributes(), 'ORM');
$defaultValue = null;
+ $commentLines = [];
if ('array' === $typeHint && !$nullable) {
$defaultValue = new Node\Expr\Array_([], ['kind' => Node\Expr\Array_::KIND_SHORT]);
+ if (null !== $mapping->enumType) {
+ $commentLines = [sprintf('@return %s[]', Str::getShortClassName($mapping->enumType))];
+ }
+ } elseif (null !== $mapping->enumType) {
+ $typeHint = $this->addUseStatementIfNecessary($mapping->enumType);
} elseif ($typeHint && '\\' === $typeHint[0] && false !== strpos($typeHint, '\\', 1)) {
$typeHint = $this->addUseStatementIfNecessary(substr($typeHint, 1));
}
@@ -146,7 +152,8 @@ public function addEntityField(ClassProperty $mapping): void
// getter methods always have nullable return values
// because even though these are required in the db, they may not be set yet
// unless there is a default value
- null === $defaultValue
+ null === $defaultValue,
+ $commentLines
);
// don't generate setters for id fields
@@ -894,6 +901,16 @@ public function buildAttributeNode(string $attributeClass, array $options, ?stri
);
}
+ if ('enumType' === $option) {
+ return new Node\Arg(
+ new Node\Expr\ConstFetch(new Node\Name(Str::getShortClassName($value).'::class')),
+ false,
+ false,
+ [],
+ new Node\Identifier($option)
+ );
+ }
+
return new Node\Arg($context->buildNodeExprByValue($value), false, false, [], new Node\Identifier($option));
}, array_keys($options), array_values($options));
diff --git a/src/Validator.php b/src/Validator.php
index 616f9b342..f26034944 100644
--- a/src/Validator.php
+++ b/src/Validator.php
@@ -244,4 +244,15 @@ public static function classIsUserInterface($userClassName): string
return $userClassName;
}
+
+ public static function classIsBackedEnum($backedEnum): string
+ {
+ self::classExists($backedEnum);
+
+ if (!isset(class_implements($backedEnum)[\BackedEnum::class])) {
+ throw new RuntimeCommandException(sprintf('The class "%s" is not a valid BackedEnum.', $backedEnum));
+ }
+
+ return $backedEnum;
+ }
}
diff --git a/tests/Maker/MakeEntityTest.php b/tests/Maker/MakeEntityTest.php
index 87fbb1c9e..c9b4646ab 100644
--- a/tests/Maker/MakeEntityTest.php
+++ b/tests/Maker/MakeEntityTest.php
@@ -620,6 +620,7 @@ public function getTestDetails(): \Generator
// field name
'firstName',
'string',
+ '',
'', // length (default 255)
// nullable
'',
@@ -710,6 +711,28 @@ public function getTestDetails(): \Generator
$this->assertFileExists($runner->getPath('src/Entity/User.php'));
}),
];
+
+ yield 'it_creates_a_new_class_with_enum_field' => [$this->createMakeEntityTest()
+ ->run(function (MakerTestRunner $runner) {
+ $this->copyEntity($runner, 'Enum/Role-basic.php');
+
+ $runner->runMaker([
+ // entity class name
+ 'User',
+ // add additional field
+ 'role',
+ 'enum',
+ 'App\\Entity\\Enum\\Role',
+ '',
+ // nullable
+ 'y',
+ // finish adding fields
+ '',
+ ]);
+
+ $this->runEntityTest($runner);
+ }),
+ ];
}
/** @param array $data */
diff --git a/tests/fixtures/make-entity/entities/attributes/Enum/Role-basic.php b/tests/fixtures/make-entity/entities/attributes/Enum/Role-basic.php
new file mode 100644
index 000000000..d7a0e7ba5
--- /dev/null
+++ b/tests/fixtures/make-entity/entities/attributes/Enum/Role-basic.php
@@ -0,0 +1,9 @@
+