con un clic
laravel-validated-dto-development
// Guidance for generating, designing, and refactoring ValidatedDTO, SimpleDTO, and ResourceDTO classes in Laravel applications.
// Guidance for generating, designing, and refactoring ValidatedDTO, SimpleDTO, and ResourceDTO classes in Laravel applications.
| name | laravel-validated-dto-development |
| description | Guidance for generating, designing, and refactoring ValidatedDTO, SimpleDTO, and ResourceDTO classes in Laravel applications. |
| metadata | null |
Use this skill when working with wendelladriel/laravel-validated-dto: generating DTO classes, improving existing DTOs, applying attributes and casts, or replacing FormRequest validation with DTOs.
ValidatedDTO: use when incoming data must be validated before the DTO is considered ready.SimpleDTO: use when you want typed data, casts, mapping, and transforms without validation.ResourceDTO: use when the DTO is primarily an API response object and should be returned directly from controllers.Default to ValidatedDTO unless the code clearly does not need validation or is strictly response-only.
Use the package commands instead of hand-writing boilerplate first:
php artisan make:dto UserDTO
php artisan make:dto CheckoutInputDTO --simple
php artisan make:dto UserResourceDTO --resource
App\DTOs by default.config/dto.php via dto.namespace.php artisan dto:stubs
That creates customizable stubs in stubs/ for validated, simple, and resource DTOs.
nullable or optional rules when a property can legitimately become null.For generated DTOs, these are the main hooks:
rules(): validation rules for ValidatedDTO only.defaults(): fallback values when data is missing.casts(): property casting definitions.Add these only when needed:
messages(): custom validation messages.attributes(): human-friendly attribute names.mapData(): map external input keys before validation/assignment.mapToTransform(): map DTO keys before toArray(), toJson(), or toModel().Use attributes when rules, casts, defaults, or mapping are property-local and easy to read inline.
#[Rules([...], messages: [...])]: define validation rules per property.#[DefaultValue(...)]: define fallback values.#[Cast(Type::class, param: OtherType::class)]: define casts inline.#[Map(data: 'incoming_key', transform: 'outgoing_key')]: map input/output names.#[Receive(PropertyCase::SnakeCase)]: accept a naming convention for all incoming properties.#[Provide(PropertyCase::PascalCase)]: transform all outgoing properties to a naming convention.#[Lazy]: defer validation and casting until validate() is called.#[SkipOnTransform]: exclude a property from toArray(), toJson(), and toModel().If a DTO is fully attribute-driven, use these traits so the class can stay minimal:
EmptyRulesEmptyDefaultsEmptyCastsThis pattern is especially useful for attribute-heavy ValidatedDTO classes.
Use built-in casts whenever possible:
StringCast, IntegerCast, FloatCast, BooleanCastArrayCast, CollectionCast, ObjectCastCarbonCast, CarbonImmutableCastDTOCast, ModelCast, EnumCastStrong defaults:
DTOCast for nested DTO objects.CollectionCast(new DTOCast(...)) or ArrayCast(new DTOCast(...)) for nested lists.EnumCast for PHP enums instead of manual string handling.Castable implementation or callable cast when the transformation is project-specific.If config('dto.require_casting') is true, every DTO property must have a cast or instantiation will fail.
Use method-based mapping for complex or nested remapping, and attributes for simple one-property renames.
mapData(): input normalization before validation.mapToTransform(): output normalization before array/json/model export.#[Receive(...)] and #[Provide(...)]: bulk casing conversion for all properties.#[SkipOnTransform]: keep internal-only fields out of exported payloads.Use nested mapping when the external payload shape and the internal DTO shape intentionally differ.
DTOs can be created from several sources:
$dto = UserDTO::fromArray($data);
$dto = UserDTO::fromJson($json);
$dto = UserDTO::fromRequest($request);
$dto = UserDTO::fromModel($user);
$dto = UserDTO::fromCommandArguments($this);
$dto = UserDTO::fromCommandOptions($this);
$dto = UserDTO::fromCommand($this);
For controllers in Laravel, prefer type-hinting the DTO directly when the package is already wired into the app:
public function store(UserDTO $dto)
{
// ...
}
When a DTO is filled progressively, prefer lazy validation:
public bool $lazyValidation = true, or#[Lazy] to the DTO class.Call $dto->validate() when the DTO is ready.
For Livewire integration, use the Wireable trait so the DTO can move between Livewire and PHP safely.
When asked to convert a FormRequest into a DTO, use this migration approach:
ValidatedDTO with public typed properties matching the validated payload.rules() from the FormRequest into the DTO.messages() and attributes() if the request defines them.prepareForValidation() style key normalization into mapData() or #[Map(...)] when possible.mapToTransform() or #[Map(transform: ...)] when needed.store(StoreUserRequest $request) with store(StoreUserDTO $dto) when the app is using DTO auto-resolution.$request->validated() with DTO properties.Important differences from FormRequest:
When creating or updating a DTO, verify that:
DTOCast, CollectionCast, or ArrayCast correctlyResourceDTO only for response objects.