مقاله

قوانین شرطی، after validation، merge و prepareForValidation، custom messages و authorize — فراتر از rules ساده.

Form Request پیشرفته در Laravel — validation، authorization و prepare

Form Request پیشرفته در Laravel — validation، authorization و prepare

Form Request در Laravel validation و authorization را از Controller جدا می‌کند. بیشتر پروژه‌ها با rules() ساده شروع می‌کنند؛ پروژه واقعی به قوانین شرطی، normalize ورودی و پیام فارسی نیاز دارد.

چرخه Form Request

  1. authorize() — 403 اگر false
  2. prepareForValidation() — normalize قبل از validate
  3. rules() + messages/attributes
  4. passedValidation() / withValidator() — after hooks

authorize با Policy

public function authorize(): bool
{
    return $this->user()->can('create', Post::class);
}

Policy — منطق مجوز یک جا.

prepareForValidation — normalize

protected function prepareForValidation(): void
{
    $this->merge([
        'slug' => Str::slug($this->input('title')),
        'phone' => preg_replace('/\D/', '', $this->input('phone', '')),
    ]);
}

ورودی تمیز قبل از rule — شماره موبایل ایران یکدست.

قوانین شرطی

public function rules(): array
{
    return [
        'type' => ['required', Rule::in(['personal', 'company'])],
        'company_name' => [
            Rule::requiredIf($this->input('type') === 'company'),
            'string', 'max:255',
        ],
        'national_id' => [
            Rule::requiredIf($this->input('type') === 'personal'),
            'digits:10',
        ],
    ];
}

withValidator — after validation

public function withValidator(Validator $validator): void
{
    $validator->after(function (Validator $validator) {
        if ($this->couponInvalid()) {
            $validator->errors()->add('coupon', 'کد تخفیف معتبر نیست.');
        }
    });
}

برای cross-field یا query DB بعد از rules پایه.

پیام و attribute فارسی

public function messages(): array
{
    return [
        'title.required' => 'عنوان مقاله الزامی است.',
        'slug.unique' => 'این آدرس قبلاً استفاده شده.',
    ];
}

public function attributes(): array
{
    return ['title' => 'عنوان', 'slug' => 'نامک'];
}

Custom Rule class

'slug' => ['required', new UniquePostSlugExcept($this->route('post'))],

قابل تست جدا — unit test.

تبدیل به DTO

public function toDto(): CreatePostData
{
    return CreatePostData::fromArray($this->validated());
}

DTO.

API vs Web Form Request

همان کلاس — failedValidation override برای JSON 422:

protected function failedValidation(Validator $validator)
{
    throw new HttpResponseException(response()->json([
        'message' => 'Validation failed',
        'errors' => $validator->errors(),
    ], 422));
}

Error handling API.

اشتباهات

  • validation در Controller تکراری
  • authorize همیشه true
  • query سنگین در rules بدون cache

جمع‌بندی

Form Request مرز ورودی HTTP است. Action فقط validated/DTO می‌گیرد. Clean Code.

فرم و validation پروژه