10、基礎組件 —— 表單驗證

簡介

   Laravel 提供了多種方法來驗證請求輸入數據。默認狀況下,Laravel 的控制器基類使用 ValidatesRequests trait,該 trait 提供了便捷方法經過各類功能強大的驗證規則來驗證輸入的 HTTP 請求。php

快速入門

   要掌握 Laravel 強大的驗證特性,讓咱們先看一個完整的驗證表單並返回錯誤信息給用戶的示例。laravel

   定義路由

    首先,咱們假定在 routes/web.php 文件中包含以下路由:git

// 顯示建立博客文章表單...
Route::get('post/create', 'PostController@create');
// 存儲新的博客文章...
Route::post('post', 'PostController@store');

     顯然,GET 路由爲用戶顯示了一個建立新的博客文章的表單,POST 路由將新的博客文章存儲到數據庫。web

   建立控制器

     接下來,讓咱們看一個處理這些路由的簡單控制器示例。咱們先將 store 方法留空:正則表達式

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Http\Controllers\Controller;

class PostController extends Controller
{
    /**
     * 顯示建立新的博客文章的表單
     *
     * @return Response
     */
    public function create()
    {
        return view('post.create');
    }

    /**
     * 存儲新的博客文章
     *
     * @param  Request  $request
     * @return Response
     */
    public function store(Request $request)
    {
        // 驗證並存儲博客文章...
    }
}

   編寫驗證邏輯

     如今咱們準備用驗證新博客文章輸入的邏輯填充 store 方法。咱們使用 Illuminate\Http\Request 對象提供的 validate 方法來實現這一功能,若是驗證規則經過,代碼將會繼續往下執行;反之,若是驗證失敗,將會拋出一個異常,相應的錯誤響應也會自動發送給用戶。在這個傳統的 HTTP 請求案例中,將會生成一個重定向響應,若是是 AJAX 請求則會返回一個 JSON 響應。數據庫

     要更好地理解 validate 方法,讓咱們回顧下 store 方法:apache

/**
 * 存儲博客文章
 *
 * @param  Request  $request
 * @return Response
 */
public function store(Request $request){
    $validatedData = $request->validate([
        'title' => 'required|unique:posts|max:255',
        'body' => 'required',
    ]);

    // 驗證經過,存儲到數據庫...
}

     正如你所看到的,咱們只是傳入指望的驗證規則到 validate 方法。再強調一次,若是驗證失敗,相應的響應會自動生成。若是驗證經過,控制器將會繼續往下執行。json

注:實際執行代碼以前,須要在數據庫中建立 posts 數據表,由於這裏用到了 unique:posts 這個驗證規則,該規則會去數據庫中查詢傳入標題是否已存在以保證惟一性。數組

     首次驗證失敗後停止後續規則驗證安全

     有時候你可能想要在首次驗證失敗後中止檢查該屬性的其它驗證規則,要實現這個功能,能夠在規則屬性中分配 bail做爲首規則:

$request->validate([
    'title' => 'bail|required|unique:posts|max:255',
    'body' => 'required',
]);

     在這個例子中,若是 title 屬性上的 required 規則驗證失敗,則不會檢查 unique 規則,規則會按照分配順序依次進行驗證。

     嵌套屬性注意事項

     若是 HTTP 請求中包含「嵌套」參數,可使用「.」在驗證規則中指定它們:

$request->validate([
    'title' => 'required|unique:posts|max:255',
    'author.name' => 'required',
    'author.desc' => 'required',
]);

     這樣的驗證規則適用於驗證以下標籤請求:

<form method="POST" action="{{route('posts.store')}}">
    {{csrf_field()}}
    <input type="text" name="title"/>
    <input type="text" name="author[name]"/>
    <input type="text" name="author[desc]"/>
    <textarea cols="20" rows="5" name="body"></textarea>
    <button type="submit">submit</button>
</form>

   顯示驗證錯誤信息

     那麼,若是請求輸入參數沒有經過給定驗證規則怎麼辦?正如前面所提到的,Laravel 將會自動將用戶重定向回上一個位置。此外,全部驗證錯誤信息會自動存放到一次性Session,咱們能夠看下這個 Session 數據的數據結構:

     

     注意:咱們並無在 GET 路由中顯式綁定錯誤信息到視圖。這是由於 Laravel 老是從 Session 數據中檢查錯誤信息,並且若是有的話會自動將其綁定到視圖。因此,值得注意的是每次請求的全部視圖中老是存在一個$errors 變量,從而容許你在視圖中方便而又安全地使用。$errors 變量是一個Illuminate\Support\MessageBag 實例。想要了解更多關於該對象的信息,查看下面的處理錯誤信息。

