wendelladriel/laravel-validated-dto
Build typed Data Transfer Objects for Laravel that validate incoming data using familiar validation rules, defaults, and casting. Create DTOs by extending ValidatedDTO, define rules(), and get safe, validated, ready-to-use properties for your app.
composer require wendelladriel/laravel-validated-dto and publish the config with php artisan vendor:publish --tag="validated-dto".ValidatedDTO and define rules(), defaults(), and casts() methods.
final class UserDTO extends ValidatedDTO {
public string $name;
public string $email;
protected function rules(): array { return ['name' => 'required|string', 'email' => 'required|email']; }
protected function defaults(): array { return []; }
protected function casts(): array { return []; }
}
UserDTO::fromArray(), UserDTO::fromRequest(), or inject into controllers.
$dto = UserDTO::fromArray(['name' => 'John', 'email' => 'john@example.com']);
Replace manual validation in controllers with DTOs. For example, replace:
$validated = request()->validate(['name' => 'required|string']);
with:
$dto = UserDTO::fromRequest(); // Automatically validates and casts
Request Handling:
public function store(UserDTO $dto) { /* $dto is validated */ }
fromRequest() for manual validation:
$dto = UserDTO::fromRequest();
Nested Data:
// Model
protected $casts = ['metadata' => MetadataDTO::class];
// DTO
final class MetadataDTO extends ValidatedDTO { ... }
Transformation:
$dto->toArray(); // ['name' => 'John', ...]
$dto->toModel(User::class); // User instance
Custom Logic:
buildDataForExport() for custom transformations:
public function toCustomFormat() {
return (object) $this->buildDataForExport();
}
toJson()/toPrettyJson() for consistent API responses.fromArray() or fromRequest().$dto = new UserDTO(['name' => 'Test']);
$this->assertEquals('Test', $dto->name);
Validation Rules:
sometimes for optional fields causes validation errors.['active' => 'sometimes|boolean'] for nullable booleans.Casting Issues:
CarbonCast with wrong date string) throw CastException.Default Values:
defaults() for optional fields with fallback values.Type Safety:
public int $age requires valid integers.ValidatedDTO::errors() for failed rules:
try {
$dto = UserDTO::fromArray(['email' => 'invalid']);
} catch (\Illuminate\Validation\ValidationException $e) {
dd($e->errors());
}
try-catch for CastException:
try {
$dto = UserDTO::fromArray(['date' => 'invalid']);
} catch (\WendellAdriel\ValidatedDTO\Exceptions\CastException $e) {
dd($e->getMessage());
}
BaseUserDTO).Castable for domain-specific types:
class CustomCast implements Castable { public function cast($value) { ... } }
/** @property string $name Required user name */
public string $name;
null values) in defaults().$this->assertNull((new UserDTO(['name' => null]))->name);
```markdown
### Extension Points
1. **Custom Transformers**:
- Override `toArray()`, `toJson()`, or `buildDataForExport()` for bespoke output.
2. **Validation Extensions**:
- Use Laravel’s validation rules (e.g., `Password`, `Unique`) in `rules()`.
3. **Event Handling**:
- Listen to `ValidatedDTO::validated` events for post-validation logic:
```php
ValidatedDTO::validated(fn (ValidatedDTO $dto) => Log::info('DTO validated', $dto->toArray()));
```
4. **Macros**:
- Add static methods to `ValidatedDTO` for project-wide utilities:
```php
ValidatedDTO::macro('sanitize', fn (array $data) => filter_var_array($data, FILTER_SANITIZE_STRING));
```
How can I help you explore Laravel packages today?