-
-
Notifications
You must be signed in to change notification settings - Fork 9.8k
[ObjectMapper] Feat 61044/enum mapping #62392
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: 8.1
Are you sure you want to change the base?
Conversation
bbda5b2 to
97e9a78
Compare
nicolas-grekas
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just wondering: can't this concern be addressed with a transformer?
Absolutely! And this PR aims to get rid of them, as it can be a common use case. Instead of writing everything in this block, I answered you in the main post. |
97e9a78 to
2b703ab
Compare
|
Transforming a UnitEnum to its name is a no-go to me. The case name is not a canonical scalar representation of an enum. |
For me neither, and I think this doesn't happen in my proposition? Tests throws error when you try to refer to the name instead of value. Did you see any line that uses name instead of value somewhere? I'm checking again! |
2b703ab to
b7a075d
Compare
|
Ok few modifications;
I have some questions:
I'm pretty happy with implementation here, beside those questions; SRP seems good (in methods, not in classes), exceptions and messages seems useful, tests covers a lot, style seems clean, performances are saved. I will not work on it anymore until your feedback, roast me boyz! |
c95e577 to
1895c59
Compare
1895c59 to
cecf816
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggestion on the approach:
- append to the ReflectionObjectMapperMetadataFactory (or create a new ObjectMapperMetadataFactory)
- this one detects whether we need a transformation and appends a transform to the Mapping
- move enum transformation code to transformers
This way we can have less specific code in the object mapper class (also helps when we want to continue #61515 )
58a0bfa to
19ca970
Compare
…flectionObjectMapperMetadataFactory (Option A) This approach extends ReflectionObjectMapperMetadataFactory to detect enum conversion needs and inject MapEnum transformer automatically. Changes: - Add Transform/MapEnum.php: Handles BackedEnum <-> scalar conversions - Modify ReflectionObjectMapperMetadataFactory: Detects enum types via context['target_refl'] and enriches Mapping with MapEnum transformer - Modify ObjectMapper: Passes target_refl context when fetching metadata Pros: - Single factory handles all metadata enrichment - No additional factories Cons: - Mixes reflection concerns with enum-specific logic - Factory becomes more complex
19ca970 to
5725a54
Compare
I changed the PR to something with your approach; for now, no details, no tests, just to confirm the direction? |
| private function detectEnumTransformer(string $sourceTypeName, string $targetTypeName): ?MapEnum | ||
| { | ||
| // BackedEnum -> scalar (int or string) | ||
| if (is_a($sourceTypeName, \BackedEnum::class, true) && \in_array($targetTypeName, ['int', 'string'], true)) { | ||
| return new MapEnum($targetTypeName); | ||
| } | ||
|
|
||
| // scalar -> BackedEnum | ||
| if (\in_array($sourceTypeName, ['int', 'string'], true) && is_a($targetTypeName, \BackedEnum::class, true)) { | ||
| return new MapEnum($targetTypeName); | ||
| } | ||
|
|
||
| return null; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using sdtClass as the $source value
symfony/src/Symfony/Component/ObjectMapper/ObjectMapper.php
Lines 121 to 127 in 5725a54
| $readMetadataFrom = $source; | |
| $refl = $this->getSourceReflectionClass($source) ?? $targetRefl; | |
| // When source contains no metadata, we read metadata on the target instead | |
| if ($refl === $targetRefl) { | |
| $readMetadataFrom = $mappedTarget; | |
| } |
will produce a $readMetadataFrom that is the same as $targetRefl.
In this case, $sourceTypeName and $targetTypeName will be equal, so neither of the two conditions will be applied
Maybe for this we should do something like?
if ($sourceTypeName === $targetTypeName && is_a($targetTypeName, \BackedEnum::class, true)) {
return new MapEnum($targetTypeName);
}
Enable the object mapper to convert backed enums (int or string) to their scalar values.
Examples:complete list:It still throws an exception if you try another combination.
For now, you have to create 2 Transformers to achieve this:
This PR aims to replace those out of the box. This is a common use case, for example if you use Symfony Messenger with an Async worker, and you have to send Commands with serialized values:
Or, the other way around, if you want to get the scalar versions of your Enums to simplify code in templates for your front devs.
Now, you just map 2 objects that has the same named property, and Object-Mapper will try to gracefully convert Enum to scalar or scalar to Enum based on their type!