跳到內容

驗證

編輯此頁面

驗證在網路應用程式中是非常常見的工作。表單中輸入的資料需要驗證。資料在寫入資料庫或傳遞到網路服務之前也需要驗證。

Symfony 提供了一個 Validator 元件來為您處理這個問題。此元件基於 JSR303 Bean Validation 規範

安裝

在使用 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" 方法來取得任何屬性的值,因此它們可以是 public、private 或 protected(請參閱驗證)。

使用驗證器服務

接下來,要實際驗證 Author 物件,請使用驗證器服務(實作 ValidatorInterface)上的 validate() 方法。驗證器的工作是讀取類別的約束(即規則),並驗證物件上的資料是否滿足這些約束。如果驗證失敗,則會傳回非空的錯誤列表(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() 方法取得導致此違規的約束。

驗證 Callable

Validation 也允許您建立一個閉包,以針對一組約束驗證值(例如,在驗證 Console 命令答案驗證 OptionsResolver 值時很有用)

createCallable()
當約束不符時,這會傳回一個拋出 ValidationFailedException 的閉包。
createIsValidCallable()
當約束不符時,這會傳回一個傳回 false 的閉包。

約束

validator 的設計目的是針對約束(即規則)驗證物件。為了驗證物件,只需將一個或多個約束對應到其類別,然後將其傳遞給 validator 服務。

在幕後,約束只是一個 PHP 物件,它會做出斷言陳述。在現實生活中,約束可能是:「蛋糕不得燒焦」。在 Symfony 中,約束是相似的:它們是對條件為真的斷言。給定一個值,約束會告訴您該值是否符合約束的規則。

支援的約束

Symfony 打包了許多最常用的約束

基本約束

這些是基本約束:使用它們來斷言關於屬性值或物件上方法傳回值的非常基本的事項。

約束設定

有些約束(例如 NotBlank)很簡單,而另一些約束(例如 Choice 約束)則有幾個可用的設定選項。假設 Author 類別還有另一個名為 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 string $genre;

    // ...
}

約束的選項始終可以作為陣列傳遞。但是,某些約束也允許您傳遞一個「預設」選項的值來代替陣列。在 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 允許您驗證 private、protected 或 public 屬性。以下列表顯示如何設定 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" 開頭的 private、protected 或 public 方法。在本指南中,這些類型的方法稱為「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 方法。雖然您在使用表單時最常間接使用驗證框架,但請記住,它可以隨時隨地用於驗證任何物件。

這個作品,包含程式碼範例,以 創用CC BY-SA 3.0 授權條款授權。
目錄
    版本