Thanks to visit codestin.com
Credit goes to github.com

Skip to content

[Serializer] fix support for unset properties on PHP < 7.4 #44111

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

Merged
merged 1 commit into from
Nov 17, 2021

Conversation

nicolas-grekas
Copy link
Member

Q A
Branch? 4.4
Bug fix? yes
New feature? no
Deprecations? no
Tickets -
License MIT
Doc PR -

This bug is why the CI fails on 5.3 currently.

@nicolas-grekas nicolas-grekas merged commit da00866 into symfony:4.4 Nov 17, 2021
@nicolas-grekas nicolas-grekas deleted the ser-no-nit branch November 17, 2021 15:27
@nicolas-grekas
Copy link
Member Author

After I merged the new test cases in 5.4, they fails, because in 5.4 we have #43469 that changed the logic on the topic.
@ivannemets-sravniru since you wrote #43469 and might know about the topic: would you mind having a look at fixing support for unset properties on 5.4 please?

@ivannemets-sravniru
Copy link

ivannemets-sravniru commented Nov 18, 2021

@nicolas-grekas in my opinion the fix added in this PR should be implemented in some other way...

That would be helpful if this PR had a link to the issue describing the bug you are fixing here, but anyway the key point here is

$propertyValues = (array) $object;

It's essentially wrong to rely on object state (values of its properties) while building the list of attributes in ObjectNormalizer::extractAttributes
The array returned by extractedAttributes must be the same for any object with any values, otherwise it would again cause the bug described in #36594

So, I'd suggest reviewing the code added in this PR to find another way of fixing the bug that this PR is supposed to fix.
Apparently PR #44122 should be reverted as well until there is another solution that does not break the fix implemented in PR #43469

There is no way to fix issue #36594 as long as extractAttributes depends on object state and the attributes cache is used. So, we have two options:

  1. ensure extractAttributes does not depend on object state
  2. get rid of attributes caching in normalizers (i.e. \Symfony\Component\Serializer\Normalizer\AbstractObjectNormalizer::$attributesCache)

This was referenced Nov 18, 2021
@nicolas-grekas
Copy link
Member Author

@ivannemets-sravniru the behavior changed in 5.4 after your PR, but older branches still remain sensitive to the object state. This PR builds on that. In 5.4, I've adapted the code to follow your lead, aka make it not rely on the object's state. It took me a few commits but please find the diff on 5.4 here:
symfony/serializer@e1f4f55...2d9e891

@ivannemets-sravniru
Copy link

ivannemets-sravniru commented Nov 18, 2021

@nicolas-grekas the diff looks good to me, the only question is - why this part has been removed from AbstractObjectNormalizer::__construct:

        if (\PHP_VERSION_ID >= 70400) {
            $this->defaultContext[self::SKIP_UNINITIALIZED_VALUES] = true;
        }

This was added to make the serializer to ignore uninitialized values by default, and this behavior was assumed in related doc PR https://github.com/symfony/symfony-docs/pull/15823/files

Still, I should had set the default value before parent constructor gets called, like this:

    public function __construct(ClassMetadataFactoryInterface $classMetadataFactory = null, NameConverterInterface $nameConverter = null, PropertyTypeExtractorInterface $propertyTypeExtractor = null, ClassDiscriminatorResolverInterface $classDiscriminatorResolver = null, callable $objectClassResolver = null, array $defaultContext = [])
    {
        if (\PHP_VERSION_ID >= 70400 && !isset($defaultContext[self::SKIP_UNINITIALIZED_VALUES])) {
            $defaultContext[self::SKIP_UNINITIALIZED_VALUES] = true;
        }

        parent::__construct($classMetadataFactory, $nameConverter, $defaultContext);

just to make it possible to configure SKIP_UNINITIALIZED_VALUES by passing it to constructor via DI

So, SKIP_UNINITIALIZED_VALUES should be set to true by default, or documentation should be updated to reflect this change

@nicolas-grekas
Copy link
Member Author

SKIP_UNINITIALIZED_VALUES doesn't need to be conditionnal: the code now always makes it true, see last default on:
$context[self::SKIP_UNINITIALIZED_VALUES] ?? $this->defaultContext[self::SKIP_UNINITIALIZED_VALUES] ?? true
and to me there is no need to set the value in the $defaultContext property (as done with several other context options).

@ivannemets-sravniru
Copy link

Yes, you are right, I didn't notice that the fallback value for SKIP_UNINITIALIZED_VALUES has changed from false to true..
It makes perfect sense now, thanks for clarification!

@nicolas-grekas
Copy link
Member Author

Great thanks for the review!

This was referenced Nov 22, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants