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 template parameter to avoid necessity to assert data in normalize#59200

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
danrot wants to merge1 commit intosymfony:7.4
base:7.4
Choose a base branch
Loading
fromdanrot:generic-normalizer-interface

Conversation

danrot
Copy link
Contributor

QA
Branch?TBH I am not sure about this one 😅
Bug fix?Also not sure...
New feature?no
Deprecations?maybe
IssuesDidn't create one, since the code change is minimal anyway
LicenseMIT

In a project I am working on we are using quite some value objects, and I also want to normalize some of them. Instead of repeating the serialization part for every object, I like to create a separateValueObjectNormalizer (whereby I useValueObject as a placeholder here and in the below code).

We are also using PHPStan with its highest level, and then there are some "issues" with that. The problem is that I always have to add a call toassert in thenormalize function, since the$data variable is typed as mixed, and whatever I am doing with the passed data PHPStan won't like. This looks something like this:

<?phpnamespaceApp\Serializer;useApp\Domain\ValueObject;useSymfony\Component\Serializer\Normalizer\NormalizerInterface;finalclass ValueObjectNormalizerimplements NormalizerInterface{publicfunctionnormalize(mixed$object,null|string$format =null,array$context = []):string{\assert($objectinstanceof ValueObject);return$object->someValueObjectProperty;}publicfunctionsupportsNormalization(mixed$data,null|string$format =null,array$context = []):bool{return$datainstanceof ValueObject;}publicfunctiongetSupportedTypes(null|string$format):array{return [ValueObject::class =>true,];}}

With the change being introduced in this PR, it would be possible to make use of generics in order to avoid thisassert call, which I think is a bit nicer.

<?phpdeclare(strict_types=1);namespaceApp\Serializer;useApp\Domain\ValueObject;useSymfony\Component\Serializer\Normalizer\NormalizerInterface;/** * @implements NormalizerInterface<ValueObject> */finalclass ValueObjectNormalizerimplements NormalizerInterface{publicfunctionnormalize(mixed$object,null|string$format =null,array$context = []):string{return$object->someValueObjectProperty;}publicfunctionsupportsNormalization(mixed$data,null|string$format =null,array$context = []):bool{return$datainstanceof ValueObject;}publicfunctiongetSupportedTypes(null|string$format):array{return [ValueObject::class =>true,];}}

What do you think about this? I am also not sure in which branch such a change would have to go, and I am also not sure if you consider this a breaking change.

DominicLuidold and uuf6429 reacted with thumbs up emoji
@carsonbot
Copy link

Hey!

Thanks for your PR. You are targeting branch "7.3" but it seems your PR description refers to branch "TBH I am not sure about this one 😅".
Could you update the PR description or change target branch? This helps core maintainers a lot.

Cheers!

Carsonbot

@danrot
Copy link
ContributorAuthor

I already saw that this causes some issues... But instead of fixing all of that now and occupying github action pipelines I'll wait for your feedback to see if you would accept this PR.

@@ -41,8 +43,8 @@ public function normalize(mixed $data, ?string $format = null, array $context =
/**
* Checks whether the given class is supported for normalization by this normalizer.
*
* @param mixed $data Data to normalize
* @param string|null $format The format being (de-)serialized from or into
* @param TData|mixed $data Data to normalize

Choose a reason for hiding this comment

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

why keep mixed?

Copy link
Contributor

@uuf6429uuf6429Jan 7, 2025
edited
Loading

Choose a reason for hiding this comment

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

ForsupportsNormalization(), it might presumably receive all sorts of data (since it's testing for serialization support).

The idea is that (for example)NormalizerInterface<string> will onlynormalize() strings, but still might receive other types to test for serialization (otherwise(NormalizerInterface<string>)->supportsNormalization(123, ...) will cause a static analysis tool warning, which is undesirable and unintended).

Copy link
ContributorAuthor

Choose a reason for hiding this comment

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

I guess you could argue thatmixed already containsTData as well, so we might as well just keepmixed as a type.

uuf6429 reacted with thumbs up emoji
@carsonbotcarsonbot changed the titleAdd template parameter to avoid necessity to assert data in normalize[Serializer] Add template parameter to avoid necessity to assert data in normalizeJan 7, 2025
@wouterj
Copy link
Member

Looking at the normalizers shipped in Symfony, they all verify the passed data tonormalize()/denormalize() is indeed what is expected (and throw a serializer exception otherwise)

So to me, it sounds like it is a good practice to verify the type in the method itself rather than relying on the return value ofsupportsNormalization()/getSupportedTypes()?

@uuf6429
Copy link
Contributor

uuf6429 commentedJan 7, 2025
edited
Loading

Looking at the normalizers shipped in Symfony, they all verify the passed data tonormalize()/denormalize() is indeed what is expected (and throw a serializer exception otherwise)

@wouterj I just checked two normalizers randomly and that doesn't seem to be the case (unless I misunderstood your point):

I don't know how/if psalm/phpstan is set up, but in either case I would have expected a warning that the usage of$object was not expected (first case not iterable, second case undefined symbol getMessage() etc).

With this PR (and some small adjustments), static analysis tools should figure out$object's type, and modern IDEs should be able to provide autocompletion withnormalize() (and possiblydenormalize() - but that's not covered in this PR - yet) - (without having to redeclare the PHPDoc for(de)normalise()).

People should still be able to opt-out by using@implements NormalizerInterface<mixed>.

@wouterj
Copy link
Member

Interesting, so we are inconsistent about this in Symfony. See e.g.

publicfunctionnormalize(mixed$object, ?string$format =null,array$context = []):string
{
if (!$objectinstanceof \DateInterval) {
thrownewInvalidArgumentException('The object must be an instance of "\DateInterval".');
}
and
publicfunctionnormalize(mixed$object, ?string$format =null,array$context = []):string
{
if (!$objectinstanceof \SplFileInfo) {
thrownewInvalidArgumentException('The object must be an instance of "\SplFileInfo".');
}

uuf6429 reacted with confused emoji

@danrot
Copy link
ContributorAuthor

I have to admit that this is kind of an edge case. It is not absolutely safe to just assume the type passed tonormalize is the one we check for insupportsNormalization, since somebody might as well instantiate aValueObjectNormalizer on their own and callnormalize without callingsupportsNormalization before.

I.e. this is probably how Symfony is calling this under the hood:

$valueObjectNormalizer =newValueObjectNormalizer();if ($valueObjectNormalizer->supportsNormalization($value)) {$valueObjectNormalizer->normalize($value);}

But nothing stops a developer from instantiating that manually and call it in the "wrong" way:

$valueObjectNormalizer =newValueObjectNormalizer();$valueObjectNormalizer->normalize($value);

Nevertheless, I would say this is an edge case, and at least for me the current PR would still be a nice addition, since it is closer to how this is actually working under the hood.

@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

@uuf6429uuf6429uuf6429 left review comments

@nicolas-grekasnicolas-grekasnicolas-grekas left review comments

@dunglasdunglasAwaiting requested review from dunglasdunglas is a code owner

Assignees
No one assigned
Projects
None yet
Milestone
7.4
Development

Successfully merging this pull request may close these issues.

6 participants
@danrot@carsonbot@wouterj@uuf6429@nicolas-grekas@fabpot

[8]ページ先頭

©2009-2025 Movatter.jp