14

I have a form to create a new entity. That entity has a collection of other entities that are also entered in that form.

I want to use the validation options of the entity in the collection to validate those entities but it does not work. The validation rules of the "main" entity (Person) are checked, but the validation rules of the entities in the addressList collection (Address) are not checked. When I input invalid information in the fields, the submitted form is successfully validated.

In this example, the annotation for street is not used on validation.

class Person 
{
    ...

    /**
     * @ORM\OneToMany(targetEntity="Address", mappedBy="owner", cascade={"persist", "detach"})
     */
    protected $addressList;

    ....
}

class Address
{
    ...
    /**
     * @ORM\ManyToOne(targetEntity="Person", inversedBy="addressList")
     * @ORM\JoinColumn(name="person_id", referencedColumnName="id", onDelete="CASCADE")
     */
    protected $owner;

    /**
     * @ORM\Column(type="string", length=75)
     * @Assert\MinLength(
     *     limit=3,
     *     message="Street must have atleast {{ limit }} characters."
     * )
     */
    protected $street;

    ...

}

How can I get the form to validate the supplied Address entities?

j0k
  • 22,600
  • 28
  • 79
  • 90
Bramklg
  • 151
  • 1
  • 2
  • 6
  • 3
    I fixed this by adding `'cascade_validation' => true` to the array of `getDefaultOptions()` of the PersonType. – Bramklg May 04 '12 at 08:46

4 Answers4

15

I had the same problem but was solved with:

/**
 * @ORM\OneToMany(
 *  targetEntity="Entity",
 *  mappedBy="mappedEntity",
 *  cascade={"persist" , "remove"}
 * )
 * @Assert\Valid
 */
  • This will validate that each address from the list is valid Address entity only. But if you want some more validations look at @sergey-polischook answer from below – Jekis Jul 11 '14 at 08:05
  • `@Assert\Valid` makes it validate all constraints on the ManyToOne side of the collection and it is exactly what I needed. – Armel Larcier Apr 26 '19 at 08:01
7

I use this:

use Symfony\Component\Validator\ExecutionContextInterface;

class Person 
{
...

/**
 * @ORM\OneToMany(targetEntity="Address", mappedBy="owner", cascade={"persist", "detach"})
 */
protected $addressList;

....

/**
 * @Assert\Callback
 */
public function validate(ExecutionContextInterface $context)
{
    if (!$this->getAddressList()->count()) {
        $context->addViolationAt(
            'addressList',
            'You must add at least one address',
            array(),
            null
        );
    }
}
}

http://symfony.com/doc/current/reference/constraints/Callback.html

Serhii Polishchuk
  • 1,442
  • 17
  • 22
6

Just add annotation assert like following

/** 
 * @Assert\Count(
 *      min = "1",
 *      minMessage = "You must specify at least one"
 * )
 * @Assert\Valid 
 * 
 */
protected $name_of_collection_property;
Julfiker
  • 121
  • 1
  • 4
0

You could also use the "Valid" constraint with the "All" constraint :

/**
 * @ORM\OneToMany(targetEntity="Address", mappedBy="owner", cascade={"persist", "detach"})
 * @Assert\All({
 *     @Assert\Valid
 * })
 */

protected $addressList;
Julien
  • 9,312
  • 10
  • 63
  • 86
  • 2
    Are you sure? This gives me "The constraint Valid cannot be nested inside constraint Symfony\Component\Validator\Constraints\All. You can only declare the Valid constraint directly on a field or method." in 2.1 – nurikabe Nov 08 '12 at 21:01
  • Not sure anymore. I think I was using 2.0 at that time and I had to deal with a similar issue. If it doesn't work maybe I should remove my answer. – Julien Nov 19 '12 at 14:16
  • 1
    I had a similar problem with 3.3 and @Assert\Valid() without the @Assert\All surrounding it seems to work fine. And, obviously, get's rid of the "... Valid cannot be nested inside... All..." error message too. – Andy Preston Feb 28 '18 at 12:49