Search code examples
formssymfonycollectionsconstraintscustom-validators

Symfony 3 | Custom constraints on CollectionType entities


I followed the documentation and was able to add custom constraints on many of my fields (http://symfony.com/doc/current/validation/custom_constraint.html).

I'm figuring a problem with CollectionType field. My custom constraint just check if user didn't tap multiple space in field (the constraint doesn't matter anyway).

I have a Question form with a title and answers :

$builder
    ->add('title', TextType::class)
    ->add('answers', CollectionType::class, array(
            'entry_type'    => AnswerType::class,
            'allow_add'     => true,
            'allow_delete'  => true,
            'by_reference' => false
        ))

I have my constraint :

use Symfony\Component\Validator\Constraint;

/**
 * @Annotation
 */
class ContainsText extends Constraint
{
    public $message = 'constraint_error';
}

And my constraint validator :

use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;

class ContainsTextValidator extends ConstraintValidator
{
    public function validate($value, Constraint $constraint)
    {
        // It checks if user didn't had multiple space in field
        if (strlen(trim($value)) == 0) {
            $this->context->buildViolation($constraint->message)
                ->addViolation();
        }
    }
}

In my entities :

Question:

use XX\XXBundle\Validator\Constraints as CustomAssert;    

class Question 
{
    /**
     * @var string
     *
     * @ORM\Column(name="title", type="string", length=255, unique=true)
     * @CustomAssert\ContainsText    
     */
    private $title;
    ...
}

Answer :

use XX\XXBundle\Validator\Constraints as CustomAssert; 

class Answer 
{
    /**
     * @var string
     *
     * @ORM\Column(name="text", type="string", length=255, unique=true)
     * @CustomAssert\ContainsText    
     */
    private $text;
    ...
}

In my form validation, if in Question title I tap many spaces, I get a form validation error with my "constraint_error" message => Everything is working.

But, if in Question answers text I tap many spaces, the form validation doesn't return any errors and my question is created with empty answers !

It seems that, if the field comes from a CollectionType, the custom asserts are ignored.

What I don't understand is, if i had a Assert (like @Assert\Blank(), not a custom one) on answer text, even if we are in a CollectionType, the assert is not ignored and I can't validate a form with a blank answer.

What did I miss here ? TY


Solution

  • Not sure which Symfony 2 version you use, but depending if that is pre 2.8 or later you have different ways to tackle this:

    v2.8+ and v3.0+

    Starting with v2.8, which I suspect you could be using given AnswerType::class, cascade_validation was deprecated. Instead, you need to applty Valid constraint, on you Question::$answers class member. Something like this:

    class Question 
    {
        /**
         * ... Other anotaions go here 
         *
         * @Assert\Valid()
         */
        private $answers
    }
    

    Pre v2.8:

    You need to specify cascade_validation option:

    $builder
        ->add('title', TextType::class)
        ->add('answers', CollectionType::class, array(
                'entry_type'    => AnswerType::class,
                'allow_add'     => true,
                'allow_delete'  => true,
                'by_reference' => false,
                'cascade_validation' => true // <========= THIS
            ));
    

    Hope this helps...