发布于 2015-08-27 16:29:29 | 254 次阅读 | 评论: 0 | 来源: 网络整理
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 ships with a Validator component that makes this task easy and transparent. This component is based on the JSR303 Bean Validation specification.
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:
// src/AppBundle/Entity/Author.php namespace AppBundleEntity; class Author { public $name; }
So far, this is just 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 can be specified via a number of different formats (YAML, XML, annotations, or PHP).
For example, to guarantee that the $name
property is not empty, add the following:
// src/AppBundle/Entity/Author.php // ... use SymfonyComponentValidatorConstraints as Assert; class Author { /** * @AssertNotBlank() */ public $name; }
# src/AppBundle/Resources/config/validation.yml AppBundleEntityAuthor: properties: name: - NotBlank: ~
<!-- src/AppBundle/Resources/config/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 http://symfony.com/schema/dic/constraint-mapping/constraint-mapping-1.0.xsd"> <class name="AppBundleEntityAuthor"> <property name="name"> <constraint name="NotBlank" /> </property> </class> </constraint-mapping>
// src/AppBundle/Entity/Author.php // ... use SymfonyComponentValidatorMappingClassMetadata; use SymfonyComponentValidatorConstraintsNotBlank; class Author { public $name; public static function loadValidatorMetadata(ClassMetadata $metadata) { $metadata->addPropertyConstraint('name', new NotBlank()); } }
小技巧
Protected and private properties can also be validated, as well as “getter” methods (see 校验的目标).
validator
服务¶Next, to actually validate an Author
object, use the validate
method on the validator
service (class Validator
). The job of the validator
is easy: 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 (class ConstraintViolationList
) is returned. Take this simple example from inside a controller:
// ... use SymfonyComponentHttpFoundationResponse; use AppBundleEntityAuthor; // ... public function authorAction() { $author = new Author(); // ... do something to the $author object $validator = $this->get('validator'); $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:
AppBundleAuthor.name: This value should not be blank
If you insert a value into the name
property, the happy success message will appear.
小技巧
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 the 校验与表单.
You could also pass the collection of errors into a template:
if (count($errors) > 0) { return $this->render('author/validation.html.twig', array( 'errors' => $errors, )); }
Inside the template, you can output the list of errors exactly as needed:
{# app/Resources/views/author/validation.html.twig #} <h3>The author has the following errors</h3> <ul> {% for error in errors %} <li>{{ error.message }}</li> {% endfor %} </ul>
<!-- app/Resources/views/author/validation.html.php --> <h3>The author has the following errors</h3> <ul> <?php foreach ($errors as $error): ?> <li><?php echo $error->getMessage() ?></li> <?php endforeach ?> </ul>
注解
Each validation error (called a “constraint violation”), is represented by a ConstraintViolation
object.
The validator
service can be used at any time to validate any object. In reality, however, you’ll usually work with the validator
indirectly when working with forms. Symfony’s form library uses the validator
service internally to validate the underlying object after values have been submitted. The constraint violations on the object are converted into FieldError
objects that can easily be displayed with your form. The typical form submission workflow looks like the following from inside a controller:
// ... use AppBundleEntityAuthor; use AppBundleFormAuthorType; use SymfonyComponentHttpFoundationRequest; // ... public function updateAction(Request $request) { $author = new Author(); $form = $this->createForm(new AuthorType(), $author); $form->handleRequest($request); if ($form->isValid()) { // the validation passed, do something with the $author object return $this->redirectToRoute(...); } return $this->render('author/form.html.twig', array( 'form' => $form->createView(), )); }
注解
This example uses an AuthorType
form class, which is not shown here.
For more information, see the Forms chapter.
The Symfony validator is enabled by default, but you must explicitly enable annotations if you’re using the annotation method to specify your constraints:
# app/config/config.yml framework: validation: { enable_annotations: true }
<!-- app/config/config.xml --> <?xml version="1.0" encoding="UTF-8" ?> <container xmlns="http://symfony.com/schema/dic/services" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:framework="http://symfony.com/schema/dic/symfony" xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd http://symfony.com/schema/dic/symfony http://symfony.com/schema/dic/symfony/symfony-1.0.xsd"> <framework:config> <framework:validation enable-annotations="true" /> </framework:config> </container>
// app/config/config.php $container->loadFromExtension('framework', array( 'validation' => array( 'enable_annotations' => true, ), ));
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.
Symfony packages many of the most commonly-needed 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.
You can also create your own custom constraints. This topic is covered in the “How to Create a custom Validation Constraint” article of the cookbook.
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 gender
that can be set to either “male” or “female”:
// src/AppBundle/Entity/Author.php // ... use SymfonyComponentValidatorConstraints as Assert; class Author { /** * @AssertChoice( * choices = { "male", "female" }, * message = "Choose a valid gender." * ) */ public $gender; // ... }
# src/AppBundle/Resources/config/validation.yml AppBundleEntityAuthor: properties: gender: - Choice: { choices: [male, female], message: Choose a valid gender. } # ...
<!-- src/AppBundle/Resources/config/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 http://symfony.com/schema/dic/constraint-mapping/constraint-mapping-1.0.xsd"> <class name="AppBundleEntityAuthor"> <property name="gender"> <constraint name="Choice"> <option name="choices"> <value>male</value> <value>female</value> </option> <option name="message">Choose a valid gender.</option> </constraint> </property> <!-- ... --> </class> </constraint-mapping>
// src/AppBundle/Entity/Author.php // ... use SymfonyComponentValidatorMappingClassMetadata; use SymfonyComponentValidatorConstraints as Assert; class Author { public $gender; // ... public static function loadValidatorMetadata(ClassMetadata $metadata) { // ... $metadata->addPropertyConstraint('gender', new AssertChoice(array( 'choices' => array('male', 'female'), 'message' => 'Choose a valid gender.', ))); } }
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.
// src/AppBundle/Entity/Author.php // ... use SymfonyComponentValidatorConstraints as Assert; class Author { /** * @AssertChoice({"male", "female"}) */ protected $gender; // ... }
# src/AppBundle/Resources/config/validation.yml AppBundleEntityAuthor: properties: gender: - Choice: [male, female] # ...
<!-- src/AppBundle/Resources/config/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 http://symfony.com/schema/dic/constraint-mapping/constraint-mapping-1.0.xsd"> <class name="AppBundleEntityAuthor"> <property name="gender"> <constraint name="Choice"> <value>male</value> <value>female</value> </constraint> </property> <!-- ... --> </class> </constraint-mapping>
// src/AppBundle/Entity/Author.php // ... use SymfonyComponentValidatorMappingClassMetadata; use SymfonyComponentValidatorConstraints as Assert; class Author { protected $gender; public static function loadValidatorMetadata(ClassMetadata $metadata) { // ... $metadata->addPropertyConstraint( 'gender', new AssertChoice(array('male', 'female')) ); } }
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 API documentation for the constraint or play it safe by always passing in an array of options (the first method shown above).
Constraints can be applied to a class property (e.g. name
) or a public getter method (e.g. getFullName
). The first is the most common and easy to use, but the second allows you to specify more complex validation rules.
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.
// AppBundle/Entity/Author.php // ... use SymfonyComponentValidatorConstraints as Assert; class Author { /** * @AssertNotBlank() * @AssertLength(min=3) */ private $firstName; }
# src/AppBundle/Resources/config/validation.yml AppBundleEntityAuthor: properties: firstName: - NotBlank: ~ - Length: min: 3
<!-- src/AppBundle/Resources/config/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 http://symfony.com/schema/dic/constraint-mapping/constraint-mapping-1.0.xsd"> <class name="AppBundleEntityAuthor"> <property name="firstName"> <constraint name="NotBlank" /> <constraint name="Length"> <option name="min">3</option> </constraint> </property> </class> </constraint-mapping>
// src/AppBundle/Entity/Author.php // ... use SymfonyComponentValidatorMappingClassMetadata; use SymfonyComponentValidatorConstraints as Assert; class Author { private $firstName; public static function loadValidatorMetadata(ClassMetadata $metadata) { $metadata->addPropertyConstraint('firstName', new AssertNotBlank()); $metadata->addPropertyConstraint( 'firstName', new AssertLength(array("min" => 3)) ); } }
Constraints can also be applied to the return value of a method. Symfony allows you to add a constraint to any 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 isPasswordLegal
method, and then asserting that this method must return true
:
// src/AppBundle/Entity/Author.php // ... use SymfonyComponentValidatorConstraints as Assert; class Author { /** * @AssertTrue(message = "The password cannot match your first name") */ public function isPasswordLegal() { // ... return true or false } }
# src/AppBundle/Resources/config/validation.yml AppBundleEntityAuthor: getters: passwordLegal: - "True": { message: "The password cannot match your first name" }
<!-- src/AppBundle/Resources/config/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 http://symfony.com/schema/dic/constraint-mapping/constraint-mapping-1.0.xsd"> <class name="AppBundleEntityAuthor"> <getter property="passwordLegal"> <constraint name="True"> <option name="message">The password cannot match your first name</option> </constraint> </getter> </class> </constraint-mapping>
// src/AppBundle/Entity/Author.php // ... use SymfonyComponentValidatorMappingClassMetadata; use SymfonyComponentValidatorConstraints as Assert; class Author { public static function loadValidatorMetadata(ClassMetadata $metadata) { $metadata->addGetterConstraint('passwordLegal', new AssertTrue(array( 'message' => 'The password cannot match your first name', ))); } }
Now, create the isPasswordLegal()
method and include the logic you need:
public function isPasswordLegal() { return $this->firstName !== $this->password; }
注解
The keen-eyed among you will have noticed that the prefix of the getter (“get”, “is” or “has”) is omitted in the mapping. This allows you to move the constraint to a property with the same name later (or vice versa) without changing your validation logic.
So far, you’ve been able to add constraints to a class and ask whether or not that class passes all the defined constraints. In some cases, however, you’ll need to validate an object against only some constraints on that class. To do this, you can organize each constraint into one or more “validation groups”, and then apply validation against just one group of constraints.
For example, suppose you have a User
class, which is used both when a user registers and when a user updates their contact information later:
// src/AppBundle/Entity/User.php namespace AppBundleEntity; use SymfonyComponentSecurityCoreUserUserInterface; use SymfonyComponentValidatorConstraints as Assert; class User implements UserInterface { /** * @AssertEmail(groups={"registration"}) */ private $email; /** * @AssertNotBlank(groups={"registration"}) * @AssertLength(min=7, groups={"registration"}) */ private $password; /** * @AssertLength(min=2) */ private $city; }
# src/AppBundle/Resources/config/validation.yml AppBundleEntityUser: properties: email: - Email: { groups: [registration] } password: - NotBlank: { groups: [registration] } - Length: { min: 7, groups: [registration] } city: - Length: min: 2
<!-- src/AppBundle/Resources/config/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 http://symfony.com/schema/dic/constraint-mapping/constraint-mapping-1.0.xsd "> <class name="AppBundleEntityUser"> <property name="email"> <constraint name="Email"> <option name="groups"> <value>registration</value> </option> </constraint> </property> <property name="password"> <constraint name="NotBlank"> <option name="groups"> <value>registration</value> </option> </constraint> <constraint name="Length"> <option name="min">7</option> <option name="groups"> <value>registration</value> </option> </constraint> </property> <property name="city"> <constraint name="Length"> <option name="min">7</option> </constraint> </property> </class> </constraint-mapping>
// src/AppBundle/Entity/User.php namespace AppBundleEntity; use SymfonyComponentValidatorMappingClassMetadata; use SymfonyComponentValidatorConstraints as Assert; class User { public static function loadValidatorMetadata(ClassMetadata $metadata) { $metadata->addPropertyConstraint('email', new AssertEmail(array( 'groups' => array('registration'), ))); $metadata->addPropertyConstraint('password', new AssertNotBlank(array( 'groups' => array('registration'), ))); $metadata->addPropertyConstraint('password', new AssertLength(array( 'min' => 7, 'groups' => array('registration'), ))); $metadata->addPropertyConstraint('city', new AssertLength(array( "min" => 3, ))); } }
With this configuration, there are three validation groups:
Default
User
User
object in the Default
group. This is always the name of the class. The difference between this and Default
is explained below.registration
email
and password
fields only.Constraints in the Default
group of a class are the constraints that have either no explicit group configured or that are configured to a group equal to the class name or the string Default
.
警告
When validating just the User object, there is no difference between the Default
group and the User
group. But, there is a difference if User
has embedded objects. For example, imagine User
has an address
property that contains some Address
object and that you’ve added the Valid constraint to this property so that it’s validated when you validate the User
object.
If you validate User
using the Default
group, then any constraints on the Address
class that are in the Default
group will be used. But, if you validate User
using the User
validation group, then only constraints on the Address
class with the User
group will be validated.
In other words, the Default
group and the class name group (e.g. User
) are identical, except when the class is embedded in another object that’s actually the one being validated.
If you have inheritance (e.g. User extends BaseUser
) and you validate with the class name of the subclass (i.e. User
), then all constraints in the User
and BaseUser
will be validated. However, if you validate using the base class (i.e. BaseUser
), then only the default constraints in the BaseUser
class will be validated.
To tell the validator to use a specific group, pass one or more group names as the third argument to the validate()
method:
// If you're using the new 2.5 validation API (you probably are!) $errors = $validator->validate($author, null, array('registration')); // If you're using the old 2.4 validation API, pass the group names as the second argument // $errors = $validator->validate($author, array('registration'));
If no groups are specified, all constraints that belong to the group Default
will be applied.
Of course, you’ll usually work with validation indirectly through the form library. For information on how to use validation groups inside forms, see 验证规则组.
In some cases, you want to validate your groups by steps. To do this, you can use the GroupSequence
feature. In this case, an object defines a group sequence, which determines the order groups should be validated.
For example, suppose you have a User
class and want to validate that the username and the password are different only if all other validation passes (in order to avoid multiple error messages).
// src/AppBundle/Entity/User.php namespace AppBundleEntity; use SymfonyComponentSecurityCoreUserUserInterface; use SymfonyComponentValidatorConstraints as Assert; /** * @AssertGroupSequence({"User", "Strict"}) */ class User implements UserInterface { /** * @AssertNotBlank */ private $username; /** * @AssertNotBlank */ private $password; /** * @AssertTrue(message="The password cannot match your username", groups={"Strict"}) */ public function isPasswordLegal() { return ($this->username !== $this->password); } }
# src/AppBundle/Resources/config/validation.yml AppBundleEntityUser: group_sequence: - User - Strict getters: passwordLegal: - "True": message: "The password cannot match your username" groups: [Strict] properties: username: - NotBlank: ~ password: - NotBlank: ~
<!-- src/AppBundle/Resources/config/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 http://symfony.com/schema/dic/constraint-mapping/constraint-mapping-1.0.xsd"> <class name="AppBundleEntityUser"> <property name="username"> <constraint name="NotBlank" /> </property> <property name="password"> <constraint name="NotBlank" /> </property> <getter property="passwordLegal"> <constraint name="True"> <option name="message">The password cannot match your username</option> <option name="groups"> <value>Strict</value> </option> </constraint> </getter> <group-sequence> <value>User</value> <value>Strict</value> </group-sequence> </class> </constraint-mapping>
// src/AppBundle/Entity/User.php namespace AppBundleEntity; use SymfonyComponentValidatorMappingClassMetadata; use SymfonyComponentValidatorConstraints as Assert; class User { public static function loadValidatorMetadata(ClassMetadata $metadata) { $metadata->addPropertyConstraint('username', new AssertNotBlank()); $metadata->addPropertyConstraint('password', new AssertNotBlank()); $metadata->addGetterConstraint('passwordLegal', new AssertTrue(array( 'message' => 'The password cannot match your first name', 'groups' => array('Strict'), ))); $metadata->setGroupSequence(array('User', 'Strict')); } }
In this example, it will first validate all constraints in the group User
(which is the same as the Default
group). Only if all constraints in that group are valid, the second group, Strict
, will be validated.
警告
As you have already seen in the previous section, the Default
group and the group containing the class name (e.g. User
) were identical. However, when using Group Sequences, they are no longer identical. The Default
group will now reference the group sequence, instead of all constraints that do not belong to any group.
This means that you have to use the {ClassName}
(e.g. User
) group when specifying a group sequence. When using Default
, you get an infinite recursion (as the Default
group references the group sequence, which will contain the Default
group which references the same group sequence, ...).
Imagine a User
entity which can be a normal user or a premium user. When it’s a premium user, some extra constraints should be added to the user entity (e.g. the credit card details). To dynamically determine which groups should be activated, you can create a Group Sequence Provider. First, create the entity and a new constraint group called Premium
:
// src/AppBundle/Entity/User.php namespace AppBundleEntity; use SymfonyComponentValidatorConstraints as Assert; class User { /** * @AssertNotBlank() */ private $name; /** * @AssertCardScheme( * schemes={"VISA"}, * groups={"Premium"}, * ) */ private $creditCard; // ... }
# src/AppBundle/Resources/config/validation.yml AppBundleEntityUser: properties: name: - NotBlank: ~ creditCard: - CardScheme: schemes: [VISA] groups: [Premium]
<!-- src/AppBundle/Resources/config/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 http://symfony.com/schema/dic/constraint-mapping/constraint-mapping-1.0.xsd"> <class name="AppBundleEntityUser"> <property name="name"> <constraint name="NotBlank" /> </property> <property name="creditCard"> <constraint name="CardScheme"> <option name="schemes"> <value>VISA</value> </option> <option name="groups"> <value>Premium</value> </option> </constraint> </property> <!-- ... --> </class> </constraint-mapping>
// src/AppBundle/Entity/User.php namespace AppBundleEntity; use SymfonyComponentValidatorConstraints as Assert; use SymfonyComponentValidatorMappingClassMetadata; class User { private $name; private $creditCard; // ... public static function loadValidatorMetadata(ClassMetadata $metadata) { $metadata->addPropertyConstraint('name', new AssertNotBlank()); $metadata->addPropertyConstraint('creditCard', new AssertCardScheme( 'schemes' => array('VISA'), 'groups' => array('Premium'), )); } }
Now, change the User
class to implement GroupSequenceProviderInterface
and add the getGroupSequence()
, method, which should return an array of groups to use:
// src/AppBundle/Entity/User.php namespace AppBundleEntity; // ... use SymfonyComponentValidatorGroupSequenceProviderInterface; class User implements GroupSequenceProviderInterface { // ... public function getGroupSequence() { $groups = array('User'); if ($this->isPremium()) { $groups[] = 'Premium'; } return $groups; } }
At last, you have to notify the Validator component that your User
class provides a sequence of groups to be validated:
// src/AppBundle/Entity/User.php namespace AppBundleEntity; // ... /** * @AssertGroupSequenceProvider */ class User implements GroupSequenceProviderInterface { // ... }
# src/AppBundle/Resources/config/validation.yml AppBundleEntityUser: group_sequence_provider: true
<!-- src/AppBundle/Resources/config/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 http://symfony.com/schema/dic/constraint-mapping/constraint-mapping-1.0.xsd"> <class name="AppBundleEntityUser"> <group-sequence-provider /> <!-- ... --> </class> </constraint-mapping>
// src/AppBundle/Entity/User.php namespace AppBundleEntity; // ... use SymfonyComponentValidatorMappingClassMetadata; class User implements GroupSequenceProviderInterface { // ... public static function loadValidatorMetadata(ClassMetadata $metadata) { $metadata->setGroupSequenceProvider(true); // ... } }
So far, you’ve seen how you can validate entire objects. But sometimes, you just want to validate a simple value - like to verify that a string is a valid email address. This is actually pretty easy to do. From inside a controller, it looks like this:
// ... use SymfonyComponentValidatorConstraints as Assert; // ... public function addEmailAction($email) { $emailConstraint = new AssertEmail(); // all constraint "options" can be set this way $emailConstraint->message = 'Invalid email address'; // use the validator to validate the value // If you're using the new 2.5 validation API (you probably are!) $errorList = $this->get('validator')->validate( $email, $emailConstraint ); // If you're using the old 2.4 validation API /* $errorList = $this->get('validator')->validateValue( $email, $emailConstraint ); */ if (0 === count($errorList)) { // ... this IS a valid email address, do something } else { // this is *not* a valid email address $errorMessage = $errorList[0]->getMessage(); // ... do something with the error } // ... }
By calling validate
on the validator, you can pass in a raw value and the constraint object that you want to validate that value against. A full list of the available constraints - as well as the full class name for each constraint - is available in the constraints reference section.
The validate
method returns a ConstraintViolationList
object, which acts just like an array of errors. Each error in the collection is a ConstraintViolation
object, which holds the error message on its getMessage
method.
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.