注:$errors 變量會經過 web 中間件組中的 Illuminate\View\Middleware\ShareErrorsFromSession中間件綁定到視圖,若是使用了該中間件,那麼 $errors 變量在視圖中老是有效,從而方便你隨時使用。

     因此,在咱們的例子中,驗證失敗的話用戶將會被重定向到控制器的 create 方法,從而容許咱們在視圖中顯示錯誤信息:

<!-- /resources/views/post/create.blade.php -->

<h1>Create Post</h1>

@if ($errors->any())
    <div class="alert alert-danger">
        <ul>
            @foreach ($errors->all() as $error)
                <li>{{ $error }}</li>
            @endforeach
        </ul>
    </div>
@endif

<!-- Create Post Form -->

     若是驗證失敗的話,跳轉回表單頁面的同時會顯示錯誤信息:

     

   可選字段注意事項

     默認狀況下,Laravel自帶了 TrimStrings 和 ConvertEmptyStringsToNull 中間件,這兩個中間件位於 App\Http\Kernel 類的全局中間件堆棧中,由於這個緣由,你須要常常將「可選」的請求字段標記爲 nullable —— 若是你不想讓驗證器將 null 斷定爲無效的話。例如:

$this->validate($request, [
    'title' => 'required|unique:posts|max:255',
    'body' => 'required',
    'publish_at' => 'nullable|date',
]);

     在這個例子中,咱們指定 publish_at 字段能夠爲 null 或者有效的日期格式。若是 nullable 沒有被添加到驗證規則,驗證器會將 null 斷定爲無效日期。

   AJAX 請求 & 驗證

     在上面的例子中,咱們使用了傳統的表單來發送數據到應用。不過,現實場景中,不少應用使用 AJAX 請求。在 AJAX 請求中使用 validate 方法時,Laravel 不會生成重定向響應。取而代之的,Laravel 生成一個包含驗證錯誤信息的 JSON 響應。該 JSON 響應會帶上一個 HTTP 狀態碼 422

表單請求驗證

   建立表單請求

     對於更復雜的驗證場景,你可能想要建立一個「表單請求」。表單請求是包含驗證邏輯的自定義請求類,要建立表單驗證類,可使用 Artisan 命令 make:request

php artisan make:request StoreBlogPost

     生成的類位於 app/Http/Requests 目錄下,若是該目錄不存在,運行 make:request 命令時會替咱們生成。接下來咱們添加少量驗證規則到該類的 rules 方法:

/**
 * 獲取應用到請求的驗證規則
 *
 * @return array
 */
public function rules(){
    return [
        'title' => 'required|unique:posts|max:255',
        'body' => 'required',
    ];
}

注:你能夠在 rules 方法簽名簽名中注入任何依賴,它們會經過服務容器自動解析。

     那麼,驗證規則如何生效呢?你所要作的就是在控制器方法中類型提示該請求類。這樣表單輸入請求會在控制器方法被調用以前被驗證,這就是說你不須要將控制器方法和驗證邏輯雜糅在一塊兒:

/**
 * 存儲輸入的博客文章
 *
 * @param  StoreBlogPostRequest  $request
 * @return Response
 */
public function store(StoreBlogPost $request){
    // The incoming request is valid...

    // Retrieve the validated input data...
    $validated = $request->validated();
}

     若是驗證失敗,重定向響應會被生成並將用戶退回上一個位置,錯誤信息也會被存儲到一次性 Session 以便在視圖中顯示。若是是 AJAX 請求,帶 422 狀態碼的 HTTP 響應將會返回給用戶,該響應數據中還包含了 JSON 格式的驗證錯誤信息。

   添加驗證後鉤子到表單請求

     若是你想要添加「驗證後」鉤子到表單請求,可使用 withValidator 方法。該方法接收完整的構造驗證器,從而容許你在驗證規則執行前調用任何驗證器方法:

/**
 * 配置驗證器實例.
 *
 * @param  \Illuminate\Validation\Validator  $validator
 * @return void
 */
public function withValidator($validator)
{
    $validator->after(function ($validator) {
        if ($this->somethingElseIsInvalid()) {
            $validator->errors()->add('field', 'Something is wrong with this field!');
        }
    });
}

   受權表單請求

     表單請求類還包含了一個 authorize 方法,你能夠經過該方法檢查認證用戶是否有權限更新指定資源。例如,若是用戶嘗試更新一條博客評論,那麼他必須是該評論的全部者。舉個例子:

/**
 * 斷定用戶是否有權限發起請求.
 *
 * @return bool
 * @translator laravelacademy.org
 */
public function authorize()
{
    $comment = Comment::find($this->route('comment'));
    return $comment && $this->user()->can('update', $comment);
}

     因爲全部請求都繼承自 Laravel 請求基類,咱們可使用 user 方法獲取當前認證用戶,還要注意上面這個例子中對 route 方法的調用。該方法賦予用戶訪問被調用路由 URI 參數的權限,好比下面這個例子中的 {comment} 參數:

Route::post('comment/{comment}');

     若是 authorize 方法返回 false,一個包含 403 狀態碼的 HTTP 響應會自動返回並且控制器方法將不會被執行。

     若是你計劃在應用的其餘部分調用受權邏輯,只需在 authorize 方法中簡單返回 true 便可:

/**
 * 判斷請求用戶是否通過受權
 *
 * @return bool
 */
public function authorize(){
    return true;
}

注:你能夠在 authorize() 方法簽名中注入任何依賴,它們將會經過服務容器自動解析。

   自定義錯誤消息

     你能夠經過重寫 messages 方法自定義表單請求使用的錯誤消息,該方法應該返回屬性/規則對數組及其對應錯誤消息:

/**
 * 獲取被定義驗證規則的錯誤消息
 *
 * @return array
 * @translator laravelacademy.org
 */
public function messages(){
    return [
        'title.required' => 'A title is required',
        'body.required'  => 'A message is required',
    ];
}

   自定義驗證屬性

     若是你想要將驗證消息中的 :attribute 部分替換爲自定義的屬性名,能夠經過重寫 attributes 方法來指定自定義的名稱。該方法會返回屬性名及對應自定義名稱鍵值對數組:

/**
 * Get custom attributes for validator errors.
 *
 * @return array
 */
public function attributes()
{
    return [
        'email' => 'email address',
    ];
}

   手動建立驗證器

     若是你不想使用請求實例上的 validate 方法,可使用 Validator 門面手動建立一個驗證器實例,該門面提供的 make 方法可用於生成一個新的驗證器實例:

<?php

namespace App\Http\Controllers;

use Validator;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;

class PostController extends Controller{
    /**
     * 存儲新的博客文章
     *
     * @param  Request  $request
     * @return Response
     */
    public function store(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'title' => 'required|unique:posts|max:255',
            'body' => 'required',
        ]);

        if ($validator->fails()) {
            return redirect('post/create')
                        ->withErrors($validator)
                        ->withInput();
        }

        // 存儲博客文章...
    }
}

     傳遞給 make 方法的第一個參數是須要驗證的數據,第二個參數是要應用到數據上的驗證規則。

     檢查請求沒有經過驗證後,可使用 withErrors 方法將錯誤數據存放到一次性 Session,使用該方法時,$errors變量重定向後自動在視圖間共享,從而容許你輕鬆將其顯示給用戶,withErrors 方法接收一個驗證器、或者一個 MessageBag ,又或者一個 PHP 數組。

   自動重定向

     若是你想要手動建立一個驗證器實例,但仍然使用請求實例的 validate 方法提供的自動重定向,能夠調用已存在驗證器實例上的 validate 方法,若是驗證失敗,用戶將會被自動重定向,或者,若是是 AJAX 請求的話,返回 JSON 響應:

Validator::make($request->all(), [
    'title' => 'required|unique:posts|max:255',
    'body' => 'required',
])->validate();

   命名錯誤包

     若是你在單個頁面上有多個表單,可能須要命名錯誤的 MessageBag,從而容許你爲指定表單獲取錯誤信息。只須要傳遞名稱做爲第二個參數給 withErrors 便可:

return redirect('register')
       ->withErrors($validator, 'login');

     而後你就能夠從 $errors 變量中訪問命名的 MessageBag 實例:

{{ $errors->login->first('email') }}

   驗證鉤子以後

     驗證器容許你在驗證完成後添加回調,這種機制容許你輕鬆執行更多驗證,甚至添加更多錯誤信息到消息集合。使用驗證器實例上的 after 方法便可:

$validator = Validator::make(...);

$validator->after(function($validator) {
    if ($this->somethingElseIsInvalid()) {
        $validator->errors()->add('field', 'Something is wrong with this field!');
    }
});

if ($validator->fails()) {
    //
}

處理錯誤信息

   調用 Validator 實例上的 errors 方法以後,將會獲取一個 Illuminate\Support\MessageBag 實例,該實例中包含了多種處理錯誤信息的便利方法。在全部視圖中默認有效的 $errors 變量也是一個 MessageBag 實例。

   獲取某字段的第一條錯誤信息

     要獲取指定字段的第一條錯誤信息,可使用 first 方法:

$errors = $validator->errors();
echo $errors->first('email');

   獲取指定字段的全部錯誤信息

     若是你想要簡單獲取指定字段的全部錯誤信息數組,使用 get 方法:

