Reputation: 1867
I have an entity with the field $companies. This field has to store an array of Company objects. So I described assert this way:
@Assert\Type("Acme\MyBundle\Entity\Company")
But it's always invalid because from my form i receive array of Companies but this assert wants it be not array but just one Company.
So how to overcome this? I suppose that it has to be something like that:
@Assert\Array(Type("Acme\MyBundle\Entity\Company"))
Upvotes: 6
Views: 6869
Reputation: 17713
Since the question is tagged for Symfony2.x, for the sake of completeness I have to point out that the new validation constraint All introduced since version 2.1 can do the whole job.
For each array or traversable objects (e.g. a Doctrine ArrayCollection
), you can do the following:
/**
* @Assert\All({
* @Assert\Type(type="Acme\MyBundle\Entity\EntityType")
* })
*/
protected $arrayOfEntities;
So, the Symfony2.1 users that are reading your question should prefer this elegant and clean solution.
Upvotes: 13
Reputation: 44376
There is no built-in constraint that would meet your requirements, therefore you'll have to define your own.
Constraint definition:
namespace MyProject\Validator\Constraints;
use Symfony\Component\Validator\Constraint;
/**
* @Annotation
*/
class CollectionOf extends Constraint {
public $message = 'This value should be a collection of type {{ type }}';
public $type;
public function getDefaultOption() {
return 'type';
}
public function getRequiredOptions() {
return array('type');
}
}
Validator definition:
namespace MyProject\Validator\Constraints;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
use Symfony\Component\Validator\Exception\UnexpectedTypeException;
class CollectionOfValidator extends ConstraintValidator {
public function isValid($value, Constraint $constraint) {
if ($value === null) {
return true;
}
if (!is_array($value) && !$value instanceof \Traversable) {
throw new UnexpectedTypeException($value, 'collection');
}
if (count($value) === 0) {
return true;
}
$type = $constraint->type == 'boolean' ? 'bool' : $constraint->type;
$function = 'is_' . $type;
$primitiveTest = function_exists($function);
foreach ($value as $item) {
if (
($primitiveTest && !call_user_func($function, $item)) ||
(!$primitiveTest && !$item instanceof $type)
) {
$this->setMessage($constraint->message, array(
'{{ value }}' => is_object($item) ? get_class($item) : gettype($item),
'{{ type }}' => $constraint->type
));
return false;
}
}
return true;
}
}
The above validator works for both, collections and arrays.
Import your own constraints:
// My\TestBundle\Entity\Company
use Doctrine\ORM\Mapping as ORM;
use MyProject\Validator\Constraints as MyAssert;
use Symfony\Component\Validator\Constraints as Assert;
class Company {
...
/**
* @ORM\ManyToOne(...)
* @Assert\NotNull
* @MyAssert\CollectionOf("My\TestBundle\Entity\Employee")
*/
private $employees;
}
To use annotations constraints you'll have to enable them in confirguartion file:
framework:
...
validation:
enable-annotations: true
Upvotes: 8