Installation
composer require azjezz/input-hydrator
Add to composer.json under autoload-dev if using for testing:
"autoload-dev": {
"psr-4": {
"Azjezz\\InputHydrator\\": "vendor/azjezz/input-hydrator/src/"
}
}
Basic Usage
Define a DTO class (e.g., CreateUserRequest):
namespace App\DTO;
use Azjezz\InputHydrator\Hydratable;
class CreateUserRequest implements Hydratable
{
public string $name;
public string $email;
public int $age;
}
First Hydration In a controller or service:
use Azjezz\InputHydrator\Hydrator;
$hydrator = new Hydrator();
$dto = $hydrator->hydrate(CreateUserRequest::class, $request->all());
Request Validation + Hydration Combine with Laravel's validation:
$validated = $request->validate([
'name' => 'required|string',
'email' => 'required|email',
'age' => 'nullable|integer|min:18',
]);
$dto = $hydrator->hydrate(CreateUserRequest::class, $validated);
Nested DTOs Support hierarchical data:
class UserWithAddressRequest implements Hydratable
{
public CreateUserRequest $user;
public AddressRequest $address;
}
Service Layer Integration Use in services to decouple request handling:
class UserService {
public function create(UserRegistrationRequest $request) {
// Business logic using $request properties
}
}
Form Requests
Extend Laravel's FormRequest for type safety:
use Azjezz\InputHydrator\Hydratable;
class StoreUserRequest extends FormRequest implements Hydratable {
public CreateUserRequest $dto;
}
Hydrator as a singleton:
$this->app->singleton(Hydrator::class, function ($app) {
return new Hydrator();
});
Hydrator into controllers/services:
public function __construct(private Hydrator $hydrator) {}
Hydratable for custom logic:
class CustomRequest implements Hydratable {
public function hydrate(array $data): void {
$data['processed'] = strtoupper($data['name']);
parent::hydrate($data);
}
}
Property Visibility
Only public properties are hydrated by default. Use:
$hydrator->hydrate(CreateUserRequest::class, $data, ['privateProperties' => true]);
Or add #[Hydrate] attribute (if supported in newer versions).
Type Mismatches Silent failures occur if input types don’t match DTO properties. Validate first:
$request->validate([
'age' => 'integer',
]);
Circular References
Avoid recursive DTO structures (e.g., User → Address → User). Use #[Hydrate(ignore: true)] or flatten data.
Null Handling
Undefined array keys default to null. Explicitly set defaults:
class UserRequest {
public ?string $bio = null; // Explicit nullability
}
$hydrator->setStrict(true); // Throws exceptions on missing properties
getHydratedData() to debug:
$hydrator->hydrate(CreateUserRequest::class, $data);
dd($hydrator->getHydratedData());
Custom Hydrators
Implement Azjezz\InputHydrator\HydratorInterface for custom logic:
class CustomHydrator implements HydratorInterface {
public function hydrate(string $class, array $data, array $options = []): object {
// Custom logic
}
}
Post-Hydration Processing
Use hydrated event (if supported) or a decorator:
$hydrator->afterHydrate(function ($dto) {
if ($dto instanceof CreateUserRequest) {
$dto->email = strtolower($dto->email);
}
});
Configuration Override defaults via constructor:
$hydrator = new Hydrator([
'ignore_missing' => false,
'allow_extra' => true,
]);
#[Attribute] (PHP 8+).How can I help you explore Laravel packages today?