Today, we will learn how to create a custom validation constraint with Symfony2 and how to use it with FOSUserBundle.
Let’s start.
We have a user registration form in which we want the username to be automatically validated.
Create your formType and your controller classically, we will focus on constraints.
Let’s name our new constraint: “ContainsUser”.
Create a “ContainsUser.php” file in Validator/Contraints directory at your bundle root.
This file should look like this:
<?php namespace VendorName\UserBundle\Validator\Constraints; use Symfony\Component\Validator\Constraint; /** * @Annotation */ class ContainsUser extends Constraint { public $message = 'The user "%string%" already exists.'; public function validatedBy() { return 'contains_user'; } public function getTargets() { return array(self::CLASS_CONSTRAINT, self::PROPERTY_CONSTRAINT); } }
- ContainsUser will be our constraint.
- ValidatedBy() function returns an alias that will help defines a service.
- In getTargets() function, we specify the targets linked to our constraint (properties and/or classes).
Ok, now we have defined our constraint, we need to create the constraintValidator, it is the file containing the validation logic we want.
Create a “ContainsUserValidator.php” file, always in Validator/Constraints directory.
The file should like this:
<?php namespace VendorName\UserBundle\Validator\Constraints; use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\ConstraintValidator; class ContainsUserValidator extends ConstraintValidator { protected $em; public function __construct(\Doctrine\ORM\EntityManager $em) { $this->em = $em; } public function validate($value, Constraint $constraint) { $repository = $this->em->getRepository('HeadooUserBundle:User'); $user = $repository->findOneByUsername($value); if ($user) { $this->context->addViolation( $constraint->message, array('%string%' => $value) ); } } }
We only loaded a Doctrine Orm dependency and, in the “validate” method, simply checked if the user already exists and generate a context violation.
In order to make it work, we must create a service that injects specified dependencies, just like that:
vendorname.user.validator.contains_user: class: VendorName\UserBundle\Validator\Constraints\ContainsUserValidator arguments: - @doctrine.orm.entity_manager tags: - { name: validator.constraint_validator, alias: contains_user }
Note that the alias must match the validateBy function return value in our constraint class.
Ok, we have now a constraint with a working validator.
The last thing to do is to call the constraint in FOSUserBundle validation file.
You must override the FOSUserBundle “validation.xml” file in your “Resources/config” directory.
We just need to add our constraint for the username property, so we only keep in this file, the username property constraints.
This is how our constraint must looks like:
<constraint name="VendorName\UserBundle\Validator\Constraints\ContainsUser"> <option name="message">fos_user.username.already_used</option> <option name="groups"> <value>Registration</value> <value>Profile</value> </option> </constraint>
if you want to keep the message specified in the constraint class, just delete the name=’message’ option.
The complete file must look like this.
<?xml version="1.0" ?> <constraint-mapping xmlns="http://symfony.com/schema/dic/constraint-mapping" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/dic/constraint-mapping http://symfony.com/schema/dic/constraint-mapping/constraint-mapping-1.0.xsd"> <class name="FOS\UserBundle\Model\User"> <property name="username"> <constraint name="NotBlank"> <option name="message">fos_user.username.blank</option> <option name="groups"> <value>Registration</value> <value>Profile</value> </option> </constraint> <constraint name="Headoo\UserBundle\Validator\Constraints\ContainsUser"> <option name="message">fos_user.username.already_used</option> <option name="groups"> <value>Registration</value> <value>Profile</value> </option> </constraint> <constraint name="Length"> <option name="min">2</option> <option name="minMessage">fos_user.username.short</option> <option name="max">255</option> <option name="maxMessage">fos_user.username.long</option> <option name="groups"> <value>Registration</value> <value>Profile</value> </option> </constraint> </property> </class> </constraint-mapping>
And that’s it, you have a fully functional customed constraint validation.
Have fun !
[…] Symfony2 tutorial: Create custom constraint validation and use it with FOSUserBundle […]
[…] Symfony2 tutorial: Create custom constraint validation and use it with FOSUserBundle […]
[…] Symfony2 tutorial: Create custom constraint validation and use it with FOSUserBundle […]
Hi thx for this but there is some mistakes :
—————————————————————————————————
Create a “ContainsUser.php” file in Validator/Contraints directory at your bundle root.
Must to be :
Create a “ContainsUser.php” file in Validator/Constraints directory at your bundle root.
———————————————————————————————
And
————————————————————————————————
arguments:
– @doctrine.orm.entity_manager
Must to be :
arguments:
[@doctrine.orm.entity_manager ]
————————————————————————————-
else it’s really perfect