Validation
Validation (Validation) is an extremely common task in Web programs. Data entered in the form requires validation. Data also needs to be validated when written to a database or transferred to a web service.
Symfony comes with a Validator component, which makes the verification work simple and transparent. This component is based on JSR303 Bean verification specification.
Basics of verification ¶
The best way to understand verification is to see its practical application. Before we begin, let's assume you create a native PHP object that is used somewhere your program needs:
// src/AppBundle/Entity/Author.phpnamespace AppBundle\Entity; class Author{ public $name;}
So far, this is just a normal class that serves some purpose for your program. The purpose of verification is to tell you whether the data in the object is valid. To do this, you need to configure a list of rules (called constraints/constraints) that the object must follow in order to be valid. These rules can be specified in a number of different formats (YAML, XML, annotations or PHP).
For example, to ensure that the attribute $name
is not empty, add the following:
PHP:// src/AppBundle/Entity/Author.php // ...use Symfony\Component\Validator\Mapping\ClassMetadata;use Symfony\Component\Validator\Constraints\NotBlank; class Author{ public $name; public static function loadValidatorMetadata(ClassMetadata $metadata) { $metadata->addPropertyConstraint('name', new NotBlank()); }}
XML:<!-- 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="AppBundle\Entity\Author"> <property name="name"> <constraint name="NotBlank" /> </property> </class></constraint-mapping>
YAML:# src/AppBundle/Resources/config/validation.ymlAppBundle\Entity\Author: properties: name: - NotBlank: ~
Annotations:// src/AppBundle/Entity/Author.php // ...use Symfony\Component\Validator\Constraints as Assert; class Author{ /** * @Assert\NotBlank() */ public $name;}
Protected and private attributes and "getter" methods can also be verified (see Constrained delivery scope).
Use verification service ¶
Next, to actually verify the Author
object, use validator
The validate method of the service (
Validator class).
validator
The job is simple: read the constraint rules of a class to verify whether the object data satisfies these constraints. If validation fails, a non-empty error list (class ConstraintViolationList
) will be returned. Implement this simple example in a controller:
// ...use Symfony\Component\HttpFoundation\Response;use AppBundle\Entity\Author; // ...public function authorAction(){ $author = new Author(); // ... do something to the $author object // ... 对 $author 对象做一些事 $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. * 对 $errors 变量,即 ConstraintViolationList 对象,使用 __toString 方法。 * 这给了我们一个美观的字符串用于调试。 */ $errorsString = (string) $errors; return new Response($errorsString); } return new Response('The author is valid! Yes!');}
If the $name
property is empty, you will see an error message:
If you insert a value for the name
attribute, a pleasant success message will appear.
Most of the time, you don't need to interact directly with the validator
service, or worry about outputting error messages. In most cases, you use validation indirectly when processing submitted form data. See Validation and Forms to learn more.
You can also pass a "collection of errors" to the template:
if (count($errors) > 0) { return $this->render('author/validation.html.twig', array( 'errors' => $errors, ));}
In the template, you can output the exact error list as needed:
PHP:<!-- 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>
Twig:{# 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>
Every validation error (called a "constraint violation/constraint violation") is caused by A ConstraintViolation
object to render.
Configuration ¶
#Symfony’s validator is enabled by default, but if you use annotation to specify constraints, you must explicitly enable it ( used for verification) annotation:
PHP:// app/config/config.php$container->loadFromExtension('framework', array( 'validation' => array( 'enable_annotations' => true, ),));
XML:<!-- 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>
YAML:# app/config/config.ymlframework: validation: { enable_annotations: true }
Constraint Rules ¶
Validator
is designed to validate objects against constraints (i.e. rules). To validate an object, simply map one or more constraints to the class it is validating and then pass it to the validator
service.
Behind the scenes, a constraint is a PHP object that generates a statement for decision making. In practice, a constraint could be "the cake must not burn". In Symfony, constraints are similar: they are assertions about whether a condition is true. Given a value, the constraint tells you whether the value obeys your constraint rules.
Supported constraints ¶
Symfony encapsulates many of the most commonly used constraints:
Basic constraints ¶
These are basic constraints: use them to assert very basic things about property values, or to assert the return values of methods in your program.
¶- Url
- Regex
- ##Ip
- Uuid
- Number constraints ¶
Range
##EqualTo
- NotEqualTo
- IdenticalTo
- NotIdenticalTo
- LessThan
- ##LessThanOrEqual
- GreaterThan
- GreaterThanOrEqual
- ##Date Constraints ¶
Date
- ##DateTime
- Time
¶
- ##Choice
- Collection ##Count
- UniqueEntity
- Language
- ##Locale
- Country
- File Constraints ¶
File
Bic
- CardScheme
- Currency
- ##Luhn
- ##Iban
- Isbn
- Issn Other constraints
- ¶
- ##Expression
- All
- UserPassword
- ##Valid
- You can also create your own custom constraints. How to create custom validation constraints This article covers this topic.
Configuration of constraints ¶
Some constraints, like NotBlank are relatively simple, while others, like Choice constraints, have many Available configuration options. Assume that the
Author
class has another attribute calledgender
, which can be set to "male", "female" or "other":PHP:// src/AppBundle/Entity/Author.php // ...use Symfony\Component\Validator\Mapping\ClassMetadata;use Symfony\Component\Validator\Constraints as Assert; class Author{ public $gender; // ... public static function loadValidatorMetadata(ClassMetadata $metadata) { // ... $metadata->addPropertyConstraint('gender', new Assert\Choice(array( 'choices' => array('male', 'female', 'other'), 'message' => 'Choose a valid gender.', ))); }}
XML:<!-- 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="AppBundle\Entity\Author"> <property name="gender"> <constraint name="Choice"> <option name="choices"> <value>male</value> <value>female</value> <value>other</value> </option> <option name="message">Choose a valid gender.</option> </constraint> </property> <!-- ... --> </class></constraint-mapping>
YAML:# src/AppBundle/Resources/config/validation.ymlAppBundle\Entity\Author: properties: gender: - Choice: { choices: [male, female, other], message: Choose a valid gender. } # ...
Annotations:// src/AppBundle/Entity/Author.php // ...use Symfony\Component\Validator\Constraints as Assert; class Author{ /** * @Assert\Choice( * choices = { "male", "female", "other" }, * message = "Choose a valid gender." * ) */ public $gender; // ...}
Constraint options can always be passed through an array. Some constraints also allow you to pass a value for the "default" option in place of this array. In
Choice
constraints,choices
options can be specified in this way.PHP:// src/AppBundle/Entity/Author.php // ...use Symfony\Component\Validator\Mapping\ClassMetadata;use Symfony\Component\Validator\Constraints as Assert; class Author{ protected $gender; public static function loadValidatorMetadata(ClassMetadata $metadata) { // ... $metadata->addPropertyConstraint( 'gender', new Assert\Choice(array('male', 'female', 'other')) ); }}
XML:<!-- 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="AppBundle\Entity\Author"> <property name="gender"> <constraint name="Choice"> <value>male</value> <value>female</value> <value>other</value> </constraint> </property> <!-- ... --> </class></constraint-mapping>
YAML:# src/AppBundle/Resources/config/validation.ymlAppBundle\Entity\Author: properties: gender: - Choice: [male, female, other] # ...
Annotations:// src/AppBundle/Entity/Author.php // ...use Symfony\Component\Validator\Constraints as Assert; class Author{ /** * @Assert\Choice({"male", "female", "other"}) */ protected $gender; // ...}
This is purely to make the most common configuration options easier and faster to use.
If you are not sure how to specify an option, either check the API documentation, or just to be on the safe side, pass it in through an options array (i.e. the first method above).
Goals of constraints ¶
Constraints can be applied to class properties (such as
name
) or to a public getter method (such asgetFullName
) or even the entire class. Attribute constraints are the most commonly used and simplest, while Getter constraints allow you to specify more complex validation rules. Finally, if the use case for class constraints is that you want to verify the class as a whole.Attribute constraints ¶
The verification of class attributes is one of the most basic verification techniques. Symfony allows you to verify private, protected or public properties. The following code shows how to configure the
$firstName
property of theAuthor
object so that it has at least 3 characters:PHP:// src/AppBundle/Entity/Author.php // ...use Symfony\Component\Validator\Mapping\ClassMetadata;use Symfony\Component\Validator\Constraints as Assert; class Author{ private $firstName; public static function loadValidatorMetadata(ClassMetadata $metadata) { $metadata->addPropertyConstraint('firstName', new Assert\NotBlank()); $metadata->addPropertyConstraint( 'firstName', new Assert\Length(array("min" => 3)) ); }}
XML:<!-- 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="AppBundle\Entity\Author"> <property name="firstName"> <constraint name="NotBlank" /> <constraint name="Length"> <option name="min">3</option> </constraint> </property> </class></constraint-mapping>
YAML:# src/AppBundle/Resources/config/validation.ymlAppBundle\Entity\Author: properties: firstName: - NotBlank: ~ - Length: min: 3
Annotations:// src/AppBundle/Entity/Author.php // ...use Symfony\Component\Validator\Constraints as Assert; class Author{ /** * @Assert\NotBlank() * @Assert\Length(min=3) */ private $firstName;}
Getters Constraints ¶
Constraints can also be applied to the return value of a method. Symfony allows you to add a constraint to any public method that begins with "get", "is" or "has". This type of method is called "getters".
The benefit of this technique is that it allows you to dynamically validate your objects. For example, suppose you want to ensure that the password field does not match the user's firstname (for security reasons). You can do this by creating a
isPasswordLegal
method and then asserting that the method must returntrue
:PHP:// src/AppBundle/Entity/Author.php // ...use Symfony\Component\Validator\Mapping\ClassMetadata;use Symfony\Component\Validator\Constraints as Assert; class Author{ public static function loadValidatorMetadata(ClassMetadata $metadata) { $metadata->addGetterConstraint('passwordLegal', new Assert\IsTrue(array( 'message' => 'The password cannot match your first name', ))); }}
XML:<!-- 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="AppBundle\Entity\Author"> <getter property="passwordLegal"> <constraint name="IsTrue"> <option name="message">The password cannot match your first name</option> </constraint> </getter> </class></constraint-mapping>
YAML:# src/AppBundle/Resources/config/validation.ymlAppBundle\Entity\Author: getters: passwordLegal: - 'IsTrue': { message: 'The password cannot match your first name' }
Annotations:// src/AppBundle/Entity/Author.php // ...use Symfony\Component\Validator\Constraints as Assert; class Author{ /** * @Assert\IsTrue(message = "The password cannot match your first name") */ public function isPasswordLegal() { // ... return true or false }}
Now, create a
isPasswordLegal()
Method, containing the logic you need:public function isPasswordLegal(){ return $this->firstName !== $this->password;}
Those with a sharp eye may notice that in the constraint configuration format of YAML, XML and PHP , the getter prefix ("get", "is" or "has") is ignored when mapping. This allows you to move a constraint to a subsequent property of the same name (or vice versa) without changing the validation logic.
Class constraints ¶
There are some constraints that can be applied to the entire class being verified. For example, a constraint of type Callback is a general constraint that can be applied to the class itself. When a class is validated, the methods specified by the constraints will be executed directly to provide more custom validation.
Summary ¶
Symfony's
validator
(validation) is a powerful tool that can be used to ensure that the data of any object is legal. sex. Its power comes from constraints, which you can apply to object properties and getter methods. Although, in most cases, the validation framework is applied indirectly when using forms, remember, it can be used anywhere to validate any object.
##1 2 | AppBundle\Author.name: This value should not be blank |