From aab771b6cb4d94bc14724b6a5c36f1a422882e09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Sapone?= Date: Sat, 4 May 2024 00:02:29 +0200 Subject: [PATCH] [make:entity] add enum support --- src/Maker/MakeEntity.php | 4 +++ src/Util/ClassSource/Model/ClassProperty.php | 7 +++++ src/Util/ClassSourceManipulator.php | 14 +++++++++ src/Validator.php | 11 +++++++ tests/Maker/MakeEntityTest.php | 31 +++++++++++++++++++ .../entities/attributes/Enum/Role-basic.php | 9 ++++++ 6 files changed, 76 insertions(+) create mode 100644 tests/fixtures/make-entity/entities/attributes/Enum/Role-basic.php diff --git a/src/Maker/MakeEntity.php b/src/Maker/MakeEntity.php index f8825610f..f08529159 100644 --- a/src/Maker/MakeEntity.php +++ b/src/Maker/MakeEntity.php @@ -424,6 +424,10 @@ private function askForNextField(ConsoleStyle $io, array $fields, string $entity if ('string' === $type) { // default to 255, avoid the question $classProperty->length = $io->ask('Field length', '255', Validator::validateLength(...)); + + if ($io->confirm('Is this field an enum?', false)) { + $classProperty->enumType = $io->ask('Enum class', null, Validator::classIsBackedEnum(...)); + } } elseif ('decimal' === $type) { // 10 is the default value given in \Doctrine\DBAL\Schema\Column::$_precision $classProperty->precision = $io->ask('Precision (total number of digits stored: 100.00 would be 5)', '10', Validator::validatePrecision(...)); 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..359f2a31e 100644 --- a/src/Util/ClassSourceManipulator.php +++ b/src/Util/ClassSourceManipulator.php @@ -112,6 +112,10 @@ public function addEntityField(ClassProperty $mapping): void } } + if (null !== $mapping->enumType) { + $typeHint = $this->addUseStatementIfNecessary($mapping->enumType); + } + // 2) USE property type on property below, nullable // 3) If default value, then NOT nullable @@ -894,6 +898,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..009de49fe 100644 --- a/tests/Maker/MakeEntityTest.php +++ b/tests/Maker/MakeEntityTest.php @@ -81,6 +81,8 @@ public function getTestDetails(): \Generator '', // default length '', + // enum type + '', // nullable '', // no more properties @@ -188,6 +190,8 @@ public function getTestDetails(): \Generator 'name', 'string', '255', // length + // enum type + '', // nullable 'y', 'createdAt', @@ -214,6 +218,8 @@ public function getTestDetails(): \Generator 'lastName', 'string', '', // length (default 255) + // enum type + '', // nullable 'y', // finish adding fields @@ -620,6 +626,7 @@ public function getTestDetails(): \Generator // field name 'firstName', 'string', + '', '', // length (default 255) // nullable '', @@ -710,6 +717,30 @@ 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 not additional fields + 'role', + 'string', + '255', // length + // enum type + 'y', + '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 @@ +