Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

[Serializer] Add ChainNormalizer and ChainDenormalizer#52900

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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Open
Nyholm wants to merge10 commits intosymfony:7.4
base:7.4
Choose a base branch
Loading
fromNyholm:normalizer-aggregator

Conversation

Nyholm
Copy link
Member

@NyholmNyholm commentedDec 5, 2023
edited
Loading

QA
Branch?7.1
Bug fix?no
New feature?yes
Deprecations?yes
Issues
LicenseMIT

This PR is less of a feature and more refactoring.
Our Serializer currently implements 5 interfaces. You may serialize and normalize (and reverse). There are also a lot of logic to figure out context, error messages and what normalizer to use.

This PR suggest to separate responsibilities a bit by splitting the normalizing and denormalizing intoChainNormalizer andChainDenormalizer.

I found this work when I was creating custom denormalizers. A low level class likeMyBlogDenormalizer should not have a dependency on the high levelSerializer. It would make more sense to use aChainDenormalizer. (Yes, there is still an ugly circular reference).

I've markedSerializerAwareInterface as deprecated for this reason. Currently,SerializerAwareInterface only works if you combine it withNormalizerInterface,DenormalizerInterface orEncoderInterface. I deprecate it because one should useNormalizerAwareInterface instead.

mtarld and yceruto reacted with thumbs up emoji
@carsonbotcarsonbot added this to the7.1 milestoneDec 5, 2023
@carsonbotcarsonbot changed the titleAdd Normalizer and Denormalizer aggregators[Serializer] Add Normalizer and Denormalizer aggregatorsDec 5, 2023
@NyholmNyholm changed the title[Serializer] Add Normalizer and Denormalizer aggregators[Serializer] Add ChainNormalizer and ChainDenormalizerDec 5, 2023
@Nyholm
Copy link
MemberAuthor

Nyholm commentedDec 5, 2023
edited
Loading

Hm.. Im considering renaming this toNormalizerAggregate instead. Similar toCacheWarmerAggregate.

EDIT:
Changed my mind. We do haveChainEncoder andChainDecoder at the moment. Using "Chain" is good here.

Copy link
Contributor

@mtarldmtarld left a comment

Choose a reason for hiding this comment

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

I really think that's a good idea to have a better separation between normalization and serialization, thanks for pushing it forward!

@Nyholm
Copy link
MemberAuthor

Wohoo. All tests are passing.

While working on this PR I found an issues like#52992. Ie some code assume a certain behaviour without any contract.
One example that we have in 7.0 right now is that you can pass$context[DenormalizerInterface::COLLECT_DENORMALIZATION_ERRORS] toSerializer::denormalize() and never get aPartialDenormalizationException because you have used the wrong normalizers.

This is something we should fix and this PR is a tiny step towards that direction.

@NyholmNyholmforce-pushed thenormalizer-aggregator branch 3 times, most recently froma36a11a to1846b99CompareJanuary 9, 2024 11:48
@Nyholm
Copy link
MemberAuthor

PR is rebased and all tests are green again.

@NyholmNyholmforce-pushed thenormalizer-aggregator branch 2 times, most recently from5e913c5 to98bdcb8CompareJanuary 31, 2024 20:14
@Nyholm
Copy link
MemberAuthor

PR is rebased =)

@Nyholm
Copy link
MemberAuthor

@mtarld and@chalasr Can you give another review on this please?

mtarld reacted with thumbs up emoji

@@ -59,7 +59,7 @@
"symfony/scheduler": "^6.4.4|^7.0.4",
"symfony/security-bundle": "^6.4|^7.0",
"symfony/semaphore": "^6.4|^7.0",
"symfony/serializer": "^6.4|^7.0",
"symfony/serializer": "^7.1",
Copy link
Contributor

Choose a reason for hiding this comment

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

