Symfony2 tutorial: Create custom constraint validation and use it with FOSUserBundle

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 !

Advertisements
Symfony2 tutorial: Create custom constraint validation and use it with FOSUserBundle

4 thoughts on “Symfony2 tutorial: Create custom constraint validation and use it with FOSUserBundle

  1. Zelkin says:

    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

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s