3分鐘短文:Laravel的“南天門”,過濾掉七七八八的資料

程式設計師小助手發表於2020-10-24

引言

上一章我們教會大家如何從使用者表單內正確地獲取資料,可是沒有講,獲取到的資料到底有啥用,或者說,有的使用者提交的資料壓根兒就沒正經填,那些錯亂無效的資料,如果直接放到資料庫,純粹是對資料庫的汙染。

img

所以本文就來說說應用程式最重要的一環,驗證資料。

程式碼時間

獲取資料的途徑除了早前介紹的在路由地址內通過位置引數繫結的方式,

還有上一章介紹的表單提交的方式,還有一些比如在get請求內附加查詢引數進行傳送的,

不管形式是什麼,我們需要將其統一口徑,將其規劃為規範的資料格式,然後只用把資料發給驗證器。

如果你對原始碼稍加留意,可能就會注意到,laravel的 Controller 類引入了 ValidatesRequests 這個驗證 trait。

class Controller extends BaseController
{
    use AuthorizesRequests, DispatchesJobs, ValidatesRequests;
}

其內部宣告瞭一個 validate 方法,使我們可以直接在上下文呼叫驗證。首先假設有兩個路由,在 routes/web.php 檔案內新增下面的程式碼:

Route::get('recipes/create', 'RecipesController@create');
Route::post('recipes', 'RecipesController@store');

其中get方法是用於渲染recipe建立的表單,post方法用於接收表單來的資料,我們先實現get的控制器方法。

在檔案 app/Http/Controllers/RecipesController.php 內新增diamante:

public function create()
{
    return view('recipes.create');
}

檢視檔案模板什麼的,我們都略過不講,就假設表單有了,使用者也可以提交上資料來了。下面實現 post 方法接收資料,並進行驗證:

public function store(Request $request)
{
    $this->validate($request, [
        'title' => 'required|unique:recipes|max:125',
        'body' => 'required'
    ]);
    // 資料有效
}

注意上面的驗證部分有一個隱式約定,就是傳入的 $request 物件,在驗證器內預設會使用 $request->all() 或 $request->input() 獲取全部的輸入欄位和資料。

validate 方法傳入的第二個引數,是一個驗證規則陣列。上面列出來的都是內建規則,簡單介紹一下吧:

  • required : 這個欄位必填
  • unique : 資料庫這個欄位值必須唯一不重樣
  • max : 這個欄位最長125個字元

那麼有的同學會立馬提出疑問:

那個validate方法如何驗證不通過,執行啥動作,也沒見控制器內有什麼捕獲異常的程式碼?

是的,這是laravel框架寫好了,如果驗證失敗,會使用 MessageBag 這些類來狀態驗證失敗的資訊,然後將錯誤資訊渲染到公共模板部分,使用 $errors 接收,這是一個物件,可以手動遍歷輸出。

如果你想手動處理,那麼只要在檢視內使用下面的程式碼列印即可,因為錯誤資訊是全域性的。

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

這都是通用的,貼到專案裡就可以起作用的。

下面我們講解一下手動使用驗證器怎麼組織程式碼。比如不想把驗證程式碼的邏輯寫到控制器裡,你可以選擇在路由的時候就進行驗證,在路由檔案內修改上述程式碼:

Route::post('recipes', function (Illuminate\Http\Request $request) {

    $validator = Validator::make($request->all(), [
        'title' => 'required|unique:recipes|max:125',
        'body' => 'required'
    ]);

    if ($validator->fails()) {
        return redirect('recipes/create')
        ->withErrors($validator)
        ->withInput();
    }
    // 驗證通過
});

大家看到了,驗證規則部分沒有一絲絲改變,只是傳入的 $request 請求物件我們必須呼叫 all() 方法對其格式化為陣列。然後顯式地使用 $validator->fails() 方法驗證是否驗證失敗。

如果驗證失敗,構建 Response 物件進行重定向,並使用 withErrors 語法糖將驗證提示資訊返回,而重定向的頁面內,可以使用 $errors 變數獲取到所有的錯誤資訊。這就組成了一個驗證的閉環。

寫在最後

本文講了一個非常關鍵的驗證器操作,讓大家明白這個功能如何使用,並沒有深入原始碼或者深度定製錯誤驗證。

還有驗證規則,千奇百怪,內建的規則都有很多,用得到的,用不到的,在處理複雜業務邏輯的時候,

還要祭出自定義驗證規則這把大寶劍,不過都是後話了。

Happy coding :-)

我是@程式設計師小助手,專注程式設計知識,圈子動態的IT領域原創作者

本作品採用《CC 協議》,轉載必須註明作者和本文連結
write-less-do-more-make-you-out-of-door

相關文章