Skip to content

Validation (Xác thực dữ liệu)

Giới thiệu (Introduction)

Laravel cung cấp nhiều cách để validate incoming data. Phổ biến nhất là dùng method validate trên HTTP request object.

Validation nhanh (Quickstart)

Định nghĩa Routes

php
use App\Http\Controllers\PostController;

Route::get('/post/create', [PostController::class, 'create']);
Route::post('/post', [PostController::class, 'store']);

Viết Logic Validation

Dùng method validate trong controller:

php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\View\View;

class PostController extends Controller
{
    public function create(): View
    {
        return view('post.create');
    }

    public function store(Request $request): RedirectResponse
    {
        $validated = $request->validate([
            'title' => 'required|unique:posts|max:255',
            'body' => 'required',
        ]);

        // Dữ liệu đã validate hợp lệ...
        // Lưu bài viết...

        return redirect('/posts');
    }
}

Nếu validation fail, Laravel tự động redirect user về trang trước kèm error messages và old input.

Với XHR requests, trả JSON response với status 422 kèm validation errors.

Hiển thị Validation Errors

Biến $errors tự động có sẵn trong tất cả views (chia sẻ qua ShareErrorsFromSession middleware):

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

Directive @error:

blade
<input id="title" type="text"
    class="@error('title') is-invalid @enderror">

@error('title')
    <div class="alert alert-danger">{{ $message }}</div>
@enderror

Repopulating Forms

Dùng old helper:

blade
<input type="text" name="title" value="{{ old('title') }}">

Lưu ý về Optional Fields

Mặc định, Laravel bao gồm middleware TrimStringsConvertEmptyStringsToNull. Nếu field optional có thể null, đánh dấu nullable:

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

Form Request Validation

Tạo Form Requests

bash
php artisan make:request StorePostRequest

Class chứa methods authorize (kiểm tra quyền) và rules (quy tắc validation):

php
<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class StorePostRequest extends FormRequest
{
    public function authorize(): bool
    {
        return true; // hoặc kiểm tra quyền user
    }

    public function rules(): array
    {
        return [
            'title' => 'required|unique:posts|max:255',
            'body' => 'required',
        ];
    }
}

Sử dụng trong controller — type-hint trong method:

php
public function store(StorePostRequest $request): RedirectResponse
{
    // Request đã validate hợp lệ
    $validated = $request->validated();

    // Lưu bài viết...

    return redirect('/posts');
}

Tùy chỉnh Error Messages

php
public function messages(): array
{
    return [
        'title.required' => 'Tiêu đề bắt buộc nhập.',
        'body.required' => 'Nội dung bài viết bắt buộc nhập.',
    ];
}

Tùy chỉnh tên Attributes

php
public function attributes(): array
{
    return [
        'email' => 'địa chỉ email',
    ];
}

Chuẩn bị Input trước Validation

php
protected function prepareForValidation(): void
{
    $this->merge([
        'slug' => Str::slug($this->slug),
    ]);
}

Tạo Validator thủ công (Manually Creating Validators)

php
use Illuminate\Support\Facades\Validator;

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

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

$validated = $validator->validated();

After Validation Hook

php
$validator->after(function ($validator) {
    if ($this->somethingElseIsInvalid()) {
        $validator->errors()->add(
            'field', 'Có gì đó không đúng!'
        );
    }
});

Làm việc với Validated Input

php
$validated = $request->validated();     // array
$validated = $request->safe()->only(['name', 'email']);
$validated = $request->safe()->except(['password']);
$validated = $request->safe()->all();
$validated = $request->safe()->merge(['name' => 'Taylor']);

Các Validation Rules có sẵn

Laravel cung cấp hơn 100 validation rules tích hợp. Một số phổ biến:

RuleMô tả
requiredField bắt buộc
stringPhải là chuỗi
numericPhải là số
integerPhải là số nguyên
emailPhải là email hợp lệ
min:valueGiá trị tối thiểu
max:valueGiá trị tối đa
unique:table,columnDuy nhất trong bảng DB
exists:table,columnPhải tồn tại trong bảng DB
confirmedField phải khớp với {field}_confirmation
datePhải là ngày hợp lệ
arrayPhải là array
filePhải là file upload
imagePhải là ảnh (jpg, png, bmp, gif, svg, webp)
nullableCho phép null
booleanPhải là true, false, 1, 0, "1", "0"
urlPhải là URL hợp lệ
jsonPhải là JSON string hợp lệ

Xem danh sách đầy đủ trên trang docs gốc.

Custom Validation Rules

Sử dụng Rule Objects

bash
php artisan make:rule Uppercase
php
<?php

namespace App\Rules;

use Closure;
use Illuminate\Contracts\Validation\ValidationRule;

class Uppercase implements ValidationRule
{
    public function validate(string $attribute, mixed $value, Closure $fail): void
    {
        if (strtoupper($value) !== $value) {
            $fail(':attribute phải viết hoa toàn bộ.');
        }
    }
}

Sử dụng:

php
use App\Rules\Uppercase;

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

Sử dụng Closures

php
$request->validate([
    'title' => [
        'required',
        'max:255',
        function (string $attribute, mixed $value, Closure $fail) {
            if ($value === 'foo') {
                $fail("Giá trị {$attribute} không hợp lệ.");
            }
        },
    ],
]);

Validating Arrays

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

Validating Files

php
$request->validate([
    'photo' => 'required|file|image|max:1024',
    'attachment' => 'required|file|mimes:jpg,png,pdf|max:2048',
]);

Validating Passwords

php
use Illuminate\Validation\Rules\Password;

$request->validate([
    'password' => ['required', 'confirmed', Password::defaults()],
]);

// Tùy chỉnh
$request->validate([
    'password' => ['required', 'confirmed', Password::min(8)
        ->letters()
        ->mixedCase()
        ->numbers()
        ->symbols()
        ->uncompromised()],
]);