Laravel form request

  • January 1, 2025
  • 122

Ở bài viết trước chúng ta đã tìm hiểu tổng quan về laravel form request, bài viết này sẽ tập chung vào các rule hay dùng khi validate data với laravel.

1. Validate create user

Tạo một form request với các rule validate dữ liệu tạo user.


public function rules()
{
    return [
        'name' => 'required|string|max:255',
        'email' => 'required|email|unique:users,email',
        'password' => 'required|min:8|confirmed',
    ];
}

Rule trên định nghĩa request tạo user phải bắt buộc(require) có các thông tin name, email, password. name có kiểu là string và nhiều nhất 255 kí tự. email có định dạng là email và phải là duy nhất trong bảng users. password ít nhất 8 kí tự và phải truyền thêm password_confirmation để confirm lại password.

2. Validate change password

Tạo một request định nghĩa các rule cho việc thay đổi password


<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

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

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules(): array
    {
        return [
            'password_old' => ['required', 'string'],
            'password_new' => [
                'required',
                'min:8',
                'max:255',
                'string',
                'regex:/^(?=.*[a-z])(?=.*\d)[A-Za-z\d@$!%*?&]{8,30}$/',
            ],
            'confirm_password' => [
                'required',
                'same:password_new',
                'min:8',
                'max:255',
                'string',
                'regex:/^(?=.*[a-z])(?=.*\d)[A-Za-z\d@$!%*?&]{8,30}$/',
            ],
        ];
    }

    /**
     * Get the error messages for the defined validation rules.
     *
     * @return array<string, string>
     */
    public function messages(): array
    {
        return [
            'password_old.required' => trans('validation.required'),
            'password_new.required' => trans('validation.required'),
            'password_new.min' => trans('validation.min.string'),
            'password_new.regex' => trans('messages.regex-password-register'),
            'confirm_password.required' => trans('validation.required'),
            'confirm_password.min' => trans('validation.min.string'),
            'confirm_password.same' => trans('validation.same'),
            'confirm_password.regex' => trans('messages.regex-password-register'),
        ];
    }

    /**
     * Get custom attributes for validator errors.
     *
     * @return array<string, string>
     */
    public function attributes(): array
    {
        return [
            'password_old' => trans('messages.attributes.password-old'),
            'password_new' => trans('messages.attributes.password-new'),
            'confirm_password' => trans('messages.attributes.confirm-password'),
        ];
    }
}

3. Validate file

Tạo form request validate người dùng gửi file


<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;
use App\Constants\PostStatus;

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

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules(): array
    {
        return [
            'title' => ['required', 'string', 'max:255'],
            'content' => ['nullable', 'string', 'max:1000'],
            'status' => ['required', 'integer', Rule::in(PostStatus::ALL)],
            'image' => 'required|file|max:10000|mimes:jpg,jpeg,png,gif',
            'file' => [
                'nullable',
                function ($attribute, $value, $fail) {
                    $mime = $value->getMimeType();
                    $videoMimeTypes = ['video/mp4', 'video/avi', 'video/mov'];

                    if (in_array($mime, $videoMimeTypes)) {
                        if ($value->getSize() > 200 * 1024 * 1024) {
                            $fail("The $attribute size must not exceed 200MB.");
                        }
                    } else {
                        $imageMimeTypes = ['image/jpeg', 'image/png', 'image/jpg', 'image/gif'];

                        if (in_array($mime, $imageMimeTypes)) {
                            if ($value->getSize() > 5 * 1024 * 1024) {
                                $fail("The $attribute size must not exceed 5MB.");
                            }
                        } else {
                            $fail("The $attribute must be either a video or an image.");
                        }
                    }
                },
            ],
        ];
    }
}

Chỉ cho upload file là ảnh hoặc video, nếu là ảnh thì nhỏ hơn 5MB, còn video nhỏ hơn 200MB.

4. Validate search

Tạo form request validate search


public function rules(): array
{
    return [
        'category_id' => 'required|string',
        'email' => 'sometimes|email',
        'phone' => 'filled|regex:/^[0-9]{10}$/',
        'shop_name' => 'bail|required|max:50',
        'search' => 'nullable|string|max:50',
        'search2' => 'present|string',
    ];
}

category_id: rule required bắt buộc phải có trong request, không được để trống hoặc null.
email: rule sometimes chỉ validate email khi có email trong request, nếu không có trong request thì không validate.
phone: rule filled, trường không bắt buộc nhưng nếu có mặt trong request thì phải có giá trị không được null và giá trị phải là 10 số.
shop_name: rule bail dừng kiểm tra rule tiếp theo nếu rule hiện tại thất bại, ví dụ không truyền shop_name thì sẽ báo lỗi shop name không được để trống, mà không kiểm tra tiếp rule max 50.
search: rule nullable cho phép truyền lên giá trị null hoặc không truyền lên request.
search2: rule present trường bắt buộc phải có trong request không thể để trống, có thể null.

5. Validate array data

Tạo form request cho dữ liệu đầu vào là một mảng như sau


{
    "form_fields": [
        {
            "form_field_id": 1,
            "is_required": true,
            "order": 0,
            "status": true
        },
        {
            "form_field_id": 2,
            "is_required": false,
            "order": 1,
            "status": false
        }
    ]
}

Tạo form validate cho dữ liệu trên


public function rules(): array
    {
        return [
            'form_fields.*.form_field_id' => 'required|integer|exists:form_fields,id',
            'form_fields.*.is_required' => 'required|boolean',
            'form_fields.*.order' => 'required|integer|min:0',
            'form_fields.*.status' => 'required|boolean',
        ];
    }

Ý nghĩa của dấu .*
form_fields.*: Xác định rằng các quy tắc được áp dụng cho từng phần tử con của mảng form_fields.
Mỗi phần tử trong mảng form_fields phải có các trường con (form_field_id, is_required, order, status) và phải thỏa mãn các quy tắc tương ứng.

Ví dụ 2: validate user_medias là mảng cái giá trị id, file. nếu id khác null thì file là required


public function rules(): array
{
    return [
        'user_medias' => ['required', 'array', 'max:9'],
        'user_medias.*.id' => ['nullable', 'integer'],
        'user_medias.*.file' => ['required_if:user_medias.*.id,!=,null', 'max:5000', 'image'],
    ];
}

6. Validate datetime

Tạo form request validate thời gian


public function rules(): array
{
    return [
        'date' => 'required|date|date_format:Y-m-d',
        'reservation_start_time' => 'required|date_format:H:i:s|before:reservation_end_time',
        'reservation_end_time' => 'required|date_format:H:i:s|after:reservation_start_time',
    ];
}

7. Validate exist

kiểm tra request truyền lên phải tồn tại trong 1 bảng nào đó

public function rules(): array
    {
        return [
            'shop_id' => 'required|integer|exists:shops,id',
            'blocked_id' => [
                'required',
                'integer',
                Rule::exists('users', 'id')->where(function ($query) {
                    $query->where('id', '!=', Auth::id());
                })
            ],
            'status' => ['required', 'integer', Rule::in(BlockStatus::ALL)],
        ];
    }

8. Custom rule validate

Tạo custom rule với các điều kiện phức tạp


<?php

namespace App\Rules;

use Illuminate\Contracts\Validation\Rule;
use Illuminate\Support\Facades\DB;

class RequiredIfFormFieldIsRequired implements Rule
{
    protected $formFieldId;
    protected $shopId;

    public function __construct($formFieldId, $shopId)
    {
        $this->formFieldId = $formFieldId;
        $this->shopId = $shopId;
    }

    public function passes($attribute, $value)
    {
        // Check if the form_field_id exists and is marked as required
        $isRequired = DB::table('shop_form_field')
            ->where('form_field_id', $this->formFieldId)
            ->where('shop_id', $this->shopId)
            ->value('is_required');

        // Pass validation if not required or if value is provided
        return !$isRequired || !empty($value);
    }

    public function message()
    {
        return '値は必須項目です。';
    }
}

Sử dụng custom rule


public function rules(): array
{
    return [
        'shop_id' => 'required|integer|exists:shops,id',
        'reservation_start_time' => 'required|date_format:H:i:s|before:reservation_end_time',
        'reservation_end_time' => 'required|date_format:H:i:s|after:reservation_start_time',
    ];

    foreach ($this->input('reservation_values', []) as $key => $reservationValue) {
            $formFieldId = $reservationValue['form_field_id'] ?? null;
            $rules["reservation_values.$key.value"] = [
                new \App\Rules\RequiredIfFormFieldIsRequired($formFieldId, $this->input('shop_id'))
            ];
        }

    return $rules;
}

Kiểm tra xem form field của shop có setting required không? nếu require thì mới validate require.