Request objects

A request object is a class whose typed properties you want populated from the request. Constructor-promoted properties and plain class properties can be used interchangeably.

use BYanelli\Roma\Request\Attributes\Rule;

readonly class CreateContactRequest {
    public function __construct(
        #[Rule('max:255')]
        public string $name,

        #[Rule(['email', 'unique:contacts', 'max:255'])]
        public string $email,
    ) {}

    #[Rule('phone')]
    public string $phone;
}

Inject it into your controller

Mark the request class with #[Request] and type-hint it in your controller. Roma resolves it from the container, maps the request onto it, and validates it before your action runs:

use BYanelli\Roma\Request\ContextualBinding\Request;

#[Request]
readonly class CreateContactRequest { /* properties as above */ }

class CreateContactController {
    public function __invoke(CreateContactRequest $request) {
        Contact::create([
            'name'  => $request->name,
            'email' => $request->email,
            'phone' => $request->phone,
        ]);
    }
}

Marking the class is also what lets the TypeScript generator auto-detect it as a request. Auto-injection is on by default; to require an explicit attribute everywhere, set auto_inject to false in config/roma.php.

Annotating the parameter instead

#[Request] also works on the controller parameter rather than the class. Both forms work and can coexist — reach for the parameter attribute when auto-injection is off, or for a one-off request you'd rather not mark at the class level:

use BYanelli\Roma\Request\ContextualBinding\Request;

class CreateContactController {
    public function __invoke(#[Request] CreateContactRequest $request) {
        // ...
    }
}

Share properties with traits

Common properties can be factored into a trait and mixed into any request:

use BYanelli\Roma\Request\Attributes\Rule;

trait HasPagination {
    #[Rule('integer|min:1')]
    public int $page = 1;

    #[Rule('integer|min:1|max:100')]
    public int $perPage = 15;
}

class ProductListRequest {
    use HasPagination;

    public ?string $search;
}