跳到内容

验证

编辑此页

验证是 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”)被省略了。这允许您稍后将约束移动到具有相同名称的属性(或反之亦然),而无需更改验证逻辑。

某些约束适用于正在验证的整个类。例如,Callback 约束是应用于类本身的通用约束。当验证该类时,只需执行该约束指定的方法,以便每个方法都可以提供更自定义的验证。

验证带有继承的对象

当您验证扩展另一个类的对象时,验证器也会自动验证在父类中定义的约束。

即使子属性覆盖了父属性中定义的约束,父属性中定义的约束仍将应用于子属性。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 方法的规则。虽然您最常在使用表单时间接使用验证框架,但请记住,它可以用于任何地方来验证任何对象。

本作品,包括代码示例,根据 Creative Commons BY-SA 3.0 许可获得许可。
目录
    版本