Skip to content

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 for POST (create)
  • Update requests: Update{Resource}Request.php — used for PUT/PATCH (update)

How They Work

Form Requests extend Illuminate\Foundation\Http\FormRequest and define:

  1. authorize() — Whether the user is allowed to make this request (usually true)
  2. 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

PatternExampleUsed For
Enum validationnew 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}Request

Then define authorize() and rules().

CPR - Clinical Patient Records