foreach ($errors->get('email') as $message) {
    //
}

     若是是一個數組表單字段,可使用 * 獲取全部數組元素錯誤信息:

foreach ($errors->get('attachments.*') as $message) {
    //
}

   獲取全部字段的全部錯誤信息

     要獲取全部字段的全部錯誤信息,可使用 all 方法:

foreach ($errors->all() as $message) {
    //
}

   判斷消息中是否存在某字段的錯誤信息

    has 方法可用於判斷錯誤信息中是否包含給定字段:

if ($errors->has(’email’)) {
    //
}

   自定義錯誤信息

     若是須要的話,你可使用自定義錯誤信息替代默認的,有多種方法來指定自定義信息。首先,你能夠傳遞自定義信息做爲第三個參數給 Validator::make 方法:

$messages = [
    'required' => 'The :attribute field is required.',
];

$validator = Validator::make($input, $rules, $messages);

     在本例中,:attribute 佔位符將會被驗證時實際的字段名替換,你還能夠在驗證消息中使用其餘佔位符,例如:

$messages = [
    'same'    => 'The :attribute and :other must match.',
    'size'    => 'The :attribute must be exactly :size.',
    'between' => 'The :attribute must be between :min - :max.',
    'in'      => 'The :attribute must be one of the following types: :values',
];

   爲給定屬性指定自定義信息

     有時候你可能只想爲特定字段指定自定義錯誤信息,能夠經過「.」來實現,首先指定屬性名,而後是規則:

$messages = [
    'email.required' => '郵箱地址不能爲空!',
];

   在語言文件中指定自定義消息

     在不少案例中,你可能想要在語言文件中指定自定義消息而不是將它們直接傳遞給 Validator。要實現這個,添加消息到 resources/lang/xx/validation.php 語言文件的 custom 數組:

'custom' => [
    'email' => [
        'required' => '郵箱地址不能爲空!',
    ],
],

   在語言文件中指定自定義屬性

     若是你想要將驗證消息的 :attribute 部分替換成自定義的屬性名稱,能夠在語言文件 resources/lang/xx/validation.php 的 attributes 數組中指定自定義名稱:

'attributes' => [
    'email' => '郵箱地址',
],

   在語言文件中指定自定義值

     有時候你可能須要將驗證消息中的 :value 部分替換成自定義的表示值,例如,下面這個驗證規則指定若是 payment_type 值是 cc 的話信用卡號不能爲空:

$request->validate([
    'credit_card_number' => 'required_if:payment_type,cc'
]);

     若是這個驗證規則驗證失敗了,將會生成以下錯誤消息:

The credit card number field is required when payment type is cc.

     若是你想要替換支付類型值 cc,能夠在 validation 語言文件中定義一個 values 數組來指定自定義的表示值:

'values' => [
    'payment_type' => [
        'cc' => 'credit card'
    ],
],

     這樣一來,若是驗證規則驗證失敗,對應的錯誤信息以下:

The credit card number field is required when payment type is credit card.

驗證規則大全

   下面是有效規則及其函數列表:

accepted:驗證字段的值必須是 yes、on、1 或 true,這在「贊成服務協議」時頗有用。

active_url:驗證字段必須是基於 PHP 函數 dns_get_record 的,有 A 或 AAAA 記錄的值。

after:date:驗證字段必須是給定日期以後的一個值,日期將會經過 PHP 函數 strtotime 傳遞:
'start_date' => 'required|date|after:tomorrow'

能夠指定另一個與日期進行比較的字段,而不是傳遞一個日期字符串給 strtotime 執行:
strtotime
'finish_date' => 'required|date|after:start_date'

after_or_equal:date:驗證字段必須是大於等於給定日期的值,更多信息,請參考 after:date 規則。

alpha:驗證字段必須是字母。

alpha_dash:驗證字段能夠包含字母和數字,以及破折號和下劃線。

alpha_num:驗證字段必須是字母或數字。

array:驗證字段必須是 PHP 數組。

bail:第一個驗證規則驗證失敗則中止運行其它驗證規則。

before:date:和 after:date 相對,驗證字段必須是指定日期以前的一個數值,日期將會傳遞給 PHP strtotime 函數。

before_or_equal:date:驗證字段必須小於等於給定日期。日期將會傳遞給 PHP 的 strtotime 函數。

between:min,max:驗證字段大小在給定的最小值和最大值之間,字符串、數字、數組和文件均可以像使用 size 規則同樣使用該規則:

'name' => 'required|between:1,20'

boolean:驗證字段必須能夠被轉化爲布爾值,接收 truefalse10"1" 和 "0" 等輸入。

