Skip to content
  • About
    • What is Symfony?
    • Community
    • News
    • Contributing
    • Support
  • Documentation
    • Symfony Docs
    • Symfony Book
    • Screencasts
    • Symfony Bundles
    • Symfony Cloud
    • Training
  • Services
    • SensioLabs Professional services to help you with Symfony
    • Platform.sh for Symfony Best platform to deploy Symfony apps
    • SymfonyInsight Automatic quality checks for your apps
    • Symfony Certification Prove your knowledge and boost your career
    • Blackfire Profile and monitor performance of your apps
  • Other
  • Blog
  • Download
sponsored by SensioLabs
  1. Home
  2. Documentation
  3. Validation
  • Documentation
  • Book
  • Reference
  • Bundles
  • Cloud

Table of Contents

  • Installation
  • The Basics of Validation
    • Using the Validator Service
    • Validation Callables
  • Constraints
    • Supported Constraints
    • Basic Constraints
    • String Constraints
    • Comparison Constraints
    • Number Constraints
    • Date Constraints
    • Choice Constraints
    • File Constraints
    • Financial and other Number Constraints
    • Other Constraints
    • Constraint Configuration
  • Constraints in Form Classes
  • Constraint Targets
    • Properties
    • Getters
    • Classes
  • Debugging the Constraints
  • Final Thoughts
  • Learn more

Validation

Edit this page

Validation

Validation is a very common task in web applications. Data entered in forms needs to be validated. Data also needs to be validated before it is written into a database or passed to a web service.

Symfony provides a Validator component to handle this for you. This component is based on the JSR303 Bean Validation specification.

Installation

In applications using Symfony Flex, run this command to install the validator before using it:

1
$ composer require symfony/validator doctrine/annotations

Note

If your application doesn't use Symfony Flex, you might need to do some manual configuration to enable validation. Check out the Validation configuration reference.

The Basics of Validation

The best way to understand validation is to see it in action. To start, suppose you've created a plain-old-PHP object that you need to use somewhere in your application:

1
2
3
4
5
6
7
// src/Entity/Author.php
namespace App\Entity;

class Author
{
    private $name;
}

So far, this is an ordinary class that serves some purpose inside your application. The goal of validation is to tell you if the data of an object is valid. For this to work, you'll configure a list of rules (called constraints) that the object must follow in order to be valid. These rules are usually defined using PHP code or annotations but they can also be defined as .yaml or .xml files inside the config/validator/ directory:

For example, to indicate that the $name property must not be empty, add the following:

1
2
3
4
5
6
7
8
9
10
11
12
13
// src/Entity/Author.php
namespace App\Entity;

// ...
use Symfony\Component\Validator\Constraints as Assert;

class Author
{
    /**
     * @Assert\NotBlank
     */
    private $name;
}
1
2
3
4
5
6
7
8
9
10
11
// src/Entity/Author.php
namespace App\Entity;

// ...
use Symfony\Component\Validator\Constraints as Assert;

class Author
{
    #[Assert\NotBlank]
    private $name;
}
1
2
3
4
5
# config/validator/validation.yaml
App\Entity\Author:
    properties:
        name:
            - NotBlank: ~
1
2
3
4
5
6
7
8
9
10
11
12
13
<!-- config/validator/validation.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<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
        https://symfony.com/schema/dic/constraint-mapping/constraint-mapping-1.0.xsd">

    <class name="App\Entity\Author">
        <property name="name">
            <constraint name="NotBlank"/>
        </property>
    </class>
</constraint-mapping>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// src/Entity/Author.php
namespace App\Entity;
// ...
use Symfony\Component\Validator\Constraints\NotBlank;
use Symfony\Component\Validator\Mapping\ClassMetadata;

class Author
{
    private $name;

    public static function loadValidatorMetadata(ClassMetadata $metadata)
    {
        $metadata->addPropertyConstraint('name', new NotBlank());
    }
}

Adding this configuration by itself does not yet guarantee that the value will not be blank; you can still set it to a blank value if you want. To actually guarantee that the value adheres to the constraint, the object must be passed to the validator service to be checked.

Tip

Symfony's validator uses PHP reflection, as well as "getter" methods, to get the value of any property, so they can be public, private or protected (see Validation).

Using the Validator Service

