skonsoft
skonsoft

Reputation: 1806

valid constraint does not support group options in symfony2

I need to cascade validation in symfony2 form unless for specified group.

here symfony team told that group option is not supported in Valid constraint https://github.com/symfony/symfony/issues/4893

How to do it ?

Details:

I have a User Entity has address property which is a foreign key to Address Entity. Also i have Entity called business having User as property and also Address property. I need to validate address for User but, without validating it When User is a property of Business...

Schema

Class Address {
    ...
}

Class User {
     /**
     * @Assert\Valid(groups={"user"})
     */
     private $address;
}

Class Business {
    /**
     * @Assert\Valid(groups={"business"})
     */
     private $user;
    /**
     * @Assert\Valid(groups={"business"})
     */
     private $address;
}

So I need to validate The address inside User only for User Forms but not for Business.

Thank you

Upvotes: 4

Views: 2243

Answers (3)

Gregsparrow
Gregsparrow

Reputation: 1372

I was faced with the same problem (Symfony 3).

I have a entity UserInfo with two fields linked to one entity Place. And I need to validate both fields in one case, and one field in another case.

And didn't want to move constraints into Form.

In first atemt I used a Callback constraint to check group and validate one or both fields. It was fine. But input fields in form wasn't marked as invalid. All errors was displayed at top of the form.

Then I simply created own validator. Thanks to this I can specify needed groups for each field. And all invalid input fields in form marked accordingly.

/**
 * @Annotation
 * @Target({"PROPERTY", "METHOD", "ANNOTATION"})
 */
class ValidGroupAware extends Constraint
{
}

class ValidGroupAwareValidator extends ConstraintValidator
{

    /**
     * Checks if the passed value is valid.
     *
     * @param mixed $value The value that should be validated
     * @param Constraint $constraint The constraint for the validation
     */
    public function validate($value, Constraint $constraint)
    {
        if (!$constraint instanceof ValidGroupAware) {
            throw new UnexpectedTypeException($constraint, __NAMESPACE__.'\ValidGroupAware');
        }

        $violations = $this->context->getValidator()->validate($value, [new Valid()], [$this->context->getGroup()]);
        /** @var ConstraintViolation[] $violations */
        foreach ($violations as $violation) {
            $this->context->buildViolation($violation->getMessage())
                ->setParameters($violation->getParameters())
                ->setCode($violation->getCode())
                ->setCause($violation->getCause())
                ->setPlural($violation->getPlural())
                ->setInvalidValue($violation->getInvalidValue())
                ->atPath($violation->getPropertyPath())
                ->addViolation();
        }
    }
}

Upvotes: 6

Jekis
Jekis

Reputation: 4695

Ok, I have a solution. Callback constraints do have 'groups' option and we can use it here. In the callback we will call validation for the required entity.

I will use php code for adding constraints, but you could use annotations.

User entity

// ...
public static function loadValidatorMetadata(ClassMetadata $metadata)
{
    $metadata->addConstraint(new Assert\Callback(array(
            'methods' => array('validAddress'),
            'groups' => array('user'),
        )));
}

public function validAddress(ExecutionContextInterface $context)
{
    $context->validate($this->address, 'address', $context->getGroup());
}

Business entity

// ...
public static function loadValidatorMetadata(ClassMetadata $metadata)
{
    $metadata->addConstraint(new Assert\Callback(array(
            'methods' => array('validUser'),
            'groups' => array('business'),
        )));
    $metadata->addConstraint(new Assert\Callback(array(
            'methods' => array('validAddress'),
            'groups' => array('business'),
        )));
}

public function validUser(ExecutionContextInterface $context)
{
    $context->validate($this->user, 'user', $context->getGroup());
}

public function validAddress(ExecutionContextInterface $context)
{
    $context->validate($this->address, 'address', $context->getGroup());
}

PS Of course my code can be optimized

Upvotes: 4

tyko
tyko

Reputation: 96

You can add your validation rules in your User FormType. Don't forget to delete your annotation.

Follow this link to learn more about validation in form type

Upvotes: 0

Related Questions