This tutorial has a new version, check it out!

Beautiful Form 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

Guess what! Server-side validation is really, really fun. Google for Symfony validation, and find the book chapter.

There is one weird thing about validation... which I love. Here it is: you don't apply validation to your form. Nope, there will be no validation code inside of GenusFormType. Instead, you add validation to the class that is bound to your form. When the form is submitted, it automatically reads those validation rules and uses them.

Validation is added with annotations. So copy the use statement from the code block, find Genus and paste it on top:

... lines 1 - 6
use Symfony\Component\Validator\Constraints as Assert;
... lines 8 - 141

The Giant List of Constraints

Good start! Next, we'll add validation rules - called constraints - above each property. On the left side bar, find the "Constraints" link.

Check out this menu of validation rules: NotBlank, NotNull, Email, Length, Regex... so many things! Pretty much anything you can dream up is inside of this list.

Let's start with an easy one: above the name property, add @Assert\NotBlank:

... lines 1 - 12
class Genus
{
... lines 15 - 21
/**
* @Assert\NotBlank()
... line 24
*/
private $name;
... lines 27 - 139
}

Without doing anything else, refresh. Boom! Validation error. And, it looks nice.

Let's add some more. For subFamily - that should be required, so add @NotBlank:

... lines 1 - 12
class Genus
{
... lines 15 - 27
/**
* @Assert\NotBlank()
... lines 30 - 31
*/
private $subFamily;
... lines 34 - 143
}

For speciesCount, add @NotBlank again:

... lines 1 - 12
class Genus
{
... lines 15 - 34
/**
* @Assert\NotBlank()
... lines 37 - 38
*/
private $speciesCount;
... lines 41 - 143
}

But in addition to that, we want speciesCount to be a positive number: we don't want some funny biologist entering negative 10.

Constraint Options

On the constraints list, there's one called Range. Check that out.

Ok cool: just like the form field types, you can pass options to the constraints. The Range constraint has several: min, max, minMessage and maxMessage. Add @Assert\Range with min=0 and minMessage="Negative species! Come on...":

... lines 1 - 12
class Genus
{
... lines 15 - 34
/**
* @Assert\NotBlank()
* @Assert\Range(min=0, minMessage="Negative species! Come on...")
... line 38
*/
private $speciesCount;
... lines 41 - 143
}

Ok, let's finish up. It's ok if funFact is empty - so don't add anything there. The same is true for isPublished: we could add a constraint to make sure this is a boolean, but the sanity validation on the form already takes care of that.

Finally, let's make sure firstDiscoveredAt is also NotBlank:

... lines 1 - 12
class Genus
{
... lines 15 - 51
/**
* @Assert\NotBlank()
... line 54
*/
private $firstDiscoveredAt;
... lines 57 - 143
}

Ok, refresh! Leave everything blank and put -10 for the number of species. I love it!

Leave a comment!

What PHP libraries does this tutorial use?

// composer.json
{
    "require": {
        "php": ">=5.5.9",
        "symfony/symfony": "3.1.*", // v3.1.4
        "doctrine/orm": "^2.5", // v2.7.2
        "doctrine/doctrine-bundle": "^1.6", // 1.6.4
        "doctrine/doctrine-cache-bundle": "^1.2", // 1.3.0
        "symfony/swiftmailer-bundle": "^2.3", // v2.3.11
        "symfony/monolog-bundle": "^2.8", // 2.11.1
        "symfony/polyfill-apcu": "^1.0", // v1.2.0
        "sensio/distribution-bundle": "^5.0", // v5.0.22
        "sensio/framework-extra-bundle": "^3.0.2", // v3.0.16
        "incenteev/composer-parameter-handler": "^2.0", // v2.1.2
        "knplabs/knp-markdown-bundle": "^1.4", // 1.4.2
        "doctrine/doctrine-migrations-bundle": "^1.1" // 1.1.1
    },
    "require-dev": {
        "sensio/generator-bundle": "^3.0", // v3.0.7
        "symfony/phpunit-bridge": "^3.0", // v3.1.3
        "nelmio/alice": "^2.1", // 2.1.4
        "doctrine/doctrine-fixtures-bundle": "^2.3" // 2.3.0
    }
}