Roma is a Request Object MApper. It has its own implementation of an object mapper designed to map all aspects of Laravel's Illuminate\Http\Request request to a fully type-safe and validated POPO (plain old PHP object). That includes headers, the query string, the body, files, and convenience methods of the request object (e.g., $request->ajax()). The goal is that when using a custom Roma request, you should never have to interact with the underlying Laravel request directly.
Creating a request object is as simple as adding all the properties you want to populate from the request. Validation rules can be added using the #[Rule] attribute:
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;
) {
// Constructor promoted properties and class properties can be used interchangeably.
#[Rule('phone')]
public string $phone;
}Simply inject the request object using the contextual binding attribute:
use BYanelli\Roma\Request\ContextualBinding\Request;
use App\Models\Contact;
class CreateContactController {
public function __invoke(
#[Request] CreateContactRequest $request,
) {
Contact::create([
'name' => $request->name,
'email' => $request->email,
'phone' => $request->phone,
]);
}
}Map specific headers to properties using the #[Header] attribute, or take advantage of pre-made ones like #[ContentType] (a shortcut for #[Header('Content-Type')]):
use BYanelli\Roma\Request\Attributes\Header;
use BYanelli\Roma\Request\Attributes\Headers\ContentType;
readonly class ApiRequest {
#[Header('X-API-Key')]
public string $apiKey;
#[ContentType]
public string $contentType;
}Access (and optionally validate) request metadata:
use BYanelli\Roma\Request\Attributes\Accessors\Ajax;
use BYanelli\Roma\Request\Attributes\Accessors\Method;
readonly class MetadataRequest {
#[Ajax(mustBe: true)] // Requires AJAX request
public bool $isAjax;
#[Method]
public string $method; // GET, POST, etc.
}Roma automatically maps values to string-backed, integer-backed, and unit enums:
enum Status: string {
case NotStarted = 'not_started';
case InProgress = 'in_progress';
case Complete = 'complete';
}
enum Priority: int {
case Low = 1;
case Medium = 2;
case High = 3;
}
enum Department {
case CustomerService;
case Sales;
}
class UpdateTaskRequest {
public Status $status;
public Priority $priority;
public Department $department;
}Type-hint any property with Illuminate\Http\UploadedFile and it will be mapped.
use Illuminate\Http\UploadedFile;
class FileRequest {
public UploadedFile $myFile;
}Type-hint your properties to other POPOs to deserialize complex nested structures from JSON payloads:
class Address {
public string $address;
public string $city;
public State $state;
public string $zipCode;
public Country $country;
}
class UserRequest {
public string $name;
public string $email;
public Address $address;
}Share common properties across multiple request classes using traits:
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;
public ?Category $category;
}Roma handles automatic type conversion for common types:
class OrderRequest {
public float $price; // "9.99" β 9.99
public bool $isGift; // "true" β true
public \DateTimeInterface $deliveryDate; // "2024-01-01" β DateTime object
/** @var array<int> */
public array $itemIds; // ["1", "2", "3"] β [1, 2, 3]
}Apply validation rules at the class level to enforce global requirements:
use BYanelli\Roma\Request\Attributes\Accessors\Ajax;
use BYanelli\Roma\Request\Attributes\Headers\ContentType;
#[Ajax] // Requires all requests mapped to this class to be AJAX
#[ContentType(ContentType::APPLICATION_JSON)] // Requires JSON content type
class ApiOnlyRequest {
public string $data;
}- Wrap remaining metadata from Illuminate Request class
- Type-safe responses! We want this to be a Request/Response Object MApper