Next, to actually validate an Author object, use the validate() method on the validator service (which implements ValidatorInterface). The job of the validator is to read the constraints (i.e. rules) of a class and verify if the data on the object satisfies those constraints. If validation fails, a non-empty list of errors (ConstraintViolationList class) is returned. Take this simple example from inside a controller:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// ...
use App\Entity\Author;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Validator\Validator\ValidatorInterface;

// ...
public function author(ValidatorInterface $validator)
{
    $author = new Author();

    // ... do something to the $author object

    $errors = $validator->validate($author);

    if (count($errors) > 0) {
        /*
         * Uses a __toString method on the $errors variable which is a
         * ConstraintViolationList object. This gives us a nice string
         * for debugging.
         */
        $errorsString = (string) $errors;

        return new Response($errorsString);
    }

    return new Response('The author is valid! Yes!');
}

If the $name property is empty, you will see the following error message:

1
2
Object(App\Entity\Author).name:
    This value should not be blank.

If you insert a value into the name property, the happy success message will appear.

Tip

Most of the time, you won't interact directly with the validator service or need to worry about printing out the errors. Most of the time, you'll use validation indirectly when handling submitted form data. For more information, see how to validate Symfony forms.

You could also pass the collection of errors into a template:

1
2
3
4
5
if (count($errors) > 0) {
    return $this->render('author/validation.html.twig', [
        'errors' => $errors,
    ]);
}

Inside the template, you can output the list of errors exactly as needed:

1
2
3
4
5
6
7
{# templates/author/validation.html.twig #}
<h3>The author has the following errors</h3>
<ul>
{% for error in errors %}
    <li>{{ error.message }}</li>
{% endfor %}
</ul>

Note

Each validation error (called a "constraint violation"), is represented by a ConstraintViolation object.

Validation Callables

The Validation also allows you to create a closure to validate values against a set of constraints (useful for example when validating Console command answers or when validating OptionsResolver values):

createCallable()
This returns a closure that throws ValidationFailedException when the constraints aren't matched.
createIsValidCallable()
This returns a closure that returns false when the constraints aren't matched.

5.1

Validation::createCallable() was introduced in Symfony 5.1.

5.3

Validation::createIsValidCallable() was introduced in Symfony 5.3.

Constraints

The validator is designed to validate objects against constraints (i.e. rules). In order to validate an object, simply map one or more constraints to its class and then pass it to the validator service.

Behind the scenes, a constraint is simply a PHP object that makes an assertive statement. In real life, a constraint could be: 'The cake must not be burned'. In Symfony, constraints are similar: they are assertions that a condition is true. Given a value, a constraint will tell you if that value adheres to the rules of the constraint.

Supported Constraints

Symfony packages many of the most commonly-needed constraints:

Basic Constraints

These are the basic constraints: use them to assert very basic things about the value of properties or the return value of methods on your object.

  • NotBlank
  • Blank
  • NotNull
  • IsNull
  • IsTrue
  • IsFalse
  • Type

String Constraints

  • Email
  • ExpressionLanguageSyntax
  • Length
  • Url
  • Regex
  • Hostname
  • Ip
  • Cidr
  • Json
  • Uuid
  • Ulid
  • UserPassword
  • NotCompromisedPassword
  • CssColor

Comparison Constraints

  • EqualTo
  • NotEqualTo
  • IdenticalTo
  • NotIdenticalTo
  • LessThan
  • LessThanOrEqual
  • GreaterThan
  • GreaterThanOrEqual
  • Range
  • DivisibleBy
  • Unique

Number Constraints

  • Positive
  • PositiveOrZero
  • Negative
  • NegativeOrZero

Date Constraints

  • Date
  • DateTime
  • Time
  • Timezone

Choice Constraints

  • Choice
  • Language
  • Locale
  • Country

File Constraints

  • File
  • Image

Financial and other Number Constraints

  • Bic
  • CardScheme
  • Currency
  • Luhn
  • Iban
  • Isbn
  • Issn
  • Isin

Other Constraints

  • AtLeastOneOf
  • Sequentially
  • Compound
  • Callback
  • Expression
  • All
  • Valid
  • Cascade
  • Traverse
  • Collection
  • Count
  • UniqueEntity

You can also create your own custom constraints. This topic is covered in the How to Create a Custom Validation Constraint article.

Constraint Configuration

Some constraints, like NotBlank, are simple whereas others, like the Choice constraint, have several configuration options available. Suppose that the Author class has another property called genre that defines the literature genre mostly associated with the author, which can be set to either "fiction" or "non-fiction":

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// src/Entity/Author.php
namespace App\Entity;

// ...
use Symfony\Component\Validator\Constraints as Assert;

class Author
{
    /**
     * @Assert\Choice(
     *     choices = {"fiction", "non-fiction"},
     *     message = "Choose a valid genre."
     * )
     */
    private $genre;

    // ...
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// src/Entity/Author.php
namespace App\Entity;

// ...
use Symfony\Component\Validator\Constraints as Assert;

class Author
{
    #[Assert\Choice(
        choices: ['fiction', 'non-fiction'],
        message: 'Choose a valid genre.',
    )]
    private $genre;

    // ...
}
1
2
3
4
5
6
# config/validator/validation.yaml
App\Entity\Author:
    properties:
        genre:
            - Choice: { choices: [fiction, non-fiction], message: Choose a valid genre. }
        # ...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<!-- config/validator/validation.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<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
        https://symfony.com/schema/dic/constraint-mapping/constraint-mapping-1.0.xsd">

    <class name="App\Entity\Author">
        <property name="genre">
            <constraint name="Choice">
                <option name="choices">
                    <value>fiction</value>
                    <value>non-fiction</value>
                </option>
                <option name="message">Choose a valid genre.</option>
            </constraint>
        </property>

        <!-- ... -->
    </class>
