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

Skip to content

[Serializer][Validator] Fix propertyPath when normalize constraint violations with MetadataAwareNameConverter #57392

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

Open
wants to merge 3 commits into
base: 6.4
Choose a base branch
from

Conversation

antten
Copy link
Contributor

@antten antten commented Jun 14, 2024

Q A
Branch? 6.4
Bug fix? yes
New feature? no
Deprecations? no
Issues Fix #56962
License MIT

When using the MapRequestPayload attribute to get the object from the input request, if a constraint fails on a property of the object that uses the SerializedName attribute, the violation error response shows the property name instead of the expected serialized name.

I propose the PR on branch 6.4, since the problem occurs with the MapRequestPayload attibute.

I create a reproducer

@AlexMinaev19
Copy link

Unfortunately, it's not enough to fix the problem. My investigation showed me, that objects with composite structure (class A contains instance class B) do not process properly in this case. We have to adjust MetadataAwareNameConverter (normalization) and handle paths like compositeB.internalField.

@antten
Copy link
Contributor Author

antten commented Jun 18, 2024

@AlexMinaev19 Thank you for your comment. It's true that I missed that case. I am going to fix that ASAP.

@antten antten marked this pull request as draft June 18, 2024 18:38
@antten antten changed the title [Serializer][Validator] Fix propertyPath when normalize constraint violations with MetadataAwareNameConverter [WIP] [Serializer][Validator] Fix propertyPath when normalize constraint violations with MetadataAwareNameConverter Jun 18, 2024
@antten
Copy link
Contributor Author

antten commented Jun 21, 2024

I think there are two things.

The MetadataAwareNameConverter class can use the SerializedName attribute when it normalizes a property name, but it doesn't work in the ConstraintViolationListNormalizer because the class parameter is needed. However, the MetadataAwareNameConverter cannot normalize nested property names.

Therefore, I propose to keep this PR to fix the bug reported in the issue. Violations reported when there are constraint errors can use SerializedName instead of the property name.

I would also like to propose a PR to fix the same problem on the 5.4 branch. Due to the attribute, this PR does not work on both branches.

Finally, I propose to create a new feature PR to enable the normalization of nested properties with MetadataAwareNameConverter.

Thank you in advance for your feedback.

@antten antten force-pushed the fix/serializer-56962 branch from db948b9 to a952a70 Compare June 21, 2024 19:20
@antten antten marked this pull request as ready for review June 21, 2024 19:31
@carsonbot carsonbot changed the title [WIP] [Serializer][Validator] Fix propertyPath when normalize constraint violations with MetadataAwareNameConverter [Serializer][Validator] [WIP] Fix propertyPath when normalize constraint violations with MetadataAwareNameConverter Jun 21, 2024
@antten antten changed the title [Serializer][Validator] [WIP] Fix propertyPath when normalize constraint violations with MetadataAwareNameConverter [Serializer][Validator] Fix propertyPath when normalize constraint violations with MetadataAwareNameConverter Jun 21, 2024
@AlexMinaev19
Copy link

I think, it's possible, but it will not solve the issue, just produces a new one and false feeling that MetadataAwareNameConverter works correctly with ConstraintViolationListNormalizer. I can help you find a solution for nested properties to solve an issue fully. What do you think?

@antten
Copy link
Contributor Author

antten commented Jun 26, 2024

Thank you for your reply.

I believe my proposal will solve the issue, including the case of nested properties. If I correctly understood your comment, your concern is that the fix for nested properties will not be merged into the 6.4 branch?

I understand that this is problematic for you, but I believe the solution requires a change in the behavior of MetadataAwareNameConverter because it is not currently able to normalize nested properties. This new behavior is not possible in a patch release for the 6.4 branch. I would appreciate a response from a Symfony maintainer to confirm or correct me. @dunglas Maybe you can help us?

@AlexMinaev19
Copy link

Thank you for helping!

I need support for nested properties because I use them frequently for request objects.

Why is it not possible to fix the 6.4 version? For me, 6.4 and 7.0 are not a problem at all. One problematic thing that I see is the 5.4 branch that is still under active support and with this, we need the help of Symfony maintainer.

Correct me if I missed something and sorry for the long delay.

@antten
Copy link
Contributor Author

antten commented Jul 2, 2024

Again, I could be wrong, and I would appreciate a response from a Symfony maintainer to correct me if needed.

Currently, the MetadataAwareNameConverter class cannot handle nested properties during normalization. The fix required is to add this new behavior to Symfony. Indeed, this is a new feature, not a bug, and it modifies the current behavior of MetadataAwareNameConverter.

Why is this problematic? Because Symfony uses semantic versioning (SemVer), which follows the format MAJOR.MINOR.PATCH. For the 6.4 branch, only the patch version will be updated as it does not receive new features, only bug fixes, as stated on the official Symfony releases page.

image

When a Symfony user wants to update the patch version in their project to get the latest fixes, their application should not experience any behavioral changes due to the Symfony update. However, if this new feature is merged into the 6.4 branch, it would cause unexpected behavior changes.

