Skip to content

Add enum support #57

Merged
dbu merged 9 commits intoliip:2.xfrom
rebuy-de:enum-support
Apr 9, 2026
Merged

Add enum support #57
dbu merged 9 commits intoliip:2.xfrom
rebuy-de:enum-support

Conversation

@Spea
Copy link
Copy Markdown
Contributor

@Spea Spea commented Mar 27, 2026

This adds enum support for JMS and simple enum types without any jms attributes

I also took this as an opportunity to update phpstan and php-cs-fixer to their latest version.

This updates to the latest version of `php-cs-fixer`.
The new rule `php_unit_data_provider_method_order` was set to `false`, as it would have changed a bit too much (without not much gain).
@Spea Spea mentioned this pull request Mar 27, 2026
1 task
Copy link
Copy Markdown
Member

@dbu dbu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks a lot for this contribution! seems nice and proper to me.

i commented a few things. the main question i have: does jms define the concept that we can serialize enum with name or with value? is it open that there could be other ways to serialize apart from name and value? i feel like we should use an enum for that choice to prevent meaningless values.

and i suggest we raise the minimal php version to 8.1 (even that one is end of life already). thanks to composer, thats not a BC break, legacy users just stay on the previous minor version.
then you can get rid of all the php version checks.

{
\assert(array_reduce($constructorParameters, static function (bool $carry, $parameter): bool {
return $carry && $parameter instanceof ParameterMetadata;
}, true));
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this can only be removed if we trust phpdoc (aka phpstan is running). as this class is not internal i'd like to keep the check.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually it will also work fine without phpstan running, as the constructor itself does a foreach over the properties and then calls $this->addProperty($property), and this method is typed to addProperty(PropertyMetadata $property), so PHP itself will throw an error if the type is wrong.

Do you still want me to change it back?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is about the $constructorParameters, not about the $properties. the $constructorParameters are assigned to an array 2 lines after this. i think we should add the check back to make sure the error is reported in the constructor.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added it back, but I also had to add a phpstan-ignore here, as otherwise it would result in this error:

 ------ ----------------------------------------------------------------------------------------------------------------------------------------------------
  Line   Metadata/ClassMetadata.php
 ------ ----------------------------------------------------------------------------------------------------------------------------------------------------
  51     Instanceof between Liip\MetadataParser\Metadata\ParameterMetadata and Liip\MetadataParser\Metadata\ParameterMetadata will always evaluate to true.
         🪪  instanceof.alwaysTrue
 ------ ----------------------------------------------------------------------------------------------------------------------------------------------------

Comment thread src/Metadata/PropertyTypeEnum.php Outdated
Comment thread src/TypeParser/JMSTypeParser.php Outdated
Comment thread src/TypeParser/JMSTypeParser.php Outdated
return null;
}

if ('value' === $mode && !is_a($enumType, \BackedEnum::class, true)) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is it a jms feature that you can chose between name and value?

are there any other options? i wonder if we should use an enum to specify name or value, rather than any string?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, that is a feature from JMS, you can decide whether you want to (de-)serialize the value or the name of an enum type by using enum<BackedEnumType, 'name'>. See also the allowed list of annotations in JMS

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we then introduce an enum with types value and name, to make this cleaner? i don't see how there would be any other modes necessary.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done via b9b6ca3

@Spea
Copy link
Copy Markdown
Contributor Author

Spea commented Apr 1, 2026

i commented a few things. the main question i have: does jms define the concept that we can serialize enum with name or with value? is it open that there could be other ways to serialize apart from name and value? i feel like we should use an enum for that choice to prevent meaningless values.

In JMS a non backed enum will always be serialized with the name, and a backed enum with the value unless specified otherwise via the type (e.g. #[Type('enum<BackedEnumType, 'name'>]). I replicated this logic in the metadata.
Apart from value and name there are no other way to (de-)serialize them.

and i suggest we raise the minimal php version to 8.1 (even that one is end of life already). thanks to composer, thats not a BC break, legacy users just stay on the previous minor version. then you can get rid of all the php version checks.

Yeah I agree, I dropped support for PHP 8.0 via f663761

Comment thread phpstan.tests.neon
excludePaths:
- tests/ModelParser/JMSParserTestLegacy.php
- tests/ModelParser/Model/ClassUsingUnionDiscriminator.php
- tests/ModelParser/Model/ClassUsingUnionTyping.php
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why do we need to exclude these files?

Copy link
Copy Markdown
Contributor Author

@Spea Spea Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The UnionDiscriminator from JMS exists since version 3.31.0, but this library supports ^2.3 || ^3 of the jms/serializer depencency. So when installing the composer dependencies in the CI workflow with the options --prefer-stable --prefer-lowest, it will install version 3.19.0, which does not include the UnionDiscriminator and thus phpstan would complain about it.

Since those fixture files are not really critical, I thought to just exclude them, but maybe it could also make sense to adjust the minimum required version for jms/serializer?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah, thanks. can you add a comment that we exclude these until only a new enough version of jms serializer is supported. thats good enough imho. the comment will be useful to know when we can stop excluding.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done - I amended the change to the original commit bfdd9ae

@dbu
Copy link
Copy Markdown
Member

dbu commented Apr 9, 2026

looked at it again. i think those are the last details to clean out.

is the idea of making the enum type an enum a bad idea or does it make sense? it seems like the typical case for me, it can only be name or value, not anything else - or am i mistaken?

Spea added 7 commits April 9, 2026 14:25
This also removes some redundant instanceof checks, as they are covered by the separate add method anyway.
This adds enum support for JMS and simple enum types without any jms attributes
This makes it a bit more straight forward on what is checked and this way we can also get rid of the null check.
This version is no longer maintained and thus can be dropped
Only the more recent versions of `jms/serializer` have this attribute, so in order to also support older ones, an additional check was added.
In case the type is missing when defining an enum (e.g. via `#[Type('enum')]`), we fallback to using the property type (or return type in case of a method).
If the type can still not be determine, because any type information is missing, an `InvalidTypeException` is thrown.
@Spea
Copy link
Copy Markdown
Contributor Author

Spea commented Apr 9, 2026

looked at it again. i think those are the last details to clean out.

is the idea of making the enum type an enum a bad idea or does it make sense? it seems like the typical case for me, it can only be name or value, not anything else - or am i mistaken?

I think that makes sense, as it can have indeed just the two values. I'll change that and let you know once I'm done.

Since the serialization mode can only be either `value` or `name`, a separate enum `SerializationMode` was introduced to be more clear on the possible values.
Copy link
Copy Markdown
Member

@dbu dbu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks a lot for this contribution

@dbu dbu merged commit 7cf5169 into liip:2.x Apr 9, 2026
7 checks passed
@dbu
Copy link
Copy Markdown
Member

dbu commented Apr 9, 2026

do you want me to tag the release now or do you want to double-check the 2.x branch before we tag?

@Spea
Copy link
Copy Markdown
Contributor Author

Spea commented Apr 9, 2026

do you want me to tag the release now or do you want to double-check the 2.x branch before we tag?

I think a release is fine, then we could also merge the changes in the liip/serializer package.

@Spea Spea deleted the enum-support branch April 9, 2026 14:54
@dbu
Copy link
Copy Markdown
Member

dbu commented Apr 9, 2026

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants