diff --git a/src/ModelDescriber/EnumModelDescriber.php b/src/ModelDescriber/EnumModelDescriber.php index 1aae41ef1..c75935bfe 100644 --- a/src/ModelDescriber/EnumModelDescriber.php +++ b/src/ModelDescriber/EnumModelDescriber.php @@ -17,17 +17,20 @@ class EnumModelDescriber implements ModelDescriberInterface { + public const FORCE_NAMES = '_nelmio_enum_force_names'; + public function describe(Model $model, Schema $schema) { $enumClass = $model->getType()->getClassName(); + $forceName = isset($model->getSerializationContext()[self::FORCE_NAMES]) && true === $model->getSerializationContext()[self::FORCE_NAMES]; $enums = []; foreach ($enumClass::cases() as $enumCase) { - $enums[] = $enumCase->value; + $enums[] = $forceName ? $enumCase->name : $enumCase->value; } $reflectionEnum = new \ReflectionEnum($enumClass); - if ($reflectionEnum->isBacked() && 'int' === $reflectionEnum->getBackingType()->getName()) { + if (!$forceName && $reflectionEnum->isBacked() && 'int' === $reflectionEnum->getBackingType()->getName()) { $schema->type = 'integer'; } else { $schema->type = 'string'; diff --git a/src/ModelDescriber/JMSModelDescriber.php b/src/ModelDescriber/JMSModelDescriber.php index b6793889f..91006dd16 100644 --- a/src/ModelDescriber/JMSModelDescriber.php +++ b/src/ModelDescriber/JMSModelDescriber.php @@ -336,6 +336,15 @@ public function describeItem(array $type, OA\Schema $property, Context $context, if (is_string($typeParam) && enum_exists($typeParam)) { $type['name'] = $typeParam; } + + if (isset($type['params'][1])) { + if ('value' !== $type['params'][1] && is_a($type['name'], \BackedEnum::class, true)) { + // In case of a backed enum, it is possible to serialize it using its names instead of values + // Set a specific serialization context property to enforce a new model, as options cannot be used to force a new model + // See https://github.com/schmittjoh/serializer/blob/5a5a03a71a28a480189c5a0ca95893c19f1d120c/src/Handler/EnumHandler.php#L47 + $serializationContext[EnumModelDescriber::FORCE_NAMES] = true; + } + } } $groups = $this->computeGroups($context, $type); diff --git a/tests/Functional/Entity/JMSEnum81.php b/tests/Functional/Entity/JMSEnum81.php index ee5b48ee1..7c2c6f6a9 100644 --- a/tests/Functional/Entity/JMSEnum81.php +++ b/tests/Functional/Entity/JMSEnum81.php @@ -22,4 +22,12 @@ class JMSEnum81 #[Serializer\Type('array>")] #[Serializer\Expose] public $enumValues; + + #[Serializer\Type('enum<'.ArticleType81::class.", 'name'>")] + #[Serializer\Expose] + public $enumName; + + #[Serializer\Type('array>")] + #[Serializer\Expose] + public $enumNames; } diff --git a/tests/Functional/JMSFunctionalTest.php b/tests/Functional/JMSFunctionalTest.php index d491b9f00..68a161d28 100644 --- a/tests/Functional/JMSFunctionalTest.php +++ b/tests/Functional/JMSFunctionalTest.php @@ -385,6 +385,15 @@ public function testEnumSupport(): void return; } + self::assertEquals([ + 'schema' => 'ArticleType812', + 'type' => 'string', + 'enum' => [ + 'DRAFT', + 'FINAL' + ] + ], json_decode($this->getModel('ArticleType812')->toJson(), true)); + self::assertEquals([ 'schema' => 'JMSEnum81', 'type' => 'object', @@ -398,6 +407,15 @@ public function testEnumSupport(): void '$ref' => '#/components/schemas/ArticleType81' ] ], + 'enum_name' => [ + '$ref' => '#/components/schemas/ArticleType812' + ], + 'enum_names' => [ + 'type' => 'array', + 'items' => [ + '$ref' => '#/components/schemas/ArticleType812' + ] + ], ] ], json_decode($this->getModel('JMSEnum81')->toJson(), true)); }