</constraint-mapping>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// src/Entity/Author.php
namespace App\Entity;

// ...
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\Validator\Mapping\ClassMetadata;

class Author
{
    private $genre;

    // ...

    public static function loadValidatorMetadata(ClassMetadata $metadata)
    {
        // ...

        $metadata->addPropertyConstraint('genre', new Assert\Choice([
            'choices' => ['fiction', 'non-fiction'],
            'message' => 'Choose a valid genre.',
        ]));
    }
}

The options of a constraint can always be passed in as an array. Some constraints, however, also allow you to pass the value of one, "default", option in place of the array. In the case of the Choice constraint, the choices options can be specified in this way.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// src/Entity/Author.php
namespace App\Entity;

// ...
use Symfony\Component\Validator\Constraints as Assert;

class Author
{
    /**
     * @Assert\Choice({"fiction", "non-fiction"})
     */
    private $genre;

    // ...
}
1
2
3
4
5
6
7
8
9
10
11
12
13
// src/Entity/Author.php
namespace App\Entity;

// ...
use Symfony\Component\Validator\Constraints as Assert;

class Author
{
    #[Assert\Choice(['fiction', 'non-fiction'])]
    private $genre;

    // ...
}
1
2
3
4
5
6
# config/validator/validation.yaml
App\Entity\Author:
    properties:
        genre:
            - Choice: [fiction, non-fiction]
        # ...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!-- config/validator/validation.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<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
        https://symfony.com/schema/dic/constraint-mapping/constraint-mapping-1.0.xsd">

    <class name="App\Entity\Author">
        <property name="genre">
            <constraint name="Choice">
                <value>fiction</value>
                <value>non-fiction</value>
            </constraint>
        </property>

        <!-- ... -->
    </class>
</constraint-mapping>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// src/Entity/Author.php
namespace App\Entity;

// ...
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\Validator\Mapping\ClassMetadata;

class Author
{
    private $genre;

    public static function loadValidatorMetadata(ClassMetadata $metadata)
    {
        // ...

        $metadata->addPropertyConstraint(
            'genre',
            new Assert\Choice(['fiction', 'non-fiction'])
        );
    }
}

This is purely meant to make the configuration of the most common option of a constraint shorter and quicker.

If you're ever unsure of how to specify an option, either check the namespace Symfony\Component\Validator\Constraints for the constraint or play it safe by always passing in an array of options (the first method shown above).

Constraints in Form Classes

Constraints can be defined while building the form via the constraints option of the form fields:

1
2
3
4
5
6
7
8
9
public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder
        ->add('myField', TextType::class, [
            'required' => true,
            'constraints' => [new Length(['min' => 3])],
        ])
    ;
}

Constraint Targets

Constraints can be applied to a class property (e.g. name), a getter method (e.g. getFullName()) or an entire class. Property constraints are the most common and easy to use. Getter constraints allow you to specify more complex validation rules. Finally, class constraints are intended for scenarios where you want to validate a class as a whole.

Properties

