Sources
Every property is populated from a source — a part of the request. By default a property reads from the merged input bag (query string + body). Attributes bind it to a specific source instead.
Query and body
Use #[Query] or #[Body] to pin a property to one bag — handy when the same key can
appear in both:
use BYanelli\Roma\Request\Attributes\Body;
use BYanelli\Roma\Request\Attributes\Query;
readonly class SearchRequest {
#[Query]
public int $page; // always from the query string
#[Body]
public string $token; // always from the request body
}
The QUERY method
QUERY (RFC 10008) is a safe, idempotent
method that carries its input in the request content instead of the URI — "GET with a
body". Roma treats that content as the body, so #[Body] and the default input source
both read it, and #[Query] still means the query string:
use BYanelli\Roma\Request\Attributes\Query;
use BYanelli\Roma\Request\Enums\Method;
// QUERY /search?page=3 with {"term": "roma"}
readonly class SearchRequest {
public string $term; // from the QUERY body
#[Query]
public int $page; // from the query string
public Method $method; // Method::Query
}
Laravel's Route::any() predates the method, so register a QUERY route explicitly:
Route::match(['QUERY'], '/search', SearchController::class);
Route parameters
Bind to a route parameter with #[RouteParameter]. The property name is the parameter name
unless you pass an explicit one. Route parameters arrive as strings, so scalar and enum
coercion applies:
use BYanelli\Roma\Request\Attributes\RouteParameter;
// Route: /users/{id}/posts/{post_slug}
readonly class ShowPostRequest {
#[RouteParameter]
public int $id; // from {id}, coerced "42" -> 42
#[RouteParameter('post_slug')]
public string $slug; // from {post_slug}
}
If the request has no bound route, a required route parameter fails validation with a
route. error — it never crashes.
Cookies
Bind to a cookie with #[Cookie], using the property name or an explicit cookie name.
Cookie names may contain literal dots, so pass one explicitly when the name isn't a valid
PHP property name:
use BYanelli\Roma\Request\Attributes\Cookie;
readonly class PreferencesRequest {
#[Cookie]
public bool $darkMode; // from the "darkMode" cookie
#[Cookie('my.pref')]
public string $pref; // from the "my.pref" cookie
}
Files
Type-hint a property as Illuminate\Http\UploadedFile and the upload is mapped:
use Illuminate\Http\UploadedFile;
class FileRequest {
public UploadedFile $myFile;
}
File uploads must be declared on the top-level request class — a UploadedFile inside a
nested object is not supported and throws.
Type coercion and enums
Roma coerces string input to the property's declared type, and maps values onto string-backed, integer-backed, and unit enums automatically:
class OrderRequest {
public float $price; // "9.99" -> 9.99
public bool $isGift; // "true" -> true
public \DateTimeInterface $deliverBy; // "2024-01-01" -> DateTime
public Status $status; // "complete" -> Status::Complete (string enum)
/** @var array<int> */
public array $itemIds; // ["1","2"] -> [1, 2]
}