Skip to content
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

[Validator] Be able to set a payload in a ConstraintValidator (instead of the Constraint) #27818

Open
lyrixx opened this Issue Jul 3, 2018 · 6 comments

Comments

Projects
None yet
4 participants
@lyrixx
Copy link
Member

lyrixx commented Jul 3, 2018

Description
ATM it's possible to set a payload on the Constraint and not in the ConstraintValidator
But in some application, some validation rule could be complex. So it's better and easier to create a custom Constraint + ConstraintValidator.
Thus, such validator could raise many Violations. In my application, I would like to be able to set different payload for each kind of violation. More specifically, I want to add a level (or severity).

Example

  1. On an DTO, I add my @AssertDiscountCardValidity
  2. I create a simple Constraint (DiscountCardValidity)
  3. I create a "complex" ConstraintValidator (DiscountCardValidityValidator).

The logic inside could ne something like:

// fetch the discount 
if (!$discountCard) {
    $this->context->buildViolation('bar')
        ->setPayload(['level' => 'error']) // THIS IS NEW
        ->addViolation()
    ;

    return;
}

// ...

if (/** something that is not critical for the validation */ true) {
    $this->context->buildViolation('foo')
        ->setPayload(['level' => 'warning']) // THIS IS NEW
        ->addViolation()
    ;
}
@linaori

This comment has been minimized.

Copy link
Contributor

linaori commented Jul 3, 2018

What should happen if it's a warning?

@lyrixx

This comment has been minimized.

Copy link
Member Author

lyrixx commented Jul 3, 2018

@iltar It's documented here http://symfony.com/doc/3.4/validation/severity.html#customize-the-error-message-template

In my case, it's for an API, so I added a custom ConstraintViolationListNormalizer

@linaori

This comment has been minimized.

Copy link
Contributor

linaori commented Jul 3, 2018

Ah I thought you meant that it was a completely new feature, but this issue is to make sure that you can manually set the payload as well as via annotations, right?

I'm still not sure what the point is of severity though, sure you get a warning in your form, but you'll never see it if the form was valid.

@yceruto

This comment has been minimized.

Copy link
Contributor

yceruto commented Jul 3, 2018

[Validator] Be able to set a payload in a ConstraintValidator

Do you mean in a ConstraintViolation instead of ConstraintValidator?

Also this would need to add a property $playload + setPayload() in ConstraintViolationBuilder too.

A workaround:

$errorConstraint = clone $constraint;
$errorConstraint->payload = ['level' => 'error'];

$this->context->buildViolation('foo')
    ->setConstraint($errorConstraint)
    ->addViolation();

// ...

$warningConstraint = clone $constraint;
$warningConstraint->payload = ['level' => 'warning'];

$this->context->buildViolation('foo')
    ->setConstraint($warningConstraint)
    ->addViolation();
@yceruto

This comment has been minimized.

Copy link
Contributor

yceruto commented Jul 3, 2018

Another workaround could be handling many levels in payload:

$constraint->payload['levels'][] = 'error';
$this->context->buildViolation('foo')
    ->addViolation(); // adds the default $constraint from context

// ...

// adding more levels to the previous violation (and same field)
$constraint->payload['levels'][] = 'warning';

It would require changes in the frontend to be able to handle these levels.

@lyrixx

This comment has been minimized.

Copy link
Member Author

lyrixx commented Jul 3, 2018

Ah I thought you meant that it was a completely new feature, but this issue is to make sure that you can manually set the payload as well as via annotations, right?

yes ;)

I'm still not sure what the point is of severity though, sure you get a warning in your form, but you'll never see it if the form was valid.

yes, that's the point.

Do you mean in a ConstraintViolation instead of ConstraintValidator?

I put an example ;)

About your workaround, I did something similar:

DTO:


/**
 * @AssertDiscountCardValidity(level="warning")
 * @AssertDiscountCardValidity(level="error")
 */
class DiscountCardValidity

Validator:

    public function validate($discountCardValidity, Constraint $constraint)
    {
    
        // ...
        if ('error' === $constraint->level) {
            $this->validateAtErrorLevel($discountCardValidity, $constraint, $discountCard);
        } elseif ('warning' === $constraint->level) {
            $this->validateAtWarningLevel($discountCardValidity, $constraint, $discountCard);
        }
    }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.