Validating class properties is the most basic validation technique. Symfony allows you to validate private, protected or public properties. The next listing shows you how to configure the $firstName property of an Author class to have at least 3 characters.

1
2
3
4
5
6
7
8
9
10
11
12
13
// src/Entity/Author.php

// ...
use Symfony\Component\Validator\Constraints as Assert;

class Author
{
    /**
     * @Assert\NotBlank
     * @Assert\Length(min=3)
     */
    private $firstName;
}
1
2
3
4
5
6
7
8
9
10
11
// src/Entity/Author.php

// ...
use Symfony\Component\Validator\Constraints as Assert;

class Author
{
    #[Assert\NotBlank]
    #[Assert\Length(min: 3)]
    private $firstName;
}
1
2
3
4
5
6
7
# config/validator/validation.yaml
App\Entity\Author:
    properties:
        firstName:
            - NotBlank: ~
            - Length:
                min: 3
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!-- config/validator/validation.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<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
        https://symfony.com/schema/dic/constraint-mapping/constraint-mapping-1.0.xsd">

    <class name="App\Entity\Author">
        <property name="firstName">
            <constraint name="NotBlank"/>
            <constraint name="Length">
                <option name="min">3</option>
            </constraint>
        </property>
    </class>
</constraint-mapping>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// src/Entity/Author.php
namespace App\Entity;

// ...
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\Validator\Mapping\ClassMetadata;

class Author
{
    private $firstName;

    public static function loadValidatorMetadata(ClassMetadata $metadata)
    {
        $metadata->addPropertyConstraint('firstName', new Assert\NotBlank());
        $metadata->addPropertyConstraint(
            'firstName',
            new Assert\Length(['min' => 3])
        );
    }
}

Caution

The validator will use a value null if a typed property is uninitialized. This can cause unexpected behavior if the property holds a value when initialized. In order to avoid this, make sure all properties are initialized before validating them.

Getters

Constraints can also be applied to the return value of a method. Symfony allows you to add a constraint to any private, protected or public method whose name starts with "get", "is" or "has". In this guide, these types of methods are referred to as "getters".

The benefit of this technique is that it allows you to validate your object dynamically. For example, suppose you want to make sure that a password field doesn't match the first name of the user (for security reasons). You can do this by creating an isPasswordSafe() method, and then asserting that this method must return true:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// src/Entity/Author.php
namespace App\Entity;

// ...
use Symfony\Component\Validator\Constraints as Assert;

