验证
验证是 Web 应用程序中非常常见的任务。表单中输入的数据需要验证。数据在写入数据库或传递给 Web 服务之前也需要验证。
Symfony 提供了一个 验证器 组件来为您处理此问题。此组件基于 JSR303 Bean 验证规范。
安装
在使用 Symfony Flex 的应用程序中,运行此命令以在开始使用验证器之前安装它
1
$ composer require symfony/validator
注意
如果您的应用程序没有使用 Symfony Flex,您可能需要进行一些手动配置才能启用验证。请查看 验证配置参考。
验证基础知识
理解验证的最佳方法是实际操作。首先,假设您创建了一个普通的 PHP 对象,需要在应用程序中的某个地方使用它
1 2 3 4 5 6 7
// src/Entity/Author.php
namespace App\Entity;
class Author
{
private string $name;
}
到目前为止,这是一个普通的类,在您的应用程序内部服务于某种目的。验证的目标是告诉您对象的数据是否有效。为了实现这一点,您需要配置对象必须遵循的一系列规则(称为约束)才能有效。这些规则通常使用 PHP 代码或属性定义,但也可以在 config/validator/
目录中使用 .yaml
或 .xml
文件定义
例如,要指示 $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 string $name;
}
仅添加此配置本身并不能保证该值不会为空白;如果您愿意,仍然可以将其设置为空白值。为了真正保证该值符合约束,必须将该对象传递给验证器服务进行检查。
提示
Symfony 的验证器使用 PHP 反射以及“getter”方法来获取任何属性的值,因此它们可以是公共的、私有的或受保护的(请参阅 验证)。
使用验证器服务
接下来,要实际验证 Author
对象,请使用 validator
服务(实现 ValidatorInterface)上的 validate()
方法。validator
的工作是读取类的约束(即规则)并验证对象上的数据是否满足这些约束。如果验证失败,则返回非空错误列表(ConstraintViolationList 类)。以下是控制器内部的简单示例
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): Response
{
$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!');
}
如果 $name
属性为空,您将看到以下错误消息
1 2
Object(App\Entity\Author).name:
This value should not be blank.
如果您在 name
属性中插入一个值,则会出现令人愉快的成功消息。
提示
在大多数情况下,您不会直接与 validator
服务交互,也不需要担心打印错误。在大多数情况下,您将在处理提交的表单数据时间接使用验证。有关更多信息,请参阅 如何验证 Symfony 表单。
您也可以将错误集合传递到模板中
1 2 3 4 5
if (count($errors) > 0) {
return $this->render('author/validation.html.twig', [
'errors' => $errors,
]);
}
在模板内部,您可以完全按照需要输出错误列表
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>
注意
每个验证错误(称为“约束冲突”)都由 ConstraintViolation 对象表示。此对象允许您(除其他外)通过 ConstraintViolation::getConstraint()
方法获取导致此冲突的约束。
验证回调
Validation
还允许您创建一个闭包,以针对一组约束验证值(例如,在验证控制台命令答案或在验证 OptionsResolver 值时非常有用)
- createCallable()
- 当约束不匹配时,这将返回一个抛出
ValidationFailedException
的闭包。 - createIsValidCallable()
- 当约束不匹配时,这将返回一个返回
false
的闭包。
约束
validator
旨在根据约束(即规则)验证对象。为了验证对象,只需将其一个或多个约束映射到其类,然后将其传递给 validator
服务。
在幕后,约束只是一个 PHP 对象,它做出一个断言语句。在现实生活中,约束可能是:“蛋糕不能烤焦”
。在 Symfony 中,约束是相似的:它们是条件为真的断言。给定一个值,约束将告诉您该值是否符合约束的规则。
支持的约束
Symfony 打包了许多最常用的约束
其他约束
您还可以创建自己的自定义约束。本主题在 如何创建自定义验证约束 文章中介绍。
约束配置
有些约束(如 NotBlank)很简单,而另一些约束(如 Choice 约束)则有多个配置选项可用。假设 Author
类还有另一个名为 genre
的属性,用于定义主要与作者相关的文学流派,可以设置为“fiction”或“non-fiction”
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 string $genre;
// ...
}
约束的选项始终可以作为数组传入。但是,某些约束还允许您传递一个“default”选项的值来代替数组。在 Choice
约束的情况下,可以以这种方式指定 choices
选项。
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 string $genre;
// ...
}
这纯粹是为了使约束最常用选项的配置更短更快。
如果您不确定如何指定选项,请检查命名空间 Symfony\Component\Validator\Constraints
中是否有约束,或者始终传入选项数组(上面显示的第一种方法)以确保安全。
表单类中的约束
可以通过表单字段的 constraints
选项在构建表单时定义约束
1 2 3 4 5 6 7 8 9
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('myField', TextType::class, [
'required' => true,
'constraints' => [new Length(['min' => 3])],
])
;
}
约束目标
约束可以应用于类属性(例如 name
)、getter 方法(例如 getFullName()
)或整个类。属性约束是最常见且易于使用的。Getter 约束允许您指定更复杂的验证规则。最后,类约束旨在用于您想要验证整个类的场景。
属性
验证类属性是最基本的验证技术。Symfony 允许您验证私有、受保护或公共属性。下一个清单显示了如何配置 Author
类的 $firstName
属性至少有 3 个字符。
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 string $firstName;
}
警告
如果类型属性未初始化,验证器将使用值 null
。如果属性在初始化时包含值,这可能会导致意外行为。为了避免这种情况,请确保在验证所有属性之前对其进行初始化。
Getter
约束也可以应用于方法的返回值。Symfony 允许您向任何名称以“get”、“is”或“has”开头的私有、受保护或公共方法添加约束。在本指南中,这些类型的方法称为“getter”。
此技术的优点是它允许您动态验证对象。例如,假设您要确保密码字段与用户的名字不匹配(出于安全原因)。您可以通过创建一个 isPasswordSafe()
方法来做到这一点,然后断言此方法必须返回 true
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(): bool
{
// ... return true or false
}
}
现在,创建 isPasswordSafe()
方法并包含您需要的逻辑
1 2 3 4
public function isPasswordSafe(): bool
{
return $this->firstName !== $this->password;
}
注意
细心的您会注意到,在 YAML、XML 和 PHP 格式的映射中,getter 的前缀(“get”、“is”或“has”)被省略了。这允许您稍后将约束移动到具有相同名称的属性(或反之亦然),而无需更改验证逻辑。
验证带有继承的对象
当您验证扩展另一个类的对象时,验证器也会自动验证在父类中定义的约束。
即使子属性覆盖了父属性中定义的约束,父属性中定义的约束仍将应用于子属性。Symfony 将始终合并每个属性的父约束。
您无法更改此行为,但可以通过在不同的 验证组中定义父约束和子约束,然后在验证每个对象时选择适当的组来克服它。
调试约束
使用 debug:validator
命令列出给定类的验证约束
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 |
| | | | ] |
+---------------+--------------------------------------------------+---------+------------------------------------------------------------+
您还可以验证存储在给定目录中的所有类
1
$ php bin/console debug:validator src/Entity
最终想法
Symfony validator
是一个强大的工具,可以用来保证任何对象的数据都是“有效的”。验证背后的力量在于“约束”,约束是您可以应用于对象的属性或 getter 方法的规则。虽然您最常在使用表单时间接使用验证框架,但请记住,它可以用于任何地方来验证任何对象。