Validation trong Laravel (P2)

Mở đầu

Ở bài trước mình đã giới thiệu qua về cách xử dụng Validation trong Laravel, nếu bạn chưa đọc thì bạn nên quay lại đọc nó trước khi bắt đầu đọc bài viết này, link bài viết Validation trong Laravel (P1). Còn nếu bạn đã đọc thì chúng ta bắt đầu thôi, bài viết này sẽ hướng dẫn cách sử dụng cũng như chỉnh sửa error message mặc định mà Laravel sinh ra theo mong muốn cá nhân của bạn.

Hiển thị Error

Như bạn thấy ở trên, phần khung đỏ thông báo lỗi chính nơi mà ta dùng để hiển thị các error mặc định của Laravel. Trong blade template của Laravel cung cắp sãn cho chúng ta một object chứa trong biến có tên là $errors là thể hiện của class Illuminate\Support\MessageBag. Tất cả các lỗi validation được sinh ra sẽ đều được lưu trữ trong biến này và sau đó ở bên giao diện bạn có thể dùng biến này để hiện thị dữ liệu theo ý muốn của bạn. Sau đây là một số hàm mình thường dùng với biến $errors:

  • $errors->any(): Kiểm tra xem có lỗi nào không
  • $errors->all(): Lấy toàn bộ lỗi (thường dùng trong vòng lặp foreach)
  • $errors->has('email'): Kiểm tra xem có lỗi nào cho input field có name là email không
  • $errors->first('email'): Lấy ra lỗi đầu tiên của input field có name là email Nếu muốn tham khảo hết các hàm mà biến $errors này hỗ trợ bạn có thể đọc ở đây

1. Hiển thị error thông thường

Nếu bạn đã đọc qua document của Laravel về phần Validation, bạn sẽ thấy có một đoạn code hướng dẫn hiển thị các lỗi như sau:

@if ($errors->any())
    <div class="alert alert-danger">
        <ul>
            @foreach ($errors->all() as $error)
                <li>{{ $error }}</li>
            @endforeach
        </ul>
    </div>
@endif
  • Đoạn code trên sử dụng 2 hàm mà mình đã nói đến ở trước đó, đầu tiên ta sẽ tiến hành kiểm tra có lỗi nào hay không với hàm any() nếu có thì sẽ dùng hàm all() trong vòng lặp để hiển thị các lỗi đó ra màn hình. Đây cũng chính là đoạn code mình sử dụng cho bức ảnh ở trên, bạn chỉ cần include đoạn code trên vào file có chứa form của bạn, khi bạn lần cầu truy cập trang chứa form này hay đúng hơn là khi không có lỗi nào thì đoạn code chứa giao diện trên sẽ không hiển thị ra. Còn trong trường hợp form người dùng nhập có lỗi và redirect lại trang có chứa form thì lập tức sẽ xuất hiện phần lỗi. Bạn có thể chỉnh lại các class trong các thẻ html đi cùng đoạn code sao cho phù hợp với trang web của bạn.

  • Nếu bạn chọn hiển thị theo dạng danh sách như trên thì bạn có thể làm như sau để tối ưu code, ta sẽ lấy đoạn code mình dùng để hiển thị lỗi như trên để demo cho ví dụ này, đoạn code của mình:

@if ($errors->any())
    <section class="error">
        <div class="container">
            <div class="columns is-centered">
                <div class="column is-6">
                    <div class="notification is-danger">
                        <ul>
                            @foreach ($errors->all() as $error)
                                <li>{{ $error }}</li>
                            @endforeach
                        </ul>
                    </div>
                </div>
            </div>
        </div>
    </section>
@endif
  • Ta có thể tách phần code nằm giữa @if - @else và đưa nó ra một file mới có tên là form-error.blade.php sau đó ta được 1 file như sau:
<!-- form-error.blade.php -->
@if ($errors->any())
    <section class="error">
        <div class="container">
            <div class="columns is-centered">
                <div class="column is-6">
                    <div class="notification is-danger">
                        <ul>
                            @foreach ($errors->all() as $error)
                                <li>{{ $error }}</li>
                            @endforeach
                        </ul>
                    </div>
                </div>
            </div>
        </div>
    </section>
@endif
  • Lưu ý: như đã nói ban đầu thì biến $errors có thể được truy cập từ bất cứ file .blade.php nào bạn tạo ra. Còn đoạn code ban đầu ta sẽ sửa lại như sau:
@include('form-error')
  • Như vậy ở mỗi form bạn có thể thêm đoạn code mới này vào vị trí mong muốn trong form. Trong trường hợp bạn cần sửa đổi giao diện sẽ chỉ cần sửa ở file form-error.blade.php thì tất cả các vị trí sử dụng form này sẽ được cập nhật giao diện. Nếu bạn giữa nguyên đoạn code ban đầu, nếu phát sinh trường hợp sửa giao diện bạn sẽ phải sửa lại ở từng file dùng đến nó.

2. Hiển thị error theo từng field

Trong trường hợp bạn muốn hiển thị lỗi của các field input ngay bên dưới field đó như sau: Đây là lúc bạn cần sử dụng hàm $errors->first(f'ield-name'), hàm này sẽ trả về lỗi đầu tiên ứng với name của field hoặc trả về rỗng nếu không có lỗi nào. Như vậy bên file chứa giao diện form bạn có thể thêm như sau:

<div class="field">
    <label class="label">Email</label>
    <div class="control">
        <input class="input" type="email" placeholder="e.g. [email protected]" name="email">
    </div>
    <p class="help is-danger">{{ $errors->first('email') }}</p>
</div>

Như đoạn code trên, ta chỉ việc thêm $errors->first('email') với email là phần name của phần nhập dữ liệu ngay trên đó. Khi ấy mỗi khi kiểm tra có lỗi và quay lại trang chứa form ta sẽ được kết quả như hình trên. Ngoài ra nếu bạn muốn kiểm tra xem có tồn tại lỗi không trước khi hiển thị thẻ <p> chứa lỗi như trên thì ta có thể sửa thành như sau:

<div class="field">
    <label class="label">Email</label>
    <div class="control">
        <input class="input" type="email" placeholder="e.g. [email protected]" name="email">
    </div>
    @if ($errors->has('email'))
        <p class="help is-danger">{{ $errors->first('email') }}</p>
    @endif
</div>

Ở đây ta sử dụng thêm hàm $errors->has('email') để kiểm tra xem có tồn tại lỗi cho field có name="email" hay không trước khi thực hiện việc hiển thị thẻ <p>.

Chỉnh sửa message mặc định

Mặc định tất cả các message bạn thấy trong biến $errors có nội dung nằm trong đường dẫn file: resources\lang\en\validation.php với nội dung dạng như sau:

<?php

return [

    /*
    |--------------------------------------------------------------------------
    | Validation Language Lines
    |--------------------------------------------------------------------------
    |
    | The following language lines contain the default error messages used by
    | the validator class. Some of these rules have multiple versions such
    | as the size rules. Feel free to tweak each of these messages here.
    |
    */

    'accepted'             => 'The :attribute must be accepted.',
    'active_url'           => 'The :attribute is not a valid URL.',
    'alpha'                => 'The :attribute may only contain letters.',
    'alpha_dash'           => 'The :attribute may only contain letters, numbers, and dashes.',
    'alpha_num'            => 'The :attribute may only contain letters and numbers.',
    'array'                => 'The :attribute must be an array.',
    ...

Trong nội dung file, ta có thể thấy phần key của mảng sẽ là tên các điều kiện kiểm tra dữ liệu còn phần value bên phải chính là message báo lỗi tương ứng với nó. Tuy nhiên trong phần báo lỗi bạn sẽ thấy có điều đặc biệt đó là :attribute, khi hiển thị message, :attribute sẽ được tự động thay thế bằng tên của field đó trong thẻ <input>. Ví dụ ta có thẻ <input> như sau:

<input type="text" name="username">

Ta áp dụng điều kiện 'alpah' => 'The :attribute may only contain letters.'. Khi có dữ liệu nhập vào đối với filed này không hợp lệ thì message báo lỗi sẽ có dạng:

The username may only containt letters

Với :attribute lúc này đã được thay thế bằng username. Như ta thấy chúng ta hoàn toàn có thể thay đổi nội dung message trong file này, tuy nhiên không nên làm như vậy mà thay vì thế ta sẽ tạo message mới cho nó. Để demo ví dụ này, ta sẽ sử dụng lại class SignupRequest đã được nhắc đến trong bài viết trước như sau:

<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class SignupRequest extends FormRequest
{
    /**
     * Determine if the user is authorized to make this request.
     *
     * @return bool
     */
    public function authorize()
    {
        return true;
    }

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        return [
            'username' => 'bail|required|alpha|min:6|max:10',
            'email' => 'bail|required|email',
            'password' => 'bail|required|min:8',
            'password_confirmation' => 'bail|required|same:password',
        ];
    }
}

Đầu tiên ta sẽ thêm một hàm mới cho class này có tên là messages() như sau:

<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class SignupRequest extends FormRequest
{
    /**
     * Determine if the user is authorized to make this request.
     *
     * @return bool
     */
    public function authorize()
    {
        return true;
    }

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        return [
            'username' => 'bail|required|alpha|min:6|max:10',
            'email' => 'bail|required|email',
            'password' => 'bail|required|min:8',
            'password_confirmation' => 'bail|required|same:password',
        ];
    }
    
    public function messages()
    {
        //
    }
}

Bên trong hàm này chính là nơi ta sẽ định nghĩa các message cho các field cũng như các điều kiện tương ứng với field như sau:

public function messages()
{
    return [
        'username.required' => 'Username không được để trống',

        'email.email' => 'Email không đúng định dạng',

        'password.min' => 'Mật khẩu tối thiểu 8 kí tự',

        'password_confirmation.same' => 'Mật khẩu không trùng nhau',
    ];
}

Giải thích qua một chút, trong hàm này ta sẽ trả về một mảng có dạng như sau: field-name.rule => custom message với tên của field-name và rule sẽ lần lượt là tên của field đó cùng với điều kiện mà chúng ta muốn kiểm tra như trong hàm rules(). Bên còn lại chính là nội dung mà chúng ta muốn dành cho điều kiện đó. Ở đây mình chỉ demo mỗi field một điều kiện còn bạn hoàn toàn có thể sửa lại toàn bộ nội dung của từng điều kiện. Sau khi thêm hàm messages() ta kiểm tra thử lại với các điều kiện đã sửa lỗi sẽ thu được kết quả như sau: Như vậy các message báo lỗi đúng như những gì mafd chúng ta mong muốn.

Kết bài

Mong rằng qua 2 bài viết của mình về Validation trong Laravel sẽ giúp bạn được phần nào trong quá trình sử dụng Laravel. Cảm ơn bạn đã đọc.