class Author
{
    /**
     * @Assert\IsTrue(message="The password cannot match your first name")
     */
    public function isPasswordSafe()
    {
        // ... return true or false
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// src/Entity/Author.php
namespace App\Entity;

// ...
use Symfony\Component\Validator\Constraints as Assert;

class Author
{
    #[Assert\IsTrue(message: 'The password cannot match your first name')]
    public function isPasswordSafe()
    {
        // ... return true or false
    }
}
1
2
3
4
5
# config/validator/validation.yaml
App\Entity\Author:
    getters:
        passwordSafe:
            - 'IsTrue': { message: 'The password cannot match your first name' }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!-- config/validator/validation.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<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
        https://symfony.com/schema/dic/constraint-mapping/constraint-mapping-1.0.xsd">

    <class name="App\Entity\Author">
        <getter property="passwordSafe">
            <constraint name="IsTrue">
                <option name="message">The password cannot match your first name</option>
            </constraint>
        </getter>
    </class>
</constraint-mapping>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// src/Entity/Author.php
namespace App\Entity;

// ...
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\Validator\Mapping\ClassMetadata;

class Author
{
    public static function loadValidatorMetadata(ClassMetadata $metadata)
    {
        $metadata->addGetterConstraint('passwordSafe', new Assert\IsTrue([
            'message' => 'The password cannot match your first name',
        ]));
    }
}

Now, create the isPasswordSafe() method and include the logic you need:

1
2
3
4
public function isPasswordSafe()
{
    return $this->firstName !== $this->password;
}

Note

The keen-eyed among you will have noticed that the prefix of the getter ("get", "is" or "has") is omitted in the mappings for the YAML, XML and PHP formats. This allows you to move the constraint to a property with the same name later (or vice versa) without changing your validation logic.

Classes

Some constraints apply to the entire class being validated. For example, the Callback constraint is a generic constraint that's applied to the class itself. When that class is validated, methods specified by that constraint are simply executed so that each can provide more custom validation.

Debugging the Constraints

5.2

The debug:validator command was introduced in Symfony 5.2.

Use the debug:validator command to list the validation constraints of a given class:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
$ php bin/console debug:validator 'App\Entity\SomeClass'

    App\Entity\SomeClass
    -----------------------------------------------------

    +---------------+--------------------------------------------------+---------+------------------------------------------------------------+
    | Property      | Name                                             | Groups  | Options                                                    |
    +---------------+--------------------------------------------------+---------+------------------------------------------------------------+
    | firstArgument | Symfony\Component\Validator\Constraints\NotBlank | Default | [                                                          |
    |               |                                                  |         |   "message" => "This value should not be blank.",          |
    |               |                                                  |         |   "allowNull" => false,                                    |
    |               |                                                  |         |   "normalizer" => null,                                    |
    |               |                                                  |         |   "payload" => null                                        |
    |               |                                                  |         | ]                                                          |
    | firstArgument | Symfony\Component\Validator\Constraints\Email    | Default | [                                                          |
    |               |                                                  |         |   "message" => "This value is not a valid email address.", |
    |               |                                                  |         |   "mode" => null,                                          |
    |               |                                                  |         |   "normalizer" => null,                                    |
    |               |                                                  |         |   "payload" => null                                        |
    |               |                                                  |         | ]                                                          |
    +---------------+--------------------------------------------------+---------+------------------------------------------------------------+

You can also validate all the classes stored in a given directory:

1
$ php bin/console debug:validator src/Entity

Final Thoughts

The Symfony validator is a powerful tool that can be leveraged to guarantee that the data of any object is "valid". The power behind validation lies in "constraints", which are rules that you can apply to properties or getter methods of your object. And while you'll most commonly use the validation framework indirectly when using forms, remember that it can be used anywhere to validate any object.

Learn more

  • How to Create a Custom Validation Constraint
  • How to Apply only a Subset of all Your Validation Constraints (Validation Groups)
  • How to Validate Raw Values (Scalar Values and Arrays)
  • How to Sequentially Apply Validation Groups
  • How to Handle Different Error Levels
  • How to Translate Validation Constraint Messages
This work, including the code samples, is licensed under a Creative Commons BY-SA 3.0 license.
TOC
    Version
    We stand with Ukraine.
    Version:

    Symfony 5.4 is backed by

    Make sure your project is risk free

    Make sure your project is risk free

    Measure & Improve Symfony Code Performance

    Measure & Improve Symfony Code Performance

    Symfony footer

    ↓ Our footer now uses the colors of the Ukrainian flag because Symfony stands with the people of Ukraine.

    Avatar of Kristof Van Cauwenbergh, a Symfony contributor

    Thanks Kristof Van Cauwenbergh (@kristofvc) for being a Symfony contributor

    6 commits • 29 lines changed

    View all contributors that help us make Symfony

    Become a Symfony contributor

    Be an active part of the community and contribute ideas, code and bug fixes. Both experts and newcomers are welcome.

    Learn how to contribute

    Symfony™ is a trademark of Symfony SAS. All rights reserved.

    • What is Symfony?

      • Symfony at a Glance
      • Symfony Components
      • Case Studies
      • Symfony Releases
      • Security Policy
      • Logo & Screenshots
      • Trademark & Licenses
      • symfony1 Legacy
    • Learn Symfony

      • Symfony Docs
      • Symfony Book
      • Reference
      • Bundles
      • Best Practices
      • Training
      • eLearning Platform
      • Certification
    • Screencasts

      • Learn Symfony
      • Learn PHP
      • Learn JavaScript
      • Learn Drupal
      • Learn RESTful APIs
    • Community

      • SymfonyConnect
      • Support
      • How to be Involved
      • Code of Conduct
      • Events & Meetups
      • Projects using Symfony
      • Downloads Stats
      • Contributors
      • Backers
    • Blog

      • Events & Meetups
      • A week of symfony
      • Case studies
      • Cloud
      • Community
      • Conferences
      • Diversity
      • Documentation
      • Living on the edge
      • Releases
      • Security Advisories
      • SymfonyInsight
      • Twig
      • SensioLabs
    • Services

      • SensioLabs services
      • Train developers
      • Manage your project quality
      • Improve your project performance
      • Host Symfony projects

      Deployed on

    Follow Symfony