confirmed:驗證字段必須有一個匹配字段 foo_confirmation,例如,若是驗證字段是 password,必須輸入一個與之匹配的 password_confirmation 字段。

date:驗證字段必須是一個基於 PHP strtotime 函數的有效日期

date_equals:date:驗證字段必須等於給定日期,日期會被傳遞到 PHP strtotime 函數。

date_format:format:驗證字段必須匹配指定格式,可使用 PHP 函數date 或 date_format 驗證該字段。

different:field:驗證字段必須是一個和指定字段不一樣的值。

digits:value:驗證字段必須是數字且長度爲 value 指定的值。

digits_between:min,max:驗證字段數值長度必須介於最小值和最大值之間。

dimensions:驗證的圖片尺寸必須知足該規定參數指定的約束條件:有效的約束條件包括:min_widthmax_widthmin_heightmax_heightwidthheightratio

'avatar' => 'dimensions:min_width=100,min_height=200'
ratio 約束寬度/高度的比率,這能夠經過表達式 3/2 或浮點數 1.5 來表示:
3/21.5
'avatar' => 'dimensions:ratio=3/2'

因爲該規則要求多個參數,可使用 Rule::dimensions 方法來構造該規則:
Rule::dimensions
use Illuminate\Validation\Rule;

         Validator::make($data, [
            'avatar' => [
                         'required',
                         Rule::dimensions()->maxWidth(1000)->maxHeight(500)->ratio(3 / 2),
            ],
         ]);

distinct:處理數組時,驗證字段不能包含重複值

'foo.*.id' => 'distinct'

email:驗證字段必須是格式正確的電子郵件地址。

exists:table,column:驗證字段必須存在於指定數據表。

                    基本使用:

'state' => 'exists:states' //若是 column 選項沒有指定,將會使用字段名。

指定自定義列名:
column
'state' => 'exists:states,abbreviation'

有時,你可能須要爲 exists 查詢指定要使用的數據庫鏈接,這能夠在表名前經過.前置數據庫鏈接來實現:
exists
'email' => 'exists:connection.staff,email'

若是你想要自定義驗證規則執行的查詢,可使用 Rule 類來定義規則。在這個例子中,咱們還以數組形式指定了驗證規則,而不是使用 | 字符來限定它們:
Rule|
use Illuminate\Validation\Rule;

                  Validator::make($data, [
                   'email' => [
                              'required',
                              Rule::exists('staff')->where(function ($query) {
                                  $query->where('account_id', 1);
                              }),
                   ],
                  ]);

file:驗證字段必須是上傳成功的文件。

filled:驗證字段若是存在則不能爲空。

gt:field:驗證字段必須大於給定 field 字段,這兩個字段類型必須一致,適用於字符串、數字、數組和文件,和 size 規則相似

gte:field:驗證字段必須大於等於給定 field 字段,這兩個字段類型必須一致,適用於字符串、數字、數組和文件,和 size 規則相似

image:驗證文件必須是圖片(jpeg、png、bmp、gif 或者 svg)

in:foo,bar…:驗證字段值必須在給定的列表中,因爲該規則常常須要咱們對數組進行 implode,咱們可使用 Rule::in 來構造這個規則:

use Illuminate\Validation\Rule;

           Validator::make($data, [
            'zones' => [
               'required',
               Rule::in(['first-zone', 'second-zone']),
            ],
           ]);

in_array:另外一個字段,驗證字段必須在另外一個字段值中存在。

integer:驗證字段必須是整型。

ip:驗證字段必須是IP地址。

ipv4:驗證字段必須是IPv4地址。

ipv6:驗證字段必須是IPv6地址。

json:驗證字段必須是有效的JSON字符串

lt:field:驗證字段必須小於給定 field 字段,這兩個字段類型必須一致,適用於字符串、數字、數組和文件,和 size 規則相似

lte:field:驗證字段必須小於等於給定 field 字段,這兩個字段類型必須一致,適用於字符串、數字、數組和文件,和 size 規則相似

max:value:驗證字段必須小於等於最大值,和字符串、數值、數組、文件字段的 size 規則使用方式同樣。

mimetypes:text/plain…:驗證文件必須匹配給定的 MIME 文件類型之一:

爲了判斷上傳文件的 MIME 類型,框架將會讀取文件內容來猜想 MIME 類型,這可能會和客戶端 MIME 類型不一樣。'video' => 'mimetypes:video/avi,video/mpeg,video/quicktime' //

 

mimes:foo,bar,…:驗證文件的 MIME 類型必須是該規則列出的擴展類型中的一個

                MIME 規則的基本使用:

'photo' => 'mimes:jpeg,bmp,png'

                儘管你只是指定了擴展名,該規則實際上驗證的是經過讀取文件內容獲取到的文件 MIME 類型。

                完整的 MIME 類型列表及其相應的擴展能夠在這裏找到:http://svn.apache.org/repos/asf/httpd/httpd/trunk/docs/conf/mime.types

min:value:與 max:value 相對,驗證字段必須大於等於最小值,對字符串、數值、數組、文件字段而言,和 size 規則使用方式一致。

not_in:foo,bar,…:驗證字段值不能在給定列表中,和 in 規則相似,咱們可使用 Rule::notIn 方法來構建規則:

use Illuminate\Validation\Rule;

                Validator::make($data, [
                 'toppings' => [
                   'required',
                   Rule::notIn(['sprinkles', 'cherries']),
                 ],
                ]);

not_regex:pattern:驗證字段不能匹配給定正則表達式

              注:使用 regex/not_regex 模式時,規則必須放在數組中,而不能使用管道分隔符,尤爲是正則表達式中包含管道符號時。

nullable:驗證字段能夠是 null,這在驗證一些能夠爲 null 的原始數據如整型或字符串時頗有用。

numeric:驗證字段必須是數值

present:驗證字段必須出如今輸入數據中但能夠爲空。

regex:pattern:驗證字段必須匹配給定正則表達式。

              該規則底層使用的是 PHP 的 preg_match 函數。所以,指定的模式須要遵循 preg_match 函數所要求的格式而且包含有效的分隔符。例如 'email' => 'regex:/^.+@.+$/i'

         注:使用 regex/not_regex 模式時,規則必須放在數組中,而不能使用管道分隔符,尤爲是正則表達式中包含管道符號時。

required:驗證字段值不能爲空,如下狀況字段值都爲空:

  • 值爲null
  • 值是空字符串
  • 值是空數組或者空的 Coutable 對象
  • 值是上傳文件但路徑爲空

required_if:anotherfield,value,…:驗證字段在 anotherfield 等於指定值 value 時必須存在且不能爲空。

                                  若是你想要爲 required_if 規則構造更復雜的條件,可使用 Rule::requiredIf 方法,該方法接收一個布爾值或閉包。

                                  當傳遞一個閉包時,會返回 true 或 false 以代表驗證字段是不是必須的:

use Illuminate\Validation\Rule;

                                  Validator::make($request->all(), [
                                      'role_id' => Rule::requiredIf($request->user()->is_admin),
                                  ]);

                                  Validator::make($request->all(), [
                                      'role_id' => Rule::requiredIf(function () use ($request) {
                                           return $request->user()->is_admin;
                                      }),
                                  ]);

required_unless:anotherfield,value,…:除非 anotherfield 字段等於 value,不然驗證字段不能空。

required_with:foo,bar,…:驗證字段只有在任一其它指定字段存在的狀況纔是必須的。

required_with_all:foo,bar,…:驗證字段只有在全部指定字段存在的狀況下才是必須的。

required_without:foo,bar,…:驗證字段只有當任一指定字段不存在的狀況下才是必須的。

required_without_all:foo,bar,…:驗證字段只有當全部指定字段不存在的狀況下才是必須的。

same:field:給定字段和驗證字段必須匹配。

size:value:驗證字段必須有和給定值 value 相匹配的尺寸/大小,對字符串而言,value 是相應的字符數目;對數值而言,value 是給定整型值;對數組而言,value 是數組長度;對文件而言,value 是相應的文件千字節數(KB)。

starts_with:foo,bar,...:驗證字段必須以某個給定值開頭。

string:驗證字段必須是字符串,若是容許字段爲空,須要分配 nullable 規則到該字段。

timezone:驗證字符必須是基於 PHP 函數 timezone_identifiers_list 的有效時區標識

unique:table,column,except,idColumn:驗證字段在給定數據表上必須是惟一的,若是不指定 column 選項,字段名將做爲默認 column

                                    1)指定自定義列名: 'email' => 'unique:users,email_address'

                                    2)自定義數據庫鏈接:有時候,你可能須要自定義驗證器生成的數據庫鏈接,正如上面所看到的,設置 unique:users 做爲驗證規則將會使用默認數據庫鏈接來查詢數據庫。要覆蓋默認鏈接,在數據表名後使用「.」指定鏈接:

'email' => 'unique:connection.users,email_address'

                                    3)強制一個忽略給定 ID 的惟一規則:有時候,你可能但願在惟一檢查時忽略給定 ID,例如,考慮一個包含用戶名、郵箱地址和位置的」更新屬性「界面,你將要驗證郵箱地址是惟一的,然而,若是用戶只改變用戶名字段而並無改變郵箱字段,你不想要由於用戶已經擁有該郵箱地址而拋出驗證錯誤,你只想要在用戶提供的郵箱已經被別人使用的狀況下才拋出驗證錯誤。

                                       要告訴驗證器忽略用戶 ID,可使用 Rule 類來定義這個規則,咱們還要以數組方式指定驗證規則,而不是使用 |來界定規則:

use Illuminate\Validation\Rule;

                                       Validator::make($data, [
                                           'email' => [
                                               'required',
                                                Rule::unique('users')->ignore($user->id),
                                            ],
                                        ]);

除了傳遞模型實例主鍵值到 ignore 方法以外,你還能夠傳遞整個模型實例。Laravel 會自動從模型實例中解析出主鍵值:
ignore
Rule::unique('users')->ignore($user)

若是你的數據表使用主鍵字段不是 id,能夠在調用 ignore 方法的時候指定字段名稱:
idignore
'email' => Rule::unique('users')->ignore($user->id, 'user_id')

默認狀況下,unique 規則會檢查與要驗證的屬性名匹配的列的惟一性。不過,你能夠指定不一樣的列名做爲 unique方法的第二個參數:
uniqueunique
Rule::unique('users', 'email_address')->ignore($user->id)

                                     4)添加額外的 where 子句:

                                           使用 where 方法自定義查詢的時候還能夠指定額外查詢約束,例如,下面咱們來添加一個驗證 account_id 爲 1 的約束:

'email' => Rule::unique('users')->where(function ($query) {
                                                        $query->where('account_id', 1);
                                                    })

url:驗證字段必須是有效的 URL。

uuid:該驗證字段必須是有效的 RFC 4122(版本 一、三、4 或 5)全局惟一標識符(UUID)。

添加條件規則

   存在時驗證

     在某些場景下,你可能想要只有某個字段存在的狀況下進行驗證檢查,要快速實現這個,添加 sometimes 規則到規則列表:

$v = Validator::make($data, [
    'email' => 'sometimes|required|email',
]);

     在上例中,email 字段只有存在於 $data 數組時纔會被驗證。

注:若是你嘗試驗證一個老是存在但可能爲空的字段時,參考 可選字段注意事項。

   複雜條件驗證

     有時候你可能想要基於更復雜的條件邏輯添加驗證規則。例如,你可能想要只有在另外一個字段值大於 100 時纔要求一個給定字段是必須的,或者,你可能須要只有當另外一個字段存在時兩個字段才都有給定值。添加這個驗證規則並非一件頭疼的事。首先,建立一個永遠不會改變的靜態規則到 Validator 實例:

$v = Validator::make($data, [
    'email' => 'required|email',
    'games' => 'required|numeric',
]);

     假定咱們的 Web 應用服務於遊戲收藏者。若是一個遊戲收藏者註冊了咱們的應用並擁有超過 100 個遊戲,咱們想要他們解釋爲何他們會有這麼多遊戲,例如,也許他們在運營一個遊戲二手店,又或者他們只是喜歡收藏。要添加這種條件,咱們可使用 Validator 實例上的 sometimes 方法:

$v->sometimes('reason', 'required|max:500', function($input) {
    return $input->games >= 100;
});

     傳遞給 sometimes 方法的第一個參數是咱們須要有條件驗證的名稱字段,第二個參數是咱們想要添加的規則,若是做爲第三個參數的閉包返回 true,規則被添加。該方法讓構建複雜條件驗證變得簡單,你甚至能夠一次爲多個字段添加條件驗證:

$v->sometimes(['reason', 'cost'], 'required', function($input) {
    return $input->games >= 100;
});

注:傳遞給閉包的 $input 參數是 Illuminate\Support\Fluent 的一個實例,可用於訪問輸入和文件。

驗證數組輸入

     驗證表單數組輸入字段再也不是件痛苦的事情,例如,若是進入的 HTTP 請求包含 photos[profile] 字段,能夠這麼驗證:

$validator = Validator::make($request->all(), [
    'photos.profile' => 'required|image',
]);

     咱們還能夠驗證數組的每一個元素,例如,要驗證給定數組輸入中每一個 email 是不是惟一的,能夠這麼作(這種針對提交的數組字段是二維數組,如 person[][email] 或 person[test][email]):

$validator = Validator::make($request->all(), [
    'person.*.email' => 'email|unique:users',
    'person.*.first_name' => 'required_with:person.*.last_name',
]);

     相似地,在語言文件中你也可使用 * 字符指定驗證消息,從而可使用單個驗證消息定義基於數組字段的驗證規則:

'custom' => [
    'person.*.email' => [
        'unique' => '每一個人的郵箱地址必須是惟一的',
    ]
],

自定義驗證規則

   使用 Rule 對象

     如上所述,Laravel 提供了多種有用的驗證規則;不過,你可能仍是須要指定一些本身的驗證規則。註冊自定義驗證規則的一種方法是使用規則對象,要生成一個新的規則對象,可使用 Artisan 命令 make:rule。下面咱們使用這個命令來生成一個用於驗證字符串是不是大寫的規則,生成的新規則對象類位於 app/Rules 目錄:

php artisan make:rule Uppercase

     規則建立以後,就能夠定義行爲方法,一個規則對象包含兩個方法:passes 和 messagepasses 方法接收屬性值和名稱,而且基於屬性值是否有效返回 true 或 falsemessage 方法用於在驗證失敗時返回驗證錯誤消息:

<?php

namespace App\Rules;

use Illuminate\Contracts\Validation\Rule;

class Uppercase implements Rule
{
    /**
     * Determine if the validation rule passes.
     *
     * @param  string  $attribute
     * @param  mixed  $value
     * @return bool
     */
    public function passes($attribute, $value)
    {
        return strtoupper($value) === $value;
    }

    /**
     * Get the validation error message.
     *
     * @return string
     */
    public function message()
    {
        return 'The :attribute must be uppercase.';
    }
}

     固然,你能夠在 message 方法中調用輔助函數 trans 來返回一個在語言文件中定義的錯誤消息:

/**
 * Get the validation error message.
 *
 * @return string
 */
public function message()
{
    return trans('validation.uppercase');
}

     規則定義好以後,就能夠將其以規則對象實例的方式和其餘驗證規則一塊兒提供給驗證器:

use App\Rules\Uppercase;

$request->validate([
    'name' => ['required', new Uppercase],
]);

   使用閉包

     若是在整個應用只須要一次自定義規則的功能,可使用閉包替代規則對象。該閉包接收屬性名、屬性值以及驗證失敗時調用的 $fail 回調:

$validator = Validator::make($request->all(), [
    'title' => [
        'required',
        'max:255',
        function($attribute, $value, $fail) {
            if ($value === 'foo') {
                return $fail($attribute.' is invalid.');
            }
        },
    ],
]);

   使用擴展

     另外一個註冊自定義驗證規則的方式是使用 Validator 門面上的 extend 方法。咱們在某個服務提供者(如 AppServiceProvider)中使用該方法註冊一個自定義驗證規則:

<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Validator;

class AppServiceProvider extends ServiceProvider
{
    /**
     * 啓動應用服務
     *
     * @return void
     */
    public function boot()
    {
        Validator::extend('foo', function($attribute, $value, $parameters, $validator) {
            return $value == 'foo';
        });
    }

    /**
     * 註冊服務提供者
     *
     * @return void
     */
    public function register()
    {
        //
    }
}

     自定義驗證器閉包接收四個參數:要驗證的屬性名稱、屬性值、傳遞給規則的參數數組以及 Validator 實例。

     你還能夠傳遞類和方法到 extend 方法而不是閉包:

Validator::extend('foo', 'FooValidator@validate');

   定義錯誤信息

     你還須要爲自定義規則定義錯誤信息。你可使用內聯自定義消息數組或者在驗證語言文件中添加條目來實現這一功能。消息應該被放到數組的第一維,而不是在只用於存放屬性指定錯誤信息的 custom 數組內:

"foo" => "Your input was invalid!",
"accepted" => "The :attribute must be accepted.",
// 驗證錯誤信息其它部分...

     當建立一個自定義驗證規則時,你可能有時候須要爲錯誤信息定義自定義佔位符,能夠經過建立自定義驗證器而後調用 Validator 門面上的 replacer 方法來實現。在服務提供者的 boot 方法中編寫以下代碼:

/**
 * 啓動應用服務
 *
 * @return void
 * @translator laravelacademy.org
 */
public function boot(){
    Validator::extend(...);
    Validator::replacer('foo', function($message, $attribute, $rule, $parameters) {
        return str_replace(...);
    });
}

   隱式擴展

     默認狀況下,被驗證的屬性若是沒有提供或者驗證規則爲 required 而值爲空,那麼正常的驗證規則,包括自定義擴展將不會執行。例如,unique 規則將不會檢驗 null 值:

$rules = ['name' => 'unique'];
$input = ['name' => null];
Validator::make($input, $rules)->passes(); // true

     若是要求即便爲空時也要驗證屬性,則必需要暗示屬性是必須的,要建立一個隱式擴展,可使用 Validator::extendImplicit() 方法:

Validator::extendImplicit('foo', function($attribute, $value, $parameters, $validator) {
    return $value == 'foo';
});

     注:一個隱式擴展僅僅暗示屬性是必須的,至於它究竟是缺失的仍是空值這取決於你。

相關文章
相關標籤/搜索