2. Tùy chỉnh quy ước xác thực

https://viblo.asia/p/tap-21-validation-laravel-tiep-theo-gAm5yGaAZdb

IX. Tùy chỉnh quy ước xác thực (Custom validation rule)

1. Sử dụng rule object (Using rule object)

Laravel cung cấp rất nhiều rule hữu ích; tuy nhiên, chúng ta vẫn có thể chỉ định các rule theo ý muốn. Để tạo một rule object mới, ta có thể sử dụng lệnh Artisan sau:

php artisan make:rule Uppercase

Một thư mục app/Rules sẽ được tạo cùng với file Uppercase.php bên trong. Bây giờ hãy mở file này lên và quan sát:

<?php

namespace App\Rules;

use Illuminate\Contracts\Validation\Rule;

class Uppercase implements Rule
{
    /**
     * Create a new rule instance.
     *
     * @return void
     */
    public function __construct()
    {
        //
    }

    /**
     * Determine if the validation rule passes.
     *
     * @param  string  $attribute
     * @param  mixed  $value
     * @return bool
     */
    public function passes($attribute, $value)
    {
        //
    }

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

Trong một rule object có hai method chính: passesmessage. Method passes sẽ nhận tên trường và giá trị của nó và trả về các giá trị true hoặc false tùy thuộc vào giá trị của trường có hợp lệ hay không. Method message sẽ trả về thông báo lỗi xác thực nếu không vượt qua.

Giờ hay chèn đoạn code này vào method passes:

public function passs($attribute, $value)
{
    return strtoupper($value) === $value;
}

Tiếp đến là tùy chỉnh một chút câu thông báo:

public function message()
{
    return 'The :attribute must be uppercase.';
}

Như thế là ta đã có thể kiểm tra được rồi đấy, để gọi validation rule ta chỉ cần khởi tạo object của nó trong validator.

use App\Rules\Uppercase;

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

2. Sử dụng closure (Using closure)

Nếu bạn chỉ cần tùy chỉnh rule 1 lần duy nhất trong ứng dụng, bạn có thể sử dụng hình thức closure để làm việc này thay thế cho rule object. Closure này sẽ nhận tên trường, giá trị của trường và một biến callback $fail để trả về lỗi nếu không vượt qua.

$request->validate([
    'name' => [
        'required',
        'string',
        function ($attribute, $value, $fail)) {
            if ($value !== strtoupper($value) {
                $fail("The $attribute must be uppercase.");
            }
        }
    ]
]);

3. Sử dụng tiện ích mở rộng (Using extension)

Một cách khác để đăng ký validation rule tùy chỉnh đó là sử dụng method extend trong Validator facade. Ta có thể định nghĩa nó tại method boot của AppServiceProvider.

public function boot()
{
    Validator::extend('uppercase', function ($attribute, $value, $parameters, $validator) {
         return strtoupper($value) === $value;
    });
}

Bạn cũng có thể truyền vào một controller action thay vì closure.

Validator::extend('uppercase', 'UppercaseValidator@validate');
public function validate($attribute, $value, $parameters, $validator)
{
    return strtoupper($value) === $value;
}

Để khai báo thông báo xác thực lỗi cho rule vừa khởi tạo, các bạn mở file resources/lang/xx/validation.php và định nghĩa câu thông báo cùng cấp với các rule có sẵn khác.

// ...
'uuid' => 'The :attribute must be a valid UUID.',
'uppercase' => 'The :attribute must be uppercase.',
// ...

Như vậy là ta đã có thể sử dụng được rồi đấy.

$request->validate([
    'name' => 'required|string|uppercase'
]);

Ngoài ra, bạn cũng có thể thay đổi câu thông báo xác thực tại service provider bằng cách sử ụng method Validator::replacer sau khi đã định nghĩa method Validator::extend trước đó.

public function boot() 
{
    Validator::extend(...);
    
    Validator::replacer('uppercase', function ($message, $attribute, $rule, $parameters) {
        return str_replace('uppercase', 'chữ hoa', $message);
    });
}

4. Tiện ích mở rộng tiềm ẩn (Implicit extension)

Theo mặc định, một trường được xác thực không tồn tại hoặc rỗng trong đầu vào, các quy tắc xác thực có sẵn, bao gồm cả các quy tắc tùy chỉnh sẽ không được chạy. Chẳng hạn rule unique sẽ không chạy nếu như đầu vào mang giá trị rỗng.

$rules = ['name' => 'unique:users,name'];

$input = ['name' => ''];

Validator::make($input, $rules)->passes(); // true

Để một rule chạy ngay cả khi trường mang dữ liệu trống, quy tắt phải ngụ ý rằng trường được required. Để tạo một "implicit" extension, sử dụng method Validator::extendImplicit.

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

Lưu ý: Một "implicit" extension chỉ ngụ ý rằng trường được required. Cho dù nó thực sự làm mất hiệu lực một trường không tồn tại hoặc trống là tùy thuộc vào bạn.

Rule object tiềm ẩn

Nếu bạn muốn một rule object chạy ngay cả khi giá trị của trường trống hoặc không tồn tại, bạn có thể implement interface Illuminate\Contracts\Validation\ImplicitRule. Interface này sẽ đóng vai trò là "giao diện đánh dấu" cho validator; do đó nó sẽ không chứa bất cứ method nào bạn cần để implement.

Cảm ơn các bạn đã quan tâm theo dõi. Cùng đồng hành với mình qua những tập tiếp theo tại series "Hành trình chinh phục Laravel Framework" nhé! Chúc may mắn và hẹn gặp lại.

Last updated