Skip to content

Commit 6408fca

Browse files
authored
feature #1534 [make:entity] add enum support
1 parent 0e089c7 commit 6408fca

File tree

6 files changed

+79
-2
lines changed

6 files changed

+79
-2
lines changed

src/Maker/MakeEntity.php

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -393,7 +393,7 @@ private function askForNextField(ConsoleStyle $io, array $fields, string $entity
393393
$allValidTypes = array_merge(
394394
array_keys($types),
395395
EntityRelation::getValidRelationTypes(),
396-
['relation']
396+
['relation', 'enum']
397397
);
398398
while (null === $type) {
399399
$question = new Question('Field type (enter <comment>?</comment> to see all types)', $defaultType);
@@ -430,6 +430,12 @@ private function askForNextField(ConsoleStyle $io, array $fields, string $entity
430430

431431
// 0 is the default value given in \Doctrine\DBAL\Schema\Column::$_scale
432432
$classProperty->scale = $io->ask('Scale (number of decimals to store: 100.00 would be 2)', '0', Validator::validateScale(...));
433+
} elseif ('enum' === $type) {
434+
// ask for valid backed enum class
435+
$classProperty->enumType = $io->ask('Enum class', null, Validator::classIsBackedEnum(...));
436+
437+
// set type according to user decision
438+
$classProperty->type = $io->confirm('Can this field store multiple enum values', false) ? 'simple_array' : 'string';
433439
}
434440

435441
if ($io->confirm('Can this field be null in the database (nullable)', false)) {
@@ -465,6 +471,9 @@ private function printAvailableTypes(ConsoleStyle $io): void
465471
'time' => ['time_immutable'],
466472
'dateinterval' => [],
467473
],
474+
'other' => [
475+
'enum' => [],
476+
],
468477
];
469478

470479
$printSection = static function (array $sectionTypes) use ($io, &$allTypes) {
@@ -535,6 +544,7 @@ private function printAvailableTypes(ConsoleStyle $io): void
535544
$io->writeln('<info>Other Types</info>');
536545
// empty the values
537546
$allTypes = array_map(static fn () => [], $allTypes);
547+
$allTypes = [...$typesTable['other'], ...$allTypes];
538548
$printSection($allTypes);
539549
}
540550

src/Util/ClassSource/Model/ClassProperty.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ public function __construct(
3333
public ?int $scale = null,
3434
public bool $needsTypeHint = true,
3535
public bool $unique = false,
36+
public ?string $enumType = null,
3637
) {
3738
}
3839

@@ -52,6 +53,10 @@ public function getAttributes(): array
5253
$attributes['unique'] = true;
5354
}
5455

56+
if ($this->enumType) {
57+
$attributes['enumType'] = $this->enumType;
58+
}
59+
5560
foreach (['length', 'id', 'nullable', 'precision', 'scale'] as $property) {
5661
if (null !== $this->$property) {
5762
$attributes[$property] = $this->$property;
@@ -74,6 +79,7 @@ public static function createFromObject(FieldMapping|array $data): self
7479
precision: $data->precision,
7580
scale: $data->scale,
7681
unique: $data->unique ?? false,
82+
enumType: $data->enumType,
7783
);
7884
}
7985

@@ -93,6 +99,7 @@ public static function createFromObject(FieldMapping|array $data): self
9399
precision: $data['precision'] ?? null,
94100
scale: $data['scale'] ?? null,
95101
unique: $data['unique'] ?? false,
102+
enumType: $data['enumType'] ?? null,
96103
);
97104
}
98105
}

src/Util/ClassSourceManipulator.php

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,8 +120,14 @@ public function addEntityField(ClassProperty $mapping): void
120120
$attributes[] = $this->buildAttributeNode(Column::class, $mapping->getAttributes(), 'ORM');
121121

122122
$defaultValue = null;
123+
$commentLines = [];
123124
if ('array' === $typeHint && !$nullable) {
124125
$defaultValue = new Node\Expr\Array_([], ['kind' => Node\Expr\Array_::KIND_SHORT]);
126+
if (null !== $mapping->enumType) {
127+
$commentLines = [sprintf('@return %s[]', Str::getShortClassName($mapping->enumType))];
128+
}
129+
} elseif (null !== $mapping->enumType) {
130+
$typeHint = $this->addUseStatementIfNecessary($mapping->enumType);
125131
} elseif ($typeHint && '\\' === $typeHint[0] && false !== strpos($typeHint, '\\', 1)) {
126132
$typeHint = $this->addUseStatementIfNecessary(substr($typeHint, 1));
127133
}
@@ -146,7 +152,8 @@ public function addEntityField(ClassProperty $mapping): void
146152
// getter methods always have nullable return values
147153
// because even though these are required in the db, they may not be set yet
148154
// unless there is a default value
149-
null === $defaultValue
155+
null === $defaultValue,
156+
$commentLines
150157
);
151158

152159
// don't generate setters for id fields
@@ -894,6 +901,16 @@ public function buildAttributeNode(string $attributeClass, array $options, ?stri
894901
);
895902
}
896903

904+
if ('enumType' === $option) {
905+
return new Node\Arg(
906+
new Node\Expr\ConstFetch(new Node\Name(Str::getShortClassName($value).'::class')),
907+
false,
908+
false,
909+
[],
910+
new Node\Identifier($option)
911+
);
912+
}
913+
897914
return new Node\Arg($context->buildNodeExprByValue($value), false, false, [], new Node\Identifier($option));
898915
}, array_keys($options), array_values($options));
899916

src/Validator.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,4 +244,15 @@ public static function classIsUserInterface($userClassName): string
244244

245245
return $userClassName;
246246
}
247+
248+
public static function classIsBackedEnum($backedEnum): string
249+
{
250+
self::classExists($backedEnum);
251+
252+
if (!isset(class_implements($backedEnum)[\BackedEnum::class])) {
253+
throw new RuntimeCommandException(sprintf('The class "%s" is not a valid BackedEnum.', $backedEnum));
254+
}
255+
256+
return $backedEnum;
257+
}
247258
}

tests/Maker/MakeEntityTest.php

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -620,6 +620,7 @@ public function getTestDetails(): \Generator
620620
// field name
621621
'firstName',
622622
'string',
623+
'',
623624
'', // length (default 255)
624625
// nullable
625626
'',
@@ -710,6 +711,28 @@ public function getTestDetails(): \Generator
710711
$this->assertFileExists($runner->getPath('src/Entity/User.php'));
711712
}),
712713
];
714+
715+
yield 'it_creates_a_new_class_with_enum_field' => [$this->createMakeEntityTest()
716+
->run(function (MakerTestRunner $runner) {
717+
$this->copyEntity($runner, 'Enum/Role-basic.php');
718+
719+
$runner->runMaker([
720+
// entity class name
721+
'User',
722+
// add additional field
723+
'role',
724+
'enum',
725+
'App\\Entity\\Enum\\Role',
726+
'',
727+
// nullable
728+
'y',
729+
// finish adding fields
730+
'',
731+
]);
732+
733+
$this->runEntityTest($runner);
734+
}),
735+
];
713736
}
714737

715738
/** @param array<string, mixed> $data */
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?php
2+
3+
namespace App\Entity\Enum;
4+
5+
enum Role: string
6+
{
7+
case ADMIN = 'admin';
8+
case USER = 'user';
9+
}

0 commit comments

Comments
 (0)