-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
[Serializer] [WIP] Added annotations and MetadataAwareNormalizer #19374
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
Conversation
|
||
if ($property->getDeclaringClass()->name === $className) { | ||
foreach ($this->reader->getPropertyAnnotations($property) as $annotation) { | ||
if ($annotation instanceof Annotation\Groups) { |
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.
why not using a switch ?
@dunglas was against this kind of change in the past and in fact l do agree with him now. BTW i advise you to open an issue before a pr or at least to not work too much on a pr before it is accepted as you dont know how it will be received by the deciders team ☺ Edit: and it looks good to me to have a third party library doing that for the people who want to have more or less the jms api but with a better support. maybe we could mention your bundle in the docs ? |
Thank you for the reviews. I did not see that PR before.
Thank you. Yes, This PR ended up being too big for not having an issue before. Sorry about that. Though, The work I've put here will (if not merged) end up in a library for it own. I've gotten (to my surprise) lots of feedback on twitter for this PR. Lots of positive voices. =) |
@Nyholm as much as I like the features it brings, as @Ener-Getick I'm against having so much changes in the core. PS: take over JmsSerializer :P |
EI prefer to have one strong, powerful, maintained and MIT licensed serializer library (JMS libs are under the Apache 2 license and cannot be used in GPL v2 projects like Drupal or phpBB) than 2 or 3 incomplete and poorly maintained competitive solutions. IMO @Nyholm is right to contribute here to improve the component. That being said, features regarding exclusion strategies and those regarding access strategies should be handled in a different manner and reuse existing Symfony components. Having annotations and configuration files to easily specify properties to include or not is a great improvement. I suggest to add a new metadata object comtaining the list of readable and writeable properties of a class. This metadata object will be populated using reflection (default), the existing groups system (refactoring) and of course the new options you implemented. This metadata system will allow to provide more features to the end user (the goal of this PR) and -at the same time - to drastically improve the performance of the component by generating automatically specialized classes implementing the PropertyAccessorInterface In the cache directory as suggested by @webmozart. This metadata system would probably fit well in the PropertyInfo component, the end user annotations in the Serializer component and (later) the static accessor class generator in the PropertyAccess component. The other topic is to let the user configuring how to access properties. We worked hard to make the serializer able to leverage PropertyAccess and PropertyInfo components. My goal is to deprecate all objects normalizers except ObjectNormalizer when performances will be similar or better (an objective that can be achieved using the strategy exposed in my prevouis point btw). All the stuff related to accessing properties (annotations specifying the method to call for instance) must be moved in the PropertyAccess component. By doing this, your work will also benefit to all other components depending of it like Form. To summaries what I suggest:
WDYT? P.S: I review and reply from a phone, and it's far from being convenient. |
Speaking about the list of readable and writable properties, I've already implemented it in API Platform: https://github.com/api-platform/core/tree/master/src/Metadata It fits well with the design of the PropertyInfo component (stores metadata in immutable Value Objects) because the current version of the PropertyInfo component has been extracted from API Platform. We can also move the property list in Symfony and use it in the Serializer component. Feel free to import the code you need and transfer the copyright to @fabpot if it can help. |
I like @dunglas proposition about creating annotations in the
The namespace |
After double checking, the PropertyInfo component is already able to guess if a property is readable / writable but th Serializer doesn't use this feature yet. @Ener-Getick:
|
@dunglas ok then but i think we should keep the current defaults (e.g. include all properties unless specified by the user) and try to make it as simple as possible. The part about accessing properties can be removed in favor of #18016. If we really want to have annotations in the Serializer namespace then we will just have to extend the ones created in #18016. |
I still struggle to use the Symfony serializer, and revert back to JMS (which sucks, since it's unmaintained). The biggest missing things for me are |
…(dunglas) This PR was squashed before being merged into the 3.3-dev branch (closes #20509). Discussion ---------- [Serializer] Allow to specify a single value in @groups | Q | A | ------------- | --- | Branch? | master | Bug fix? | no | New feature? | yes | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | #19374 (comment) | License | MIT | Doc PR | todo Tiny DX improvement: Before: ```php use Symfony\Component\Serializer\Annotation\Groups; class Product { /** * @groups({"admins"}) */ public $itemsSold; } ``` Now allowed: ```php use Symfony\Component\Serializer\Annotation\Groups; class Product { /** * @groups("admins") */ public $itemsSold; } ``` Commits ------- 926aa48 [Serializer] Allow to specify a single value in @groups
…(dunglas) This PR was squashed before being merged into the 3.3-dev branch (closes #20509). Discussion ---------- [Serializer] Allow to specify a single value in @groups | Q | A | ------------- | --- | Branch? | master | Bug fix? | no | New feature? | yes | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | symfony/symfony#19374 (comment) | License | MIT | Doc PR | todo Tiny DX improvement: Before: ```php use Symfony\Component\Serializer\Annotation\Groups; class Product { /** * @groups({"admins"}) */ public $itemsSold; } ``` Now allowed: ```php use Symfony\Component\Serializer\Annotation\Groups; class Product { /** * @groups("admins") */ public $itemsSold; } ``` Commits ------- 926aa48 [Serializer] Allow to specify a single value in @groups
@weaverryan the missing part to implement a feature like |
Moving to 4.1. Rebase on master needed, where PHP 7.1 features can be used btw. |
I’ve tried to figure out how to to use PropertyInfo and PropertyAccess components more. But I’m stuck, probably just because of my ignorance :) I will add some more tests and fix one more bug. But later (my battery is dead) |
Proposal: Redesign of Generic Object Normalizers I discussed this PR with @Nyholm on Slack, and I think object normalizers deserve a major redesign: we should capitalize on other existing Symfony components (namely PropertyInfo and PropertyAccess), use them when possible, and make their interfaces hard dependencies of the Serializer (we may move them in Here is my detailed proposal:
In addition to improving code reuse, doing so will have another major benefit: the huge The current Another major improvement with this strategy is that both We would even introduce cache warmers for classes in predefined directories (for instance Note: API Platform already sucessfully uses a similar strategy for its own normalizers. @symfony/deciders, would you mind challenging this redesign proposal? |
@dunglas one of the main reasons for this proposed refactoring is to improve DX (Developer experience). Could you please share some simple before/after code snippets to see those improvements? Thanks a lot! |
This will not answer the question, but it may give a little idea how the "new" use would be. Check the readme at the "proof of concept" bundle: https://github.com/Happyr/SerializerBundle |
Just asking: instead of deprecating/breaking things in the current serializer, which will only cause frustration to users ... if the proposed change is so big, what if we create a new modern component instead? We could get inspiration from the nice "encoding" package from Go which makes all this in a great, modern and concise way. |
That is a good question. Currently Im just adding a new way of configure the serializer. The PR is massive but there is a lot of tests. Kevin is proposing to keep the current feature set in this PR and reduce the added code. (Which is great.) There is currently no deprecations or breaking behavior for the user. This will be opt-in. |
OK. Good to know. Let's wait for those before/after examples because right now the proposal is too abstract for me. Thanks! |
They aren't that big. Actually only I think it doesn't wort it to create a new component (that will use all the interfaces of the current package anyway) for "just" this change. Also, asking users to switch to a new, totally different component instead of "just" injecting new services instead of using an abstract class will be a painfuller upgrade process.
|
…properties through metadata (fbourigault) This PR was squashed before being merged into the 4.2-dev branch (closes #28505). Discussion ---------- [Serialized] allow configuring the serialized name of properties through metadata | Q | A | ------------- | --- | Branch? | master | Bug fix? | no | New feature? | yes | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | #15171 | License | MIT | Doc PR | symfony/symfony-docs#10422 This leverage the new `AdvancedNameConverterInterface` interface (#27021) to implement a name converter that relies on metadata. The name to use is configured per property using a `@SerializedName` annotation or the `serialized-name` XML attribute or the `serialized_name` key for YAML. This was exposed by @dunglas in #19374 (comment). # Framework integration For FramworkBundle integration, a ChainNameConverter could be added to allow users to use this name converter with a custom one. # To do - [x] add a CHANGELOG.md entry. - [x] add a fallback. - [x] add framework integration. - [x] add local caching to `MetadataAwareNameConverter`. - [x] add a doc PR. Commits ------- d1d1ceb [Serialized] allow configuring the serialized name of properties through metadata
What's the status of this PR? I can see a lot of interesting ideas but I fail to see a path to move forward. Is it possible to "finish" it before feature freeze? |
@Nyholm friendly ping :) |
I think this PR brings some great features. I will keep working to make sure they are implemented. But we should do it with a different approach. See here #30818 for the general plan. |
Thank you all for reviews and spending time on this. |
We had a discussion on SoundOfSymfony about Serializers. There are two big libraries, JMSSerializer which is very easy to use but is basically abandoned. And then there is the Symfony Serializer which is way more hard code but very flexible. The result of that discussion was a Bundle built on top of Symfony Serializer that makes it easy to use. Have a look at the bundle's Readme (https://github.com/Happyr/SerializerBundle).
Later @dunglas saw the bundle and asked me to send a PR to the serializer component and here we are now.
I spend a great amount of time on this trying to make it work with the existing AnnotationLoader but failed. The existing AnnotationLoader treats accessors and mutators as "holy" methods that share metadata with their property. I added an other AnnotationLoader to make it work. I named it
BetterAnnotationLoader
which is an awful name but it works until this PR is ready.Differences between ObjectNormalizer and MetadataAwareNormalizer
I tried and failed to make the
MetadataAwareNormalizer
backwards compatible with theObjectNormalizer
. Here are some differences:MetadataAwareNormalizer
ignores all methods by defaultMetadataAwareNormalizer
uses reflection to access propertiesMetadataAwareNormalizer
does not merge metadata for a property and its accessorTODO
Next step
I would like some feedback if you like this approach or not. Should I continue with my TODO list above?