This tutorial has a new version, check it out!

Server-Side Validation

Keep on Learning!

If you liked what you've learned so far, dive in!
Subscribe to get access to this tutorial plus
video, code and script downloads.

Start your All-Access Pass
Buy just this tutorial for $12.00

Server-Side Validation

In Symfony, validation is done a little bit differently. Instead of validating the submitted form data itself, validation is applied to the User object.

Start by heading to the validation chapter of the documentation. Click on the “Annotations” tab of the code example and copy the use statement. Paste this into your User class:

// src/Yoda/UserBundle/Entity/User.php
// ...

use Symfony\Component\Validator\Constraints as Assert;

Whenever you add annotations, you need a use statement.

Basic Constraints and Options

Adding a validation constraint is easy. To make the username field required, add @Assert\NotBlank above the property:

// src/Yoda/UserBundle/Entity/User.php
// ...

/**
 * @ORM\Column(name="username", type="string", length=255)
 * @Assert\NotBlank()
 */
private $username;

Try it out! When we submit the form blank, we see the validation error above the field. It looks terrible, but we’ll work on that later. To customize the message, add the message option:

// src/Yoda/UserBundle/Entity/User.php
// ...

/**
 * @ORM\Column(name="username", type="string", length=255)
 * @Assert\NotBlank(message="Put in a username you rebel scum :P")
 */
private $username;

Refresh to see the new error.

All of this magic happens automatically when we call handleRequest in our controller. This takes the submitted values, pushes them into the User object, and then applies validation.

Add all the Constraints!

Let’s keep going. We can use the Length constraint to make sure the username is at least 3 characters long:

/**
 * @ORM\Column(name="username", type="string", length=255)
 * @Assert\NotBlank(message="Put in a username of course!")
 * @Assert\Length(min=3, minMessage="Give us at least 3 characters!")
 */
private $username;

For the email property, use NotBlank and Email to guarantee that it’s a valid email address:

/**
 * @ORM\Column(type="string", length=255)
 * @Assert\NotBlank
 * @Assert\Email
 */
private $email;

For plainPassword, we can use the NotBlank constraint and the Regex constraint to guarantee a strong password:

/**
 * @Assert\NotBlank
 * @Assert\Regex(
 *      pattern="/^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?!.*\s).*$/",
 *      message="Use 1 upper case letter, 1 lower case letter, and 1 number"
 * )
 */
private $plainPassword;

Let’s try this out by filling out the form in different ways. All the errors show up! They’re just really ugly.

Docs for The Built-In Constraints

Symfony comes packed with a lot of other constraints you can use. Check them out in the reference section of the documentation. You can see the Length constraint we just used and all of the options for it. Cool!

The UniqueEntity Constraint

Check out the UniqueEntity constraint. This is useful if you need to make sure a value stays unique in the database. We need to make sure that nobody signs up using an existing username or email address, so this is perfect.

The UniqueEntity constraint is special because unlike the others, this one requires a different use statement. Copy it into your User class. Also, @UniqueEntity goes above the class, not above a property. It takes two options: the field that should be unique followed by a message. Add a constraint for both the username and the email:

// src/Yoda/UserBundle/Entity/User.php
// ...

use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;

/**
 * @ORM\Table(name="yoda_user")
 * @ORM\Entity(repositoryClass="Yoda\UserBundle\Entity\UserRepository")
 * @UniqueEntity(fields="username", message="That username is taken!")
 * @UniqueEntity(fields="email", message="That email is taken!")
 */
class User implements AdvancedUserInterface, Serializable

Tip

"username" is equivalent to fields="username". fields is the “default” option. If it’s the only option you’re using, saying fields isn’t needed. See Constraint Configuration.

If we try to register with an existing username or email, we see the error!

The Callback Constraint

Before we move on, I want to show you one more useful constraint: Callback. This constraint is awesome because it lets you create a method inside your class that’s called during validation. You can apply whatever logic you need to figure out if the object is valid. You can even place the errors on exactly which field you want. If you have a more difficult validation problem, this might be exactly what you need.

We won’t show it here, but check it out.

Tip

You can also check Custom Validation, Callback and Constraints page of our “Question and Answer Day” tutorial to learn more about custom validation in Symfony with a bunch of examples and use cases.

Leave a comment!

What PHP libraries does this tutorial use?

// composer.json
{
    "require": {
        "php": ">=5.3.3",
        "symfony/symfony": "~2.4", // v2.4.2
        "doctrine/orm": "~2.2,>=2.2.3", // v2.4.2
        "doctrine/doctrine-bundle": "~1.2", // v1.2.0
        "twig/extensions": "~1.0", // v1.0.1
        "symfony/assetic-bundle": "~2.3", // v2.3.0
        "symfony/swiftmailer-bundle": "~2.3", // v2.3.5
        "symfony/monolog-bundle": "~2.4", // v2.5.0
        "sensio/distribution-bundle": "~2.3", // v2.3.4
        "sensio/framework-extra-bundle": "~3.0", // v3.0.0
        "sensio/generator-bundle": "~2.3", // v2.3.4
        "incenteev/composer-parameter-handler": "~2.0", // v2.1.0
        "doctrine/doctrine-fixtures-bundle": "~2.2.0", // v2.2.0
        "ircmaxell/password-compat": "~1.0.3", // 1.0.3
        "phpunit/phpunit": "~4.1" // 4.1.0
    }
}