symfony: [2.2] [Validator] Constraints\Valid does not respect "groups" option

I have an entity where I’m using the following validators:

/**
 * @Assert\Callback(methods={"isValid"}, groups={"group1", "group2"})
 */
class UserProduct
{
    /**
     * @var string $title
     * @Assert\NotBlank(message="title.blank", groups={"group1", "group2"});
     */
    private $title;

    /**
     * @var Project\AuthenticationBundle\Entity\User
     * @Assert\Valid(groups={"group2"});
     */
    private $user;

Calling $this->get('validator')->validate($userProduct, array('group1')) asserts the class constraint (@Assert\Callback) and the $title property but also the $user one too, even though it’s not included in the validation group. The same happens if no groups are passed to the Valid constraint.

Removing the @Assert\Valid() constraint and running the same validation again for group1 does not assert the $user property, as expected.

The MemberMetadata class appears to always force the cascading of the Valid constraint, although I’m unsure if this is exactly related to the issue I’m experiencing.

// Symfony\Component\Validator\Mapping\MemberMetadata.php
        if ($constraint instanceof Valid) {
            $this->cascaded = true;
            $this->collectionCascaded = $constraint->traverse;
        } else {
            parent::addConstraint($constraint);
        }

Running on Symfony2 master.

About this issue

  • Original URL
  • State: closed
  • Created 12 years ago
  • Reactions: 1
  • Comments: 37 (22 by maintainers)

Commits related to this issue

Most upvoted comments

This issue makes me wonder whether deprecating cascade_validation in 2.7 is reasonable, since replacing cascade_validation with Assert\Valid (which is recommended) will break any embedded form that has validation_groups specifically set.

cascade_validation should be deprecated only when Assert\Valid has support for the groups option IMO.

@webmozart a simple example would be two different sibling forms that are bound to the same class through different attributes, like $mailingAddress and $billingAddress, Since they would both @Embed the Address model, they share the validations, but on the outside model class, they would have @Valid("BillingAddress") and @Valid("MailingAddress") so they can be validated or not validated individually.

I ran into the same situation, a work around can be to assign the constraint via your form type. It seems like only via annotations it’s not provided. If I add the constraint when adding the field to the builder, it works fine.

Basically I have this:

CancelData
    - contract_cancel (ContractCancelData)
CancelType
    $builder->add('contract_cancel', ContractCancelType::class);

ContractCancelData
    - cancel_when
    - cancel_at @Assert\NotBlank(message="cancel.at.required", groups={"cancel-at-date"})

ContractCancelType
    $constraint = new AfterMonth();
    $constraint->groups = ['cancel-at-date'];

    $form->add('cancel_at', TextType::class, ['constraints' => [$constraint]]);

In this case when I set the validation groups to ['Default', 'cancel-at-date'], the AfterMonth is validated but the NotBlank is not. When I had the NotBlank on the type directly, it is triggered. Note that this is added via the event: form.post_set_data.

/cc @webmozart any idea why those constraints are validated but not the annotations?