Therefore, I believe we cannot add this new feature to the 6.4.x version of Symfony, but only in the new 7.2 release.

I have serious doubts about changing the normalization of the PropertyPath result in a 6.4.x Symfony release, as developers might see it as a regression, potentially requiring updates to their applications, which is not acceptable in a patch version.

Maybe the change of the propertyPath value in violation return message is considered an acceptable change due to its minimal impact. In that case, I would be pleased to update this PR to include handling of nested properties.

I hope my explanations have been helpful.

@AlexMinaev19
Copy link

Thanks for the explanation. Now I understand what you mean and agree with you.

In this case, we can proceed with this, but maybe we need to talk about it with somebody (Symfony maintainer) who can help us with further steps.

@xabbuh
Copy link
Member

xabbuh commented Jul 3, 2024

I am actually having trouble understanding the related issue. Could you please wrap it in an application that one can check out and play with to get a better understanding about what you are talking about?

@antten
Copy link
Contributor Author

antten commented Jul 3, 2024

The problem related to this PR occurs when we have one or more validation constraints fail while trying to deserialize a JSON body string with the MapRequestPayload attribute for object properties that have the SerializedName attribute.

On the next example, we have two classes:

class UserDto
{
    public function __construct(
        #[Assert\NotBlank]
        #[Assert\Length(max: 10)]
        #[SerializedName('first_name')]
        private string $firstName,

        #[Assert\NotBlank]
        #[Assert\Valid]
        #[SerializedName('child')]
        private ?ChildDto $childDto,
    ) {
    }
}

class ChildDto
{
    public function __construct(
        #[Assert\NotBlank]
        #[Assert\Length(min: 5)]
        #[SerializedName('first_name')]
        private string $childFirstName,
    ) {
    }
}

We want to retrieve the UserDto from request using this controller:

class UserController extends AbstractController
{
    #[Route(path: '/users', name: 'create_user', methods: ['POST'], format: 'json')]
    public function __invoke(
        #[MapRequestPayload(acceptFormat: 'json')] UserDto $userDto
    ): JsonResponse {
        return new JsonResponse();
    }
}

We send the following JSON body of the request:

{
      "first_name": "supercalifragilisticexpialidocious",
      "child": {
          "first_name": "aaa"
      }
}

The values of both first_name properties are incorrect according to the constraints defined in the UserDto and ChildDto classes with attributes.

When we try to request our controller, we get the following response:

{
  "type": "https://symfony.com/errors/validation",
  "title": "Validation Failed",
  "status": 422,
  "detail": "firstName: This value is too long. It should have 10 characters or less.\nchildDto.childFirstName: This value is too short. It should have 5 characters or more.",
  "violations": [
    {
      "propertyPath": "firstName",
      "title": "This value is too long. It should have 10 characters or less.",
      "template": "This value is too long. It should have {{ limit }} character or less.|This value is too long. It should have {{ limit }} characters or less.",
      "parameters": {
        "{{ value }}": "\"supercalifragilisticexpialidocious\"",
        "{{ limit }}": "10",
        "{{ value_length }}": "34"
      },
      "type": "urn:uuid:d94b19cc-114f-4f44-9cc4-4138e80a87b9"
    },
    {
      "propertyPath": "childDto.childFirstName",
      "title": "This value is too short. It should have 5 characters or more.",
      "template": "This value is too short. It should have {{ limit }} character or more.|This value is too short. It should have {{ limit }} characters or more.",
      "parameters": {
        "{{ value }}": "\"aaa\"",
        "{{ limit }}": "5",
        "{{ value_length }}": "3"
      },
      "type": "urn:uuid:9ff3fdc4-b214-49db-8718-39c315e33d45"
    }
  ]
}

You can see that the detail and violations propertyPath display the class property name instead of the expected SerializedName.

I have created a reproducer project with this example.

To resolve this problem, I have identified two different issues.

First, in the ConstraintViolationListNormalizer, which calls the name converter to normalize the property path related to the properties whose constraints fail, it does not work in this case because we need to pass the class parameter to the normalize method of the name converter.

However, this fix won't work with nested properties (child.first_name) because the MetadataAwareNameConverter class cannot handle nested properties.

Therefore, we need two different developments to resolve this problem. I think the first is the objective of this PR to the 6.4 branch, and the second is a new feature for the 7.2 branch. The target branches of these two fixes are the reason for our doubt.

Thank you for your help, and I hope my explanations are clear and understandable.

@xeurun
Copy link

xeurun commented Feb 13, 2025

Hi, it seems to have become more actual, with 8.4 getters, for example like this:

    public string $url {
        get => $this->_url;
    }

    public function __construct(
        #[SerializedName('url')]
        #[Assert\NotBlank]
        #[Assert\Type('string')]
        #[Assert\Length(min: 10, max: 4096)]
        private readonly mixed $_url,

result: propertyPath: "_url"
temp workaround pretty simple - trim leading underscore

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.

5 participants