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

Skip to content

[Serializer] Only unset data in AbstractNormalizer::instantiateObject if constructor invocation succeeded #52499

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

Closed
philipsorst opened this issue Nov 8, 2023 · 0 comments

Comments

@philipsorst
Copy link

philipsorst commented Nov 8, 2023

Symfony version(s) affected

6.3.x,5.4.x

Description

The AbstractNormalizer::instantiateObject unsets the corresponding &$data value for a constructor argument if it believes it will be set by constructor invocation so that no set is called later on. However, if constructor invocation fails as it is missing arguments, the value won't be set again at a later stage, even if the object could be instantiated partially when setting the property later on.

How to reproduce

If we have an example object

class ExampleObject
{
    public function __construct(public readonly string $propertyMissing, public readonly string $propertyGiven)
    {
    }
}

I would expect the following test to pass:

try {
    $exampleObject = $serializer->denormalize(['propertyGiven' => 'foo'],
        ExampleObject::class,
        null,
        [DenormalizerInterface::COLLECT_DENORMALIZATION_ERRORS => true]);
} catch (PartialDenormalizationException $e) {
    $exampleObject = $e->getData();
}
self::assertInstanceOf(ExampleObject::class, $exampleObject);
self::assertEquals('foo', $exampleObject->propertyGiven);

however it says: $propertyGiven must not be accessed before initialization as there was no attempt to set it later on after the constructor instantiation failed.

Possible Solution

Remember the properties that have to be unset if the constructor instantiation succeeds and only unset them if there are no missing parameters and the instantiation actually worked.

Additional Context

I realized this as the behaviour changed with commit c54cfbb6f3129c41ea5b26b4e3115919132ab726 as it now collects all missing arguments. Before it returned early and the $data values for later constructor arguments were not unset. So this is kind of a regression, although before it just worked "accidentially" in my use case as the first argument was already missing for my data.

@philipsorst philipsorst added the Bug label Nov 8, 2023
nicolas-grekas added a commit that referenced this issue Nov 20, 2023
This PR was merged into the 5.4 branch.

Discussion
----------

[Serializer] Fix denormalize constructor arguments

| Q             | A
| ------------- | ---
| Branch?       | 5.4
| Bug fix?      | yes
| New feature?  | no
| Deprecations? | no
| Issues        | Fix #52499, Fix #52422
| License       | MIT

Since this PR: #51907, objects with partial constructor parameters were wrongly instantiated.

This PR fixes that issue by delegating the properties values assignment, by unsetting normalized data only when the constructor has been called properly.

This might correct #50759 as well.

Commits
-------

8f7c7ae [Serializer] Fix denormalize constructor arguments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants