در مقاله قبلی با Validation در Laravel آشنا شدیم و یاد گرفتیم چگونه دادههای دریافتشده از Request را قبل از پردازش بررسی کنیم.
برای پروژههای کوچک، میتوان Validation را مستقیماً داخل Controller نوشت:
$request->validate([
'name' => ['required', 'string'],
'email' => ['required', 'email'],
]);
اما هرچه پروژه بزرگتر شود، تعداد فرمها، قوانین اعتبارسنجی و شرایط مختلف بیشتر میشود.
در چنین شرایطی اگر تمام Validationها را داخل Controller قرار دهیم، Controller بهتدریج شلوغ و نگهداری آن سخت میشود.
Laravel برای حل این مشکل قابلیتی به نام Form Request در اختیار ما قرار میدهد.
Form Request به ما اجازه میدهد منطق مربوط به Validation و Authorization یک Request را در یک کلاس جداگانه قرار دهیم.
در این مقاله یاد میگیریم:
- Form Request چیست؟
- چرا باید از آن استفاده کنیم؟
- چگونه Form Request بسازیم؟
rules()چیست؟authorize()چیست؟- چگونه Validation را به Form Request منتقل کنیم؟
- چگونه پیام خطا را شخصیسازی کنیم؟
- چگونه دادههای Validationشده را دریافت کنیم؟
- چگونه برای Create و Update Form Request جدا بسازیم؟
- چه زمانی Form Request بهتر از Validation مستقیم داخل Controller است؟
# Form Request در Laravel چیست؟
Form Request یک کلاس اختصاصی Laravel است که برای مدیریت Validation و Authorization مربوط به یک Request استفاده میشود.
بهجای اینکه تمام قوانین Validation را داخل Controller بنویسیم، میتوانیم یک کلاس جدا ایجاد کنیم.
مثلاً:
StoreProductRequest
این کلاس میتواند قوانین Validation مربوط به ایجاد محصول را در خود نگه دارد.
در نتیجه Controller به شکل سادهتری درمیآید:
public function store(StoreProductRequest $request)
{
// پردازش محصول
}
در اینجا قبل از رسیدن Request به متد store، Laravel Form Request را پردازش میکند.
# چرا از Form Request استفاده کنیم؟
فرض کنید یک Controller داریم که چندین متد مختلف دارد:
public function store(...)
{
// validation
}
public function update(...)
{
// validation
}
public function profile(...)
{
// validation
}
اگر قوانین Validation زیادی داشته باشیم، Controller بهسرعت بزرگ میشود.
با Form Request میتوانیم Validation هر عملیات را در کلاس مخصوص خودش قرار دهیم:
StoreProductRequest
UpdateProductRequest
UpdateProfileRequest
RegisterUserRequest
ChangePasswordRequest
در این حالت ساختار پروژه خواناتر میشود.
# مزایای Form Request در Laravel
استفاده از Form Request مزایای مختلفی دارد.
جدا شدن Validation از Controller
Controller بیشتر روی اجرای جریان عملیات تمرکز میکند.
خوانایی بهتر
وقتی قوانین Validation در یک کلاس جدا باشند، پیدا کردن و تغییر آنها سادهتر است.
استفاده مجدد
یک Form Request را میتوان در محلهای مناسب دوباره استفاده کرد.
مدیریت Authorization
Form Request فقط برای Validation نیست و میتواند مشخص کند کاربر اجازه انجام آن Request را دارد یا خیر.
مناسب برای پروژههای بزرگ
در پروژههای متوسط و بزرگ، جدا کردن مسئولیتها باعث نگهداری بهتر کد میشود.
# ساخت Form Request در Laravel
برای ساخت Form Request میتوانیم از Artisan استفاده کنیم:
php artisan make:request StoreProductRequest
Laravel کلاس مربوط به Request را ایجاد میکند.
معمولاً این فایل در مسیر زیر قرار میگیرد:
app/Http/Requests/StoreProductRequest.php
ساختار اولیه کلاس مشابه این خواهد بود:
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class StoreProductRequest extends FormRequest
{
public function authorize(): bool
{
return false;
}
public function rules(): array
{
return [
//
];
}
}
دو متد مهم این کلاس عبارتاند از:
authorize()
و:
rules()
# متد rules() در Form Request چیست؟
مهمترین قسمت Form Request معمولاً متد rules() است.
قوانین Validation را در این متد قرار میدهیم.
مثلاً:
public function rules(): array
{
return [
'name' => ['required', 'string', 'max:255'],
'email' => ['required', 'email'],
];
}
حالا هر Request که از این Form Request استفاده کند، این قوانین را خواهد داشت.
# متد authorize() چیست؟
متد authorize() مشخص میکند آیا کاربر اجازه انجام این Request را دارد یا خیر.
مثلاً:
public function authorize(): bool
{
return true;
}
در این حالت اجازه عبور Request داده میشود.
اگر:
public function authorize(): bool
{
return false;
}
باشد، Request مجاز نخواهد بود.
نکته مهم این است که authorize() با Validation تفاوت دارد.
Validation بررسی میکند:
> آیا دادهها معتبر هستند؟
Authorization بررسی میکند:
> آیا این کاربر اجازه انجام این عملیات را دارد؟
# سادهترین Form Request
مثلاً:
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class StoreProductRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
public function rules(): array
{
return [
'name' => ['required', 'string', 'max:255'],
'price' => ['required', 'numeric'],
];
}
}
در این مثال:
- Request مجاز است.
nameالزامی است.nameباید رشته باشد.- طول
nameمحدود شده است. priceالزامی است.priceباید عددی باشد.
# استفاده از Form Request در Controller
حالا باید Form Request را به Controller معرفی کنیم.
use App\Http\Requests\StoreProductRequest;
سپس:
public function store(StoreProductRequest $request)
{
//
}
دیگر نیازی نیست در این Controller بنویسیم:
$request->validate([
//
]);
Laravel خودش Form Request را قبل از اجرای متد پردازش میکند.
# یک مثال کامل از Form Request
فرض کنید میخواهیم محصول ایجاد کنیم.
قوانین:
- نام الزامی
- نام رشته
- حداکثر ۲۵۵ کاراکتر
- قیمت الزامی
- قیمت عددی
- دستهبندی الزامی
- دستهبندی باید وجود داشته باشد
Form Request:
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class StoreProductRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
public function rules(): array
{
return [
'name' => [
'required',
'string',
'max:255',
],
'price' => [
'required',
'numeric',
],
'category_id' => [
'required',
'exists:categories,id',
],
];
}
}
Controller:
use App\Http\Requests\StoreProductRequest;
public function store(StoreProductRequest $request)
{
$data = $request->validated();
// ایجاد محصول
return redirect()
->route('products.index');
}
در اینجا Controller بسیار سادهتر از حالتی است که تمام Validation را داخل آن نوشته باشیم.
# متد validated() چیست؟
یکی از قابلیتهای مهم Form Request، متد:
$request->validated()
است.
این متد دادههایی را در اختیار ما قرار میدهد که از Validation عبور کردهاند.
مثلاً:
$data = $request->validated();
سپس:
$data['name'];
یا:
$data['price'];
در دسترس خواهند بود.
این روش معمولاً بهتر از کار کردن با تمام دادههای خام Request است، چون مشخص است داده مورد استفاده قبلاً از قوانین Validation عبور کرده است.
# تفاوت validated() و all()
فرض کنید Request شامل این دادهها باشد:
name
price
category_id
is_admin
اگر بنویسیم:
$request->all();
تمام دادههای موجود Request را دریافت میکنیم.
اما:
$request->validated();
دادههایی را برمیگرداند که در فرآیند Validation مورد تأیید قرار گرفتهاند.
به همین دلیل برای منطق اصلی برنامه معمولاً استفاده از دادههای Validationشده انتخاب مناسبتری است.
# دریافت یک مقدار Validationشده
میتوانیم بهجای دریافت تمام دادهها، فقط بخشی از آنها را استفاده کنیم.
مثلاً:
$data = $request->validated();
$name = $data['name'];
یا در صورت نیاز میتوانیم ساختار دادههای معتبر را متناسب با منطق برنامه پردازش کنیم.
# شخصیسازی پیامهای Validation در Form Request
میتوانیم پیامهای Validation را مستقیماً داخل Form Request تعریف کنیم.
برای این کار متد:
messages()
را اضافه میکنیم.
مثلاً:
public function messages(): array
{
return [
'name.required' => 'وارد کردن نام محصول الزامی است.',
'name.max' => 'نام محصول نباید بیشتر از ۲۵۵ کاراکتر باشد.',
'price.required' => 'وارد کردن قیمت الزامی است.',
'price.numeric' => 'قیمت باید عددی باشد.',
];
}
در این حالت Controller نیازی به نگهداری پیامهای Validation ندارد.
# شخصیسازی نام Attributeها
برای نمایش پیامهای طبیعیتر میتوان نام فیلدها را نیز مشخص کرد.
مثلاً:
public function attributes(): array
{
return [
'name' => 'نام محصول',
'price' => 'قیمت',
'category_id' => 'دستهبندی',
];
}
این موضوع بهخصوص برای پروژههای فارسی بسیار کاربردی است.
# Form Request و authorize()
یکی از مهمترین قابلیتهای Form Request امکان بررسی مجوز کاربر است.
مثلاً فرض کنید فقط مدیر اجازه ایجاد محصول دارد.
میتوانیم منطق Authorization را در:
authorize()
قرار دهیم.
برای مثال اگر سیستم احراز هویت پروژه چنین قابلیتی داشته باشد:
public function authorize(): bool
{
return $this->user()?->is_admin === true;
}
در این حالت فقط کاربری که شرایط موردنظر را داشته باشد مجاز خواهد بود.
البته در پروژههای بزرگ، منطق Authorization ممکن است به Policy یا ساختارهای تخصصیتر منتقل شود.
# تفاوت Validation و Authorization در Form Request
این دو مفهوم را نباید با یکدیگر اشتباه بگیریم.
Validation
بررسی میکند:
آیا داده صحیح است؟
مثلاً:
'email' => ['required', 'email']
Authorization
بررسی میکند:
آیا این کاربر اجازه انجام این عملیات را دارد؟
مثلاً:
public function authorize(): bool
{
return $this->user()?->is_admin === true;
}
پس:
Validation = اعتبار داده
Authorization = مجوز عملیات
# Form Request برای ثبتنام کاربر
فرض کنید یک فرم ثبتنام داریم.
میتوانیم Request زیر را ایجاد کنیم:
php artisan make:request RegisterUserRequest
سپس:
class RegisterUserRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
public function rules(): array
{
return [
'name' => [
'required',
'string',
'max:255',
],
'email' => [
'required',
'email',
'unique:users,email',
],
'password' => [
'required',
'string',
'min:8',
'confirmed',
],
];
}
}
Controller:
public function register(RegisterUserRequest $request)
{
$data = $request->validated();
// ایجاد کاربر
return redirect()
->route('login');
}
Controller اکنون مسئول Validation نیست و میتواند روی عملیات ثبتنام تمرکز کند.
# Form Request برای Update
در پروژههای واقعی معمولاً Validation مربوط به Create و Update دقیقاً یکسان نیست.
مثلاً:
StoreProductRequest
UpdateProductRequest
میتوانیم برای هرکدام Request جداگانه ایجاد کنیم:
php artisan make:request StoreProductRequest
و:
php artisan make:request UpdateProductRequest
این کار باعث میشود قوانین هر عملیات کاملاً مشخص باشند.
# چرا Create و Update میتوانند Validation متفاوتی داشته باشند؟
فرض کنید هنگام ایجاد محصول، name و slug الزامی هستند.
اما هنگام ویرایش ممکن است کاربر فقط قیمت را تغییر دهد.
یا مثلاً در زمان ایجاد محصول:
'name' => [
'required',
'string',
]
ولی در Update:
'name' => [
'sometimes',
'string',
]
در نتیجه جدا کردن Form Requestها میتواند ساختار پروژه را بسیار واضحتر کند.
# استفاده از Route Parameter در Form Request
یکی از قابلیتهای کاربردی Form Request این است که میتوان به اطلاعات Route نیز دسترسی داشت.
مثلاً Route:
Route::put('/products/{product}', ...);
در Form Request میتوان به پارامتر Route دسترسی داشت:
$this->route('product');
این قابلیت مخصوصاً هنگام Update بسیار کاربردی است.
مثلاً برای Validation یک مقدار Unique، ممکن است لازم باشد رکورد فعلی را از بررسی Unique مستثنی کنیم.
# Form Request برای Validation پیچیده
یکی از مهمترین مزایای Form Request زمانی مشخص میشود که قوانین زیاد باشند.
مثلاً:
public function rules(): array
{
return [
'name' => [
'required',
'string',
'max:255',
],
'email' => [
'required',
'email',
],
'phone' => [
'nullable',
'string',
],
'price' => [
'required',
'numeric',
],
'category_id' => [
'required',
'exists:categories,id',
],
'image' => [
'nullable',
'image',
],
];
}
اگر چنین Validationی را داخل چندین Controller قرار دهیم، مدیریت آن سختتر میشود.
Form Request این مسئولیت را از Controller جدا میکند.
# استفاده از prepareForValidation()
در بعضی سناریوها لازم است قبل از اجرای Validation دادههای Request را آماده کنیم.
Form Request میتواند متدی به نام:
prepareForValidation()
داشته باشد.
مثلاً:
protected function prepareForValidation(): void
{
$this->merge([
'slug' => strtolower($this->slug),
]);
}
در این حالت قبل از Validation، مقدار موردنظر آماده میشود.
این قابلیت برای Normalize کردن دادهها در سناریوهای مناسب کاربرد دارد.
# استفاده از passedValidation()
گاهی لازم است بعد از موفقیت Validation کاری انجام دهیم.
برای چنین سناریوهایی میتوان از:
passedValidation()
استفاده کرد.
مثلاً:
protected function passedValidation(): void
{
//
}
این قابلیت برای پردازشهای خاص کاربرد دارد، اما بهتر است منطق کسبوکار سنگین را در Form Request قرار ندهیم.
Form Request بهتر است عمدتاً مسئول Validation و Authorization مرتبط با Request باشد.
# Form Request و Controller؛ مسئولیت هرکدام چیست؟
یکی از اهداف اصلی Form Request این است که مسئولیتها را جدا کنیم.
Form Request
مسئول:
- Validation
- Authorization مرتبط با Request
- آمادهسازی داده برای Validation در صورت نیاز
- پیامهای Validation
Controller
مسئول:
- دریافت Request معتبر
- اجرای جریان عملیات
- فراخوانی Service یا Model
- برگرداندن Response
مثلاً:
Form Request
↓
Validation
↓
Controller
↓
Service
↓
Model
↓
Response
این ساختار در پروژههای بزرگ بسیار قابلمدیریتتر است.
# Form Request و Service Layer
در پروژههای بزرگ ممکن است حتی Controller نیز بسیار بزرگ شود.
در چنین شرایطی میتوان منطق کسبوکار را به Service منتقل کرد.
مثلاً:
public function store(StoreProductRequest $request)
{
$data = $request->validated();
$product = $this->productService->create($data);
return redirect()
->route('products.index');
}
در این ساختار:
Form Request
↓
Validation
↓
Controller
↓
Service
↓
Database
هر لایه وظیفه مشخصی دارد.
# اشتباهات رایج در استفاده از Form Request
۱. فراموش کردن authorize()
وقتی Form Request ایجاد میکنید، باید به authorize() توجه کنید.
مثلاً:
public function authorize(): bool
{
return false;
}
اگر این مقدار بدون توجه باقی بماند، Request مجاز نخواهد بود.
برای Requestهایی که فعلاً Authorization خاصی ندارند، معمولاً:
public function authorize(): bool
{
return true;
}
قرار داده میشود.
۲. قرار دادن منطق کسبوکار در Form Request
Form Request جای مناسبی برای منطق پیچیده کسبوکار نیست.
مثلاً بهتر است عملیات پرداخت، ایجاد سفارش یا محاسبه کمیسیون را داخل Form Request قرار ندهیم.
Form Request باید بیشتر روی Validation و Authorization مرتبط با Request تمرکز کند.
۳. استفاده از Request خام بهجای validated()
اگر Validation انجام دادهایم، بهتر است در منطق اصلی برنامه از دادههای معتبر استفاده کنیم:
$data = $request->validated();
بهجای اینکه دوباره تمام دادههای خام Request را در اختیار منطق برنامه قرار دهیم.
۴. ساخت یک Form Request بسیار بزرگ
اگر یک Form Request صدها Rule برای عملیاتهای مختلف داشته باشد، احتمالاً بهتر است آن را به چند Request تخصصی تقسیم کنیم.
مثلاً:
StoreProductRequest
UpdateProductRequest
BulkUpdateProductRequest
ImportProductRequest
# Form Request برای API
Form Request فقط مخصوص فرمهای HTML نیست.
در API نیز میتوان از آن استفاده کرد.
مثلاً:
Route::post('/api/products', [
ProductController::class,
'store'
]);
Controller:
public function store(StoreProductRequest $request)
{
$data = $request->validated();
return response()->json([
'success' => true,
'data' => $data,
]);
}
در نتیجه همان Validation میتواند در جریان API نیز استفاده شود.
# Form Request و پاسخ خطا
اگر Validation شکست بخورد، Laravel بر اساس نوع Request رفتار مناسب را انجام میدهد.
در فرمهای وب معمولاً کاربر به مسیر قبلی برگردانده میشود و خطاها در اختیار View قرار میگیرند.
در درخواستهای API، Laravel میتواند Response خطای مناسب برای Client ایجاد کند.
بنابراین Form Request باعث نمیشود مجبور باشیم تمام مدیریت خطا را از صفر پیادهسازی کنیم.
# چه زمانی از validate() و چه زمانی از Form Request استفاده کنیم؟
برای پروژههای کوچک ممکن است این روش کاملاً مناسب باشد:
$request->validate([
'name' => ['required'],
]);
اما اگر:
- Validation طولانی است.
- Controller بزرگ شده است.
- چندین فرم دارید.
- Create و Update قوانین متفاوت دارند.
- Authorization مرتبط با Request دارید.
- APIهای متعددی دارید.
- پروژه قرار است در آینده توسعه پیدا کند.
استفاده از Form Request انتخاب ساختاریافتهتری است.
بهصورت ساده:
| شرایط | روش مناسب |
|---|---|
| Validation بسیار ساده | $request->validate() |
| Validation چند فیلدی | هر دو روش ممکن است |
| Controller بزرگ | Form Request |
| فرم پیچیده | Form Request |
| Create و Update متفاوت | Form Request جداگانه |
| Authorization مرتبط با Request | Form Request |
| پروژه بزرگ | Form Request |
# یک ساختار پیشنهادی برای پروژه Laravel
فرض کنید یک فروشگاه اینترنتی داریم.
میتوانیم ساختار Requestهای پروژه را به شکل زیر طراحی کنیم:
app/
└── Http/
└── Requests/
├── Auth/
│ ├── LoginRequest.php
│ └── RegisterRequest.php
│
├── Product/
│ ├── StoreProductRequest.php
│ └── UpdateProductRequest.php
│
├── Order/
│ └── StoreOrderRequest.php
│
└── User/
└── UpdateProfileRequest.php
این ساختار باعث میشود پیدا کردن Validationهای پروژه سادهتر شود.
البته سازماندهی دقیق پوشهها به اندازه و معماری پروژه بستگی دارد.
# مثال نهایی؛ ایجاد محصول با Form Request
فرض کنیم Form Request ما:
class StoreProductRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
public function rules(): array
{
return [
'name' => [
'required',
'string',
'max:255',
],
'price' => [
'required',
'numeric',
],
'category_id' => [
'required',
'exists:categories,id',
],
];
}
public function messages(): array
{
return [
'name.required' => 'نام محصول الزامی است.',
'price.required' => 'قیمت محصول الزامی است.',
'category_id.required' => 'انتخاب دستهبندی الزامی است.',
];
}
}
Controller:
use App\Http\Requests\StoreProductRequest;
public function store(StoreProductRequest $request)
{
$data = $request->validated();
$product = Product::create($data);
return redirect()
->route('products.index')
->with('success', 'محصول با موفقیت ایجاد شد.');
}
حالا مسئولیتها کاملاً مشخص هستند:
StoreProductRequest
↓
Validation
↓
Controller
↓
Product
↓
Database
↓
Redirect Response
این دقیقاً همان نوع تفکیک مسئولیت است که در پروژههای Laravel بزرگ اهمیت زیادی پیدا میکند.
# جمعبندی
Form Request یکی از ابزارهای مهم Laravel برای ساختارمند کردن Validation و Authorization درخواستها است.
در پروژههای کوچک میتوان Validation را مستقیماً با:
$request->validate()
انجام داد.
اما وقتی پروژه بزرگتر میشود، بهتر است Validationهای مهم را به کلاسهای جداگانه منتقل کنیم.
برای ساخت Form Request میتوان از Artisan استفاده کرد:
php artisan make:request StoreProductRequest
سپس قوانین Validation را داخل:
rules()
و منطق Authorization مرتبط با Request را داخل:
authorize()
قرار میدهیم.
همچنین برای دریافت دادههای تأییدشده میتوان از:
$request->validated()
استفاده کرد.
مزیت اصلی این ساختار این است که Controller از جزئیات Validation جدا میشود و کد پروژه خواناتر، منظمتر و قابل نگهداریتر خواهد بود.
با یادگیری Form Request، حالا مسیر ما از:
Request
↓
Validation
↓
Form Request
به مفاهیم مهم دیگری مانند Session، Cookie، Database و Eloquent ادامه پیدا میکند.
# سوالات متداول
Form Request در Laravel چیست؟
Form Request یک کلاس Laravel برای مدیریت Validation و Authorization مرتبط با یک Request است.
چگونه Form Request بسازیم؟
با Artisan:
php artisan make:request StoreProductRequest
rules() در Form Request چه کاری انجام میدهد؟
قوانین Validation مربوط به Request در متد rules() تعریف میشوند.
authorize() در Form Request چیست؟
این متد مشخص میکند آیا Request از نظر مجوز دسترسی اجازه ادامه پردازش دارد یا خیر.
validated() در Laravel چیست؟
متد validated() دادههایی را در اختیار برنامه قرار میدهد که از قوانین Validation عبور کردهاند.
آیا Form Request فقط برای فرمهای HTML است؟
خیر. میتوان از Form Request برای APIها و انواع دیگر HTTP Request نیز استفاده کرد.
آیا باید برای هر فرم یک Form Request بسازیم؟
الزاماً نه. بهتر است بر اساس مسئولیت و تفاوت قوانین Validation تصمیم بگیریم. فرمهای پیچیده یا عملیاتهایی با قوانین متفاوت معمولاً Form Requestهای جداگانه میخواهند.
آیا Form Request جای Controller را میگیرد؟
خیر. Form Request بیشتر مسئول Validation و Authorization مرتبط با Request است؛ Controller همچنان جریان اصلی عملیات را مدیریت میکند.
تفاوت Form Request و Middleware چیست؟
Middleware معمولاً قبل یا اطراف اجرای Request برای کنترلهایی مانند Authentication، بررسی دسترسی عمومی، محدودسازی درخواست و موارد مشابه استفاده میشود؛ Form Request بیشتر روی Validation و Authorization همان Request تمرکز دارد.





