Flag of Ukraine
SymfonyCasts stands united with the people of Ukraine
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!

5
Login or Register to join the conversation
Neal O. Avatar
Neal O. Avatar Neal O. | posted 4 years ago

Following along wit the tutorial during the server side validation portion I have the @Assert/Regex as shown. But error message for that field always comes up "The value is not valid". I do have the use statement all other errors using @Assert work. What could I be missing

Reply

Hi Neal!

I don't know the answer, but I can help point you in the right direction. The "The value is not valid" is a message that doesn't come from the @Assert\-style validation - it's actually coming from the form field itself. For example, if setup a field to be a "number" form field type, and then type in a string, you'll get this error (some browsers prevent this, but just follow my idea). I call this type of validation, "sanity validation" - it's when the value you put in just doesn't make sense at all for the field type you did. So double-check what field type you have and see what's going on - but don't worry about your @Assert stuff - the issue isn't there :).

Here's an example of where that message comes from for the integer type (but this message is used if you fail "sanity validation" on any form field type): http://symfony.com/doc/curr...

Let me know how it goes!

Reply
Neal O. Avatar

Thanks Ryan,

The field type is set to password

$builder
->add('username', 'text')
->add('email', 'email', array(
'required' => false,
'label' =>'Email Address',
'attr' => array('class' => 'C-3P0')
))
->add('plainPassword', 'repeated', array(
'type' => 'password'
));

Which I would think would just be a string. The private $plainPassword is set to @var string and the getter and setter for it are both using string. At a loss here I'm sure is is something simple that I am just over looking.

Reply

Hey Neal!

You're right - the password type does *not* have any of this "sanity validation" on it, nor does the email type of the text type. With the form you posted, the only place it could be coming from is the "repeated" type, which will throw this error if the passwords don't match. To absolutely make sure that the problem is being caused by the plainPassword field, add the invalid_message option to it (http://symfony.com/doc/curr... and set it to something different than "this value is not valid". If this successfully changes the message, then the issue is *definitely* that Symfony thinks that the 2 password fields don't match. Then, it should be easier to debug :).

Cheers!

Reply
Neal O. Avatar

Thanks it was the repeated field getting to understand how all these interact is tricky. Great Tutorials. Look forward to whats to come

Reply
Cat in space

"Houston: no signs of life"
Start the conversation!

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
    }
}
userVoice