Skip to content

[Serializer] Constructor arguments are mapped wrong if request is missing an argument #52422

Closed
@Havrin

Description

@Havrin

Symfony version(s) affected

6.3.6

Description

This issue rose while using the MapRequestPayload Attribute on a request.

Consider the following DTO and Controller:

final class ChangePassword
{
    #[SerializedName(serializedName: 'old_password')]
    private ?string $oldPassword = null;

    public function __construct(
        #[Assert\NotNull,
            Assert\NotBlank,
            Assert\Email]
        private string $email,
        #[Assert\NotNull,
            Assert\NotBlank]
        private string $password,
        ?string $oldPassword = null
    ) {
        $this->oldPassword = $oldPassword;
    }

    public function getEmail(): string
    {
        return $this->email;
    }

    public function getPassword(): string
    {
        return $this->password;
    }

    public function getOldPassword(): ?string
    {
        return $this->oldPassword;
    }
}
   #[Route(path: 'api/change-password', name: 'change-password', methods: ['POST'])]
    public function changePasswordAction(#[MapRequestPayload] ChangePassword $changePassword): JsonResponse
    {
        return new JsonResponse($changePassword->getEmail());
    }

When calling this route with

{
  "password": "abc",
  "old_password": "def"
}

the created object looks like this:

object(App\DTO\ChangePassword)#2315 (3) {
["oldPassword":"App\DTO\ChangePassword":private]=>
NULL
["email":"App\DTO\ChangePassword":private]=>
string(3) "abc"
["password":"App\DTO\ChangePassword":private]=>
string(3) "def"
}

the values are not correctly mapped

How to reproduce

A simple way to reproduce it is described above.

It's also possible to use my github project: https://github.com/Havrin/symfony-payload-bug

start it and throw the following request against https://localhost/api/change-password

{
  "password": "abc",
  "old_password": "def"
}

Possible Solution

While debugging I noticed, that https://github.com/symfony/serializer/blob/1197823bacefc3397fafb8f10709c1574b2f69ce/Normalizer/AbstractNormalizer.php#L376 is creating an array of values with just an index-number as key.
After creating the object in https://github.com/symfony/serializer/blob/1197823bacefc3397fafb8f10709c1574b2f69ce/Normalizer/AbstractNormalizer.php#L420 the values are wrongly mapped. Seems like the code is not correctly using the name as key but rather the index-number.

Additional Context

The wrong mapping started occurring after this fix: #51907

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions