Validation Laravel Phần cuối - Conditionally adding rules

Trong phần cuối cùng của loạt bài Validation Laravel này chúng ta sẽ tìm hiểu về Conditionally adding rules ( Cách thêm các điều kiện) trong Laravel các bạn nhé

VII. Thêm điều kiện (Conditionally adding rules)

1. Xác thực khi tồn tại (Validating when present)

Trong một vài trường hợp, bạn muốn chạy trình xác thực khi trường đó thực sự tồn tại trong đầu vào. Để thực hiện nhanh, bạn có thể thêm rule sometimes trước khi khai báo các validation rule khác.

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

Trong đoạn code trên, trường email chỉ được xác thực khi nó tồn tại trong $data.

Lưu ý: Nếu như bạn đang muốn xác thực một trường nhưng nó có thể trống, bạn có thể xem xét đặt rule nullable.

2. Xác thực điều kiện phức tạp (Complex conditional validation)

Đôi khi, bạn muốn thêm các quy tắc xác thực dựa trên điều kiện logic phức tạo hơn. Chẳng hạn bạn chỉ muốn required một trường nhất định nếu trường khác có giá trị lớn hơn hoặc bằng 100. Hãy xem ví dụ sau:

HTML:

Mình sẽ tạo hai trường field và anotherfield.

<input type="text" name="field">
<input type="text" name="anotherfield">

Validation rule:

Đến đây, ta sẽ tạo trình validator với Validator facade.

use Illuminate\Support\Facades\Validator;

$validator = Validator::make($request->all(), [
    'field' => 'required|numeric'
]);

$validator->sometimes('anotherfield', 'required', function ($input) {
    return $input->field >= 100;
});

Quan sát quá trình validator trên, ban đầu mình đã khai báo các validation rule cho trường field. Yêu cầu của ứng dụng là nếu như giá trị của trường field này mà lớn hơn hoặc bằng 100 thì sẽ xác thực required cho trường anotherfield bằng cách sử dùng method sometimes.

  • Tham số thứ nhất chính là tên trường cần xác thực
  • Tham số thứ hai chính là danh sách các validation rule cần vượt qua.
  • Tham số thứ ba sẽ là một Closure object, nó nhận nhận tham số $input để có thể truy cập đến các input request, cuối cùng trả về một giá trị boolean, nếu true thì trường đó sẽ thực hiện validate.

VIII. Xác thực mảng (Validating array)

Xác thực các trường dựa trên mảng không phải là một điều quá khó khăn. Bạn có thể sử dụng ký tự . để tham chiểu đến các phần tử trong mảng trong quá trình tạo trình xác thực. Chẳng hạn nếu request có chứa mảng hình ảnh photos[profile] thì ta có thể thực hiện validate như sau:

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

Nếu request chứa mảng multi-level, bạn vẫn có thể tham chiếu đến các phần tử con trong mảng như sau:

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

Tương tự, bạn cũng có thể sử dụng ký tự * để chỉ định các thông báo xác thực trong file ngôn ngữ, giúp dễ dàng tạo thông báo xác thực cho các trường dựa trên mảng.

'custom' => [
    'person.*.email' => [
        'unique' => 'Each person must have a unique e-mail address',
    ]
],

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: passes và message. 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.

Lời kết:

Vậy là chúng ta đã tìm hiểu xong toàn bộ phần Validation Laravel rồi đấy. Có gì thắc mắc hay chưa hiểu các bạn hãy comment bên dưới nha. Chúc các bạn học tốt!

Bình luận