-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
[Serializer] Give access to the context to support* methods #19371
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
{ | ||
$context = 4 === func_num_args() ? func_get_arg(3) : []; |
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.
Long array syntax should be used
I always wondered why it was not already the case and assumed it was by design. However, IIRC, the Serializer previously used — in older versions of the component — a hash of the |
@ogizanagi It's not a problem because we don't use the context in |
@dunglas I would be 👎 for this one. It is a limitation for sure, but having the context in the supports makes the lookup for the (de)normalizer much more dynamic, thus extremely hard to cache. Now let's say you have a set of data that you want to denormalize in a |
I agree with @dunglas this is not part of the symfony promises imo. @theofidry if you change the context the serializer output will very likely change too so i don't get what's the problem. Moreover the context shouldn't change that much. |
The context is very likely to change a lot, it already changes natively to handle proxies or cache keys. In ApiPlatform for example, we also have a lot of keys passing through the context (
Yeah the output may change, but so does the context. It makes much harder to predict the result for a given context and now you have to handle the context, which is dynamic and accessible to all normalizers (hence very likely to change) for caching. The context was initially for giving additional info on how to (de)normalize a set of data. Adding it to the |
@theofidry if i'm not wrong the things such as proxy classes, cache keys, etc. are generated only when the cache is cleared ? If this is true then the context should remain the same. Anyway imo as the context describes how to (de)serialize an object it should be possible to not execute a normalizer in case it doesn't support some part of the context. |
Maybe adding a new field |
{ | ||
$context = 4 === func_num_args() ? func_get_arg(3) : array(); |
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.
should be changed to func_num_args() > 3 ? func_get_arg(3) : array()
for consistency (this is always written like that) and for clarity
@Ener-Getick could mitigate it, but looks horribly brittle to me. I just feel like this feature is about trying to extend the usage of context for something it is not meant. I'm not the one who gets to decide, but IMO it will only add complexity to something that is already very complex and make it messier. @dunglas is there any use case in which you want to use this feature? |
@theofidry I just looked the code @ogizanagi mentioned and it is no longer in the code (the normalizer to use is always determined) so there are absolutely no problem. So there won't ever be any issues about caching here (except if someone doesn't update to the latest patches but this is not our problem...). I'm in favor of merging that as a feature (as people were limited but didn't have a weird behaviour). And I see several use cases. One of them is if you use normalization groups with custom normalizers, you may want to have one normalizer per group. |
@Ener-Getick I fail to see how have a dynamic array that can change from one call to another is not going to have an impact on caching. It may not have one in the Symfony code base right now but it will definitely have some in userland (I am not talking of BC, but of usability).
To that I would said my argument still stands:
So it's not that I don't see the use case (and believe me, I'm the first one abusing of it), but I don't believe it belongs to the core. |
@theofidry nothing is cached anymore about which normalizer to use so we can't have a problem about that ^^ Your argument doesn't work in case you have to deal with third party normalizers. Anyway it would be easier to have other people reviews :) |
Nevermind misread your comment. Indeed if there is no caching there anymore should be alright. |
Maybe there should be caching? For a system with many Normalizers there is likely to be some gain from do so - You can imagine a Serializer that uses code generation to make this really fast. Thinking if the use cases for this outweigh not being able (or so able) to create a cache in the future. It seems like if the action of a Normalizer needs to change based on the content, it could always delegate in the actual normalize/denormalize methods. |
@mcfedr caching at this level has been removed because proved to be more likely to cause bugs than anything else. The Serializer lookup is usually quite fast unless you really do weird things in your |
ping @symfony/deciders |
It would be great to have this feature for 3.2 :) |
Changing the interfaces needs a smooth upgrade path. In this case, we have no choice but create new interfaces that extend the current ones, while deprecating them. |
@nicolas-grekas It will be very difficult to find a better name than the current one. Maybe can we let interfaces as-is in 4.0+ (with the comment)? Updating every single implementation of these interfaces to use the new ones will also be a very tedious work. But I agree, breaking existing code is a worse solution and we will not do it. |
|
ff31957
to
e3cfe63
Compare
Status: needs work |
007c106
to
cdbf9b5
Compare
I've uncommented all the commented code. It should be ok now to merge this PR. However I'm unsure if it's ok or not to uncomment new arguments in the WDYT? /cc @symfony/deciders |
@dunglas That is indeed a BC break and our BC promise forbids such a change (see http://symfony.com/doc/current/contributing/code/bc.html#changing-classes):
|
@xabbuh yes I know but see this thread for the why: #19371 (comment) We have 3 solutions if we want to merge give access to the context in
|
518b79b
to
21c3f49
Compare
I've used the same strategy than in
It should be ready now. Status: Needs review |
if (__CLASS__ !== get_class($this)) { | ||
$r = new \ReflectionMethod($this, __FUNCTION__); | ||
if (__CLASS__ !== $r->getDeclaringClass()->getName()) { | ||
@trigger_error(sprintf('Method %s() will have a second `$context = array()` argument in version 4.0. Not defining it is deprecated since 3.3.', get_class($this), __FUNCTION__), E_USER_DEPRECATED); |
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.
can't we remove this block since the class is @final
now?
if (__CLASS__ !== get_class($this)) { | ||
$r = new \ReflectionMethod($this, __FUNCTION__); | ||
if (__CLASS__ !== $r->getDeclaringClass()->getName()) { | ||
@trigger_error(sprintf('Method %s() will have a second `$context = array()` argument in version 4.0. Not defining it is deprecated since 3.3.', get_class($this), __FUNCTION__), E_USER_DEPRECATED); |
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.
could be removed
if (__CLASS__ !== get_class($this)) { | ||
$r = new \ReflectionMethod($this, __FUNCTION__); | ||
if (__CLASS__ !== $r->getDeclaringClass()->getName()) { | ||
@trigger_error(sprintf('Method %s() will have a third `$context = array()` argument in version 4.0. Not defining it is deprecated since 3.3.', get_class($this), __FUNCTION__), E_USER_DEPRECATED); |
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.
could be removed
if (__CLASS__ !== get_class($this)) { | ||
$r = new \ReflectionMethod($this, __FUNCTION__); | ||
if (__CLASS__ !== $r->getDeclaringClass()->getName()) { | ||
@trigger_error(sprintf('Method %s() will have a fourth `$context = array()` argument in version 4.0. Not defining it is deprecated since 3.3.', get_class($this), __FUNCTION__), E_USER_DEPRECATED); |
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.
make the class @final
instead?
if (__CLASS__ !== get_class($this)) { | ||
$r = new \ReflectionMethod($this, __FUNCTION__); | ||
if (__CLASS__ !== $r->getDeclaringClass()->getName()) { | ||
@trigger_error(sprintf('Method %s() will have a third `$context = array()` argument in version 4.0. Not defining it is deprecated since 3.3.', get_class($this), __FUNCTION__), E_USER_DEPRECATED); |
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.
make the class @final
instead?
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.
Overriding this class is common (even if it's not a good practice IMO). Not sure it is worth it to make it final.
21c3f49
to
e9b56ec
Compare
e9b56ec
to
661005e
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.
👍
@@ -267,7 +267,7 @@ private function validateAndDenormalize($currentClass, $attribute, $data, $forma | |||
throw new LogicException(sprintf('Cannot denormalize attribute "%s" for class "%s" because injected serializer is not a denormalizer', $attribute, $class)); | |||
} | |||
|
|||
if ($this->serializer->supportsDenormalization($data, $class, $format)) { | |||
if ($this->serializer->supportsDenormalization($data, $class, $format, $context)) { |
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.
@dunglas Can you check that my conflict resolution is the right one. If not, can you fix it directly on master? Thanks.
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.
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.
thanks
Thank you @dunglas. |
This is a current use case to want to access the context form the
supports*
methods. This PR fixes this limitation.Maybe can it be considered a bug fix?