Skip to main content

laravel-validated-dto-development

Guidance for generating, designing, and refactoring ValidatedDTO, SimpleDTO, and ResourceDTO classes in Laravel applications.

Aller à l'installation

Informations de source

Dépôt
WendellAdriel/laravel-validated-dto
Dernière activité de la source
11 mars 2026 à 11:24
Langue détectée de SKILL.md
anglais
Étoiles
775
Forks
46

Options d'installation

Le prompt qui vérifie d'abord la source est sélectionné par défaut. Vous pouvez passer à une commande directe ou télécharger une copie locale.

Vérifiez les fichiers source

Lisez SKILL.md et les fichiers associés affichés par SkillsMP avant de décider de l'installer.

Affichage de SKILL.md

SKILL.md
Instructions source · Aperçu en lecture seule
name
laravel-validated-dto-development
description
Guidance for generating, designing, and refactoring ValidatedDTO, SimpleDTO, and ResourceDTO classes in Laravel applications.
metadata
null
# Laravel Validated DTO 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. ## Choose the right DTO type - `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. ## Generate DTOs with commands Use the package commands instead of hand-writing boilerplate first: ```bash php artisan make:dto UserDTO php artisan make:dto CheckoutInputDTO --simple php artisan make:dto UserResourceDTO --resource ``` - Generated classes go to `App\DTOs` by default. - The namespace comes from `config/dto.php` via `dto.namespace`. - If the project needs custom templates, publish the stubs first: ```bash php artisan dto:stubs ``` That creates customizable stubs in `stubs/` for validated, simple, and resource DTOs. ## Authoring high-quality DTOs ### Core rules - Declare public typed properties for every field the DTO owns. - Keep validation rules, default values, casts, and mapping aligned with those property types. - Prefer explicit casts for non-trivial types, nested objects, collections, enums, dates, and numeric string inputs. - Use `nullable` or `optional` rules when a property can legitimately become `null`. - Keep DTOs focused on transport and normalization, not business logic. ### Required methods 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()`. ## Prefer attributes for concise DTOs Use attributes when rules, casts, defaults, or mapping are property-local and easy to read inline. ### Available attributes - `#[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()`. ### Traits that pair well with attributes If a DTO is fully attribute-driven, use these traits so the class can stay minimal: - `EmptyRules` - `EmptyDefaults` - `EmptyCasts` This pattern is especially useful for attribute-heavy `ValidatedDTO` classes. ## Casting guidance Use built-in casts whenever possible: - scalars: `StringCast`, `IntegerCast`, `FloatCast`, `BooleanCast` - structures: `ArrayCast`, `CollectionCast`, `ObjectCast` - dates: `CarbonCast`, `CarbonImmutableCast` - domain types: `DTOCast`, `ModelCast`, `EnumCast` Strong defaults: - Use `DTOCast` for nested DTO objects. - Use `CollectionCast(new DTOCast(...))` or `ArrayCast(new DTOCast(...))` for nested lists. - Use `EnumCast` for PHP enums instead of manual string handling. - Use a custom `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. ## Mapping guidance 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. ## Working with runtime sources DTOs can be created from several sources: ```php $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: ```php public function store(UserDTO $dto) { // ... } ``` ## Livewire and lazy validation When a DTO is filled progressively, prefer lazy validation: - set `public bool $lazyValidation = true`, or - add `#[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. ## Converting FormRequests into DTOs When asked to convert a `FormRequest` into a DTO, use this migration approach: 1. Create a `ValidatedDTO` with public typed properties matching the validated payload. 2. Move `rules()` from the `FormRequest` into the DTO. 3. Move `messages()` and `attributes()` if the request defines them. 4. Convert `prepareForValidation()` style key normalization into `mapData()` or `#[Map(...)]` when possible. 5. Convert output reshaping into `mapToTransform()` or `#[Map(transform: ...)]` when needed. 6. Add casts for booleans, integers, floats, enums, nested DTOs, collections, models, and dates. 7. Replace controller signatures like `store(StoreUserRequest $request)` with `store(StoreUserDTO $dto)` when the app is using DTO auto-resolution. 8. Replace usages of `$request->validated()` with DTO properties. Important differences from `FormRequest`: - Authorization does not live in the DTO; keep that in policies, middleware, or controller/application logic. - DTOs are reusable outside HTTP, so prefer keeping request-only concerns out of them. - File validation rules can stay in the DTO; uploaded files are supported. ## Refactoring checklist When creating or updating a DTO, verify that: - property types, rules, defaults, and casts agree with each other - nullable fields have matching validation rules - nested data uses `DTOCast`, `CollectionCast`, or `ArrayCast` correctly - mapping is symmetrical only when it needs to be - exported payloads do not leak internal-only properties - the chosen DTO base class matches the actual use case ## Good defaults to follow - Prefer attributes for local property concerns. - Prefer methods for cross-field or nested mapping. - Prefer explicit casts over relying on raw input types. - Prefer `ResourceDTO` only for response objects. - Prefer DTO injection over manually duplicating request validation in controllers.
Voir sur GitHub