Form Requests
Form Requests are dedicated validation classes that validate and authorize incoming HTTP requests before they reach the controller. The CPR backend has 80+ Form Request classes organized by module.
Directory Structure
app/Http/Requests/
├── Auth/
│ ├── LoginRequest.php
│ └── ResetPasswordRequest.php
├── Patient/
│ ├── StorePatientDataRequest.php
│ └── UpdatePatientDateRequest.php
├── Transaction/
│ ├── StoreTransactionRequest.php
│ └── UpdateTransactionRequest.php
├── IndirectOphthalmoscopy/
│ ├── StoreIndirectOphthalmoscopyRequest.php
│ └── UpdateIndirectOphthalmoscopyRequest.php
├── Medicine/
│ ├── StoreMedicineRequest.php
│ └── UpdateMedicineRequest.php
├── Queue/
│ ├── StoreQueueTicketRequest.php
│ └── TransferQueueTicketRequest.php
└── ... (39+ modules, Store/Update variants each)Naming Convention
- Store requests:
Store{Resource}Request.php— used forPOST(create) - Update requests:
Update{Resource}Request.php— used forPUT/PATCH(update)
How They Work
Form Requests extend Illuminate\Foundation\Http\FormRequest and define:
authorize()— Whether the user is allowed to make this request (usuallytrue)rules()— Validation rules as an array
Laravel automatically validates the request before the controller method runs. If validation fails, a 422 response is returned with error details.
Examples
Simple CRUD Validation
php
class StoreMedicineRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
public function rules(): array
{
return [
'brand_name' => ['required', 'string', 'max:255'],
'generic_name' => ['required', 'string', 'max:255'],
'type' => ['required', new Enum(TypeEnum::class)],
'unit' => ['required', new Enum(UnitEnum::class)],
'status' => ['required', new Enum(StatusEnum::class)],
];
}
}Patient Validation (with Enums and File Upload)
php
class StorePatientDataRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
public function rules(): array
{
return [
'last_name' => ['required', 'string', 'max:255'],
'first_name' => ['required', 'string', 'max:255'],
'middle_name' => ['required', 'string', 'max:255'],
'birthdate' => ['required', 'date'],
'nationality' => ['required', 'string'],
'sex' => ['required', new Enum(PatientGenderEnum::class)],
'civil_status' => [new Enum(PatientCivilStatusEnum::class)],
'email' => ['nullable', 'email'],
'photo' => ['nullable', 'image', 'max:2048'],
'nick_name' => ['nullable', 'string'],
'occupation' => ['nullable', 'string'],
'telephone' => ['nullable', 'string'],
'mobile_phone' => ['nullable', 'string'],
// ... address fields, referral fields
];
}
}Transaction Validation (with Nested Items Array)
php
class StoreTransactionRequest extends FormRequest
{
public function rules(): array
{
return [
'patient_id' => ['nullable', 'exists:patients,id'],
'transaction_date' => ['required', 'date'],
'transaction_time' => ['required'],
'total_amount' => ['required', 'numeric', 'min:0'],
'payment_method_id' => ['required', 'exists:payment_methods,id'],
'status' => ['nullable', 'string', 'in:Completed,Pending,Cancelled'],
'notes' => ['nullable', 'string'],
'items' => ['required', 'array', 'min:1'],
'items.*.pharmacy_item_id' => ['nullable', 'exists:pharmacy_items,id'],
'items.*.name' => ['required', 'string', 'max:255'],
'items.*.quantity' => ['required', 'integer', 'min:1'],
'items.*.unit_price' => ['required', 'numeric', 'min:0'],
];
}
}Clinical Exam Validation (with Nested JSON Structure)
php
class StoreIndirectOphthalmoscopyRequest extends FormRequest
{
public function rules(): array
{
return [
'patient_visit_id' => ['required', 'exists:patient_visits,id'],
'shots' => ['nullable', 'array'],
'shots.*.date' => ['required_with:shots', 'date'],
'shots.*.shot' => ['required_with:shots', 'string'],
'remarks' => ['nullable', 'string'],
];
}
}Key Validation Patterns
| Pattern | Example | Used For |
|---|---|---|
| Enum validation | new Enum(StatusEnum::class) | Status, gender, eye, priority |
| Exists rule | 'exists:patients,id' | Foreign key references |
| Nested arrays | 'items.*.name' | Transaction items, exam shots |
| File validation | 'image', 'max:2048' | Patient photo upload |
| Conditional | 'required_with:shots' | Fields required when parent present |
| Sometimes | 'sometimes' | Update requests (partial updates) |
Store vs Update Differences
Update requests typically use sometimes to allow partial updates:
php
// StorePatientDataRequest
'last_name' => ['required', 'string', 'max:255'],
// UpdatePatientDateRequest
'last_name' => ['sometimes', 'required', 'string', 'max:255'],Usage in Controllers
Controllers type-hint the Form Request — Laravel runs validation automatically:
php
class PatientController extends Controller
{
public function store(StorePatientDataRequest $request)
{
// $request->validated() returns only validated data
$patient = $this->service->create($request->validated(), $branch);
return PatientResource::make($patient);
}
}Creating a New Form Request
bash
php artisan make:request {Module}/Store{Resource}Request
php artisan make:request {Module}/Update{Resource}RequestThen define authorize() and rules().