Is that bump really needed? AFAIK, we try to avoid as much as possible to bump dependencies (see#53160 (comment))

(same for othercomposer.json files)

Copy link
Member

Choose a reason for hiding this comment

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

FrameworkBundle often bumps the min version instead of trying to support multiple versions of the service definitions, for simplicity.
This is different for other package, which can be reused outside the fullstack framework and for which supporting compatibility with 2 different major versions of Symfony reduces the risk of dependency hell in those projects (the lower level the package is, the more useful this is).

Copy link
MemberAuthor

@NyholmNyholmJun 19, 2024
edited
Loading

Choose a reason for hiding this comment

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

Thank you.

I've bumped version on FrameworkBundle and HttpKernel. I have reverted the other packages and make sure they (still) support both 6.4 and 7.2.

@@ -80,6 +82,9 @@

class SerializerTest extends TestCase
{
/**
* @group legacy
*/
Copy link
Contributor

Choose a reason for hiding this comment

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

I think that we can add the non-legacy version as well

@xabbuhxabbuh removed this from the7.1 milestoneMay 15, 2024
@xabbuhxabbuh added this to the7.2 milestoneMay 15, 2024
@dunglas
Copy link
Member

It's a good step forward. I'm +1 for the idea.

Nyholm reacted with heart emoji

@NyholmNyholmforce-pushed thenormalizer-aggregator branch 2 times, most recently fromd18dd6d to7fe79f3CompareJune 19, 2024 11:27
@NyholmNyholmforce-pushed thenormalizer-aggregator branch fromee04567 to5e56886CompareJune 19, 2024 15:58
Copy link
Member

@ycerutoyceruto left a comment

Choose a reason for hiding this comment

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

Nice refactoring! I left minor comments only.

/**
* @param array<NormalizerInterface|DenormalizerInterface> $normalizers
* @param array<EncoderInterface|DecoderInterface> $encoders
*/
public function __construct(
privatearray $normalizers = [],
array $normalizers = [],
Copy link
Member

Choose a reason for hiding this comment

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

defining the new signature of the constructor as beingnew Serializer([], $encoders, $chainNormalizer, $chainDenormalizer) looks weird to me. It don't think the array as first argument should be kept in the new signature

Copy link
Member

Choose a reason for hiding this comment

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

alternatively, we could keep the current constructor signature, making the ChainNormalizer and ChainDenormalizer internal implementation details, as done for the ChainEncoder and ChainDecoder (for which we classify them as being encoders, decoders or both inside the constructor). As most implementations are implementing both interfaces in the same class, it allows passing a single list in instantiation, making the configuration easier

Btw, this would mean that the chain classes would not need to implement the*aware interfaces (as the injection would be handled by the Serializer on each registered class)

Copy link
MemberAuthor

@NyholmNyholmJun 20, 2024
edited
Loading

Choose a reason for hiding this comment

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

Yeah. I dont like the current signature too.

I want to have a signature like:

newSerializer($encoders,$normalizer,$denormalizer);// ornewSerializer($normalizer,$denormalizer,$encoders);

Should I immediately go to that signature or should we change it in SF8?


On your separate topic of making theChain* classes an implementation detail.. That was an earlier version of the PR, but we decided against that to make theSerializer more simple. See#52900 (comment)

Treating them like$encoders is a valid idea. However, you have 1-3 encoders MAX. But you may have 100+ normalizers/denormalizers. So I think it makes more sense to keep them separate and give the developer more control.

Copy link
Member

Choose a reason for hiding this comment

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

Should I immediately go to that signature or should we change it in SF8?

Youmust support the new signature immediately. Otherwise doing the change in 8.0 will be forbidden as it would be a BC break without migration path.

On your separate topic of making the Chain* classes an implementation detail.. That was an earlier version of the PR, but we decided against that to make the Serializer more simple. See#52900 (comment)

That comment was actually suggesting toalso change the way encoders are injected (we should avoid making 2 successive signature changes on the constructor, as that would be a pain to have 2 deprecated signatures to support in the BC layer)

Treating them like $encoders is a valid idea. However, you have 1-3 encoders MAX. But you may have 100+ normalizers/denormalizers. So I think it makes more sense to keep them separate and give the developer more control.

but then, you make it more likely to have nested ChainNormalizer instance, making it necessary to be 100% sure about the reliability ofgetSupportedTypes for instance (my suggestedreturn ['*' => false]` will be reliable, even though it might not be the most optimized one).

}

$class = $definition->getClass();
if (null === $class) {
Copy link
Member

Choose a reason for hiding this comment

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

this logic looks wrong to me. As this compiler pass is registered as a before-optimization pass, the definition class might not be known yet as a class name:

  • when using ChildDefinition, it can benull (if the class will be inherited from the parent), but this doesnot mean that skipping the registration of the service is the valid processing (btw, this is a BC break in case someone uses a ChildDefinition to configure a normalizer today)
  • if a service definition uses a parameter in the class name (which is supported since 2.0), the parameter is not yet resolved at that point, requiring to resolve it explicitly

public function addNormalizer(NormalizerInterface $normalizer): void
{
if ($normalizer instanceof NormalizerAwareInterface) {
$normalizer->setNormalizer($this);
Copy link
Member

Choose a reason for hiding this comment

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

if we make the ChainNormalizer available publicly, this is flawed as it breaks when nesting a ChainNormalizer inside another ChainNormalizer (the normalizers inside the inner ChainNormalizer won't get access to the main normalizer supporting everything)

Copy link
MemberAuthor

Choose a reason for hiding this comment

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

Would a solution be to haveChainNormalizer also implement theNormalizerAwareInterface?

@fabpotfabpot modified the milestones:7.2,7.3Nov 20, 2024
@fabpotfabpot modified the milestones:7.3,7.4May 26, 2025
Sign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment
Reviewers

@stofstofstof requested changes

@ycerutoycerutoyceruto left review comments

@mtarldmtarldmtarld requested changes

@dunglasdunglasAwaiting requested review from dunglasdunglas is a code owner

@chalasrchalasrAwaiting requested review from chalasr

Assignees
No one assigned
Projects
None yet
Milestone
7.4
Development

Successfully merging this pull request may close these issues.

9 participants
@Nyholm@dunglas@stof@yceruto@mtarld@chalasr@fabpot@xabbuh@carsonbot

[8]ページ先頭

©2009-2025 Movatter.jp