Configuration
RequestHandler Constructor
public function __construct(
ValidatorInterface $validator,
bool $autoTrim = true
)| Parameter | Type | Default | Description |
|---|---|---|---|
$validator | ValidatorInterface | required | Validator instance |
$autoTrim | bool | true | Auto-trim whitespace from string inputs |
Auto Trim
By default, all string inputs are trimmed before validation:
// Input: " John Doe " → Stored as: "John Doe"
#[Field(rules: 'required|string')]
public string $name;Disable globally:
$handler = new RequestHandler($validator, autoTrim: false);Or use preProcess for specific fields:
#[Field(preProcess: 'trim')]
public string $name;Dependency Injection
Register processor/generator instances with dependencies:
// Generator with database connection
class SequenceGenerator implements GeneratorInterface
{
public function __construct(
private readonly Connection $connection
) {}
public function generate(array $options = []): int
{
return $this->connection->getNextId($options['table']);
}
}
// Register the instance
$handler = new RequestHandler($validator);
$handler->register(
SequenceGenerator::class,
new SequenceGenerator($connection)
);The register() method returns $this for chaining:
$handler
->register(SequenceGenerator::class, new SequenceGenerator($db))
->register(SlugProcessor::class, new SlugProcessor($transliterator));handleQuery()
Create a Request DTO from query parameters (GET requests):
public function handleQuery(string $className, ServerRequestInterface $request, array $routeParams = []): RequestReads data from $request->getQueryParams().
$dto = $handler->handleQuery(SearchRequest::class, $request);handleBody()
Create a Request DTO from request body (POST/PUT/PATCH requests):
public function handleBody(string $className, ServerRequestInterface $request, array $routeParams = []): RequestReads data from $request->getParsedBody().
$dto = $handler->handleBody(CreateProductRequest::class, $request);handleArray()
Process raw data arrays without a PSR-7 request:
public function handleArray(string $className, array $data): RequestUseful for testing or manual processing:
$dto = $handler->handleArray(OrderItemRequest::class, [
'product' => 'Widget',
'quantity' => '3',
'price' => '9.99',
]);
$dto->product; // 'Widget'
$dto->quantity; // 3 (int - auto-casted)
$dto->price; // 9.99 (float - auto-casted)INFO
handleArray() runs the same pipeline as handleBody()/handleQuery() — validation, casting, pre/post-processing — but takes a plain array instead of ServerRequestInterface.
Route Parameters
Pass route parameters for placeholder replacement in validation rules:
class UpdateProductRequest extends Request
{
#[Field(rules: 'required|email|unique:users,email,{id}')]
public string $email;
}
// Usage
$dto = $handler->handleBody(
UpdateProductRequest::class,
$request,
['id' => 123] // Route params
);
// Rule becomes: 'required|email|unique:users,email,123'Multiple placeholders are supported:
#[Field(rules: 'unique:users,email,{userId},tenant_id,{tenantId}')]
public string $email;
// With routeParams: ['userId' => 42, 'tenantId' => 99]
// Rule becomes: 'unique:users,email,42,tenant_id,99'Handle Raw Arrays
Use handleArray() to create a Request DTO from a raw array instead of a PSR-7 request:
$dto = $handler->handleArray(OrderItemRequest::class, [
'product' => 'Widget',
'quantity' => '3',
'price' => '9.99',
]);
$dto->product; // 'Widget'
$dto->quantity; // 3 (int - auto-casted)This is useful for testing, CLI commands, or processing data from non-HTTP sources.
Request Base Class
All Request DTOs must extend Solo\RequestHandler\Request:
use Solo\RequestHandler\Request;
final class MyRequest extends Request
{
// Properties with #[Field] attributes
}The base class provides:
toArray()— Convert to array (excludes uninitialized and excluded fields)has(string $name)— Check if property is initializedget(string $name, mixed $default)— Get value with defaultgroup(string $name)— Get fields by group name