laravel-dto · git:20261101.814b3d5 · 2026-11-01 · sha256 47738cb945e39c41
laravel-dto git:20261101.814b3d5A
Immutable. This exact content never changes and is served at /api/v1/blob/47738cb945e39c41.
---
model_tier: medium
name: laravel-dto
description: "Use when creating a Laravel/PHP DTO with the SimpleDto base class and attribute mapping. For DTOs in other stacks, use the stack-native skill (TypeScript, Python, Rust, Go)."
domain: engineering
framework: laravel
workspaces:
- engineering
packs:
- laravel
trust:
level: professional
install:
default: false
removable: true
---
# laravel-dto
## When to use
Use this skill when creating a new DTO for data transfer between layers (DB ↔ PHP, API ↔ Service, etc.).
## Procedure: Create a DTO
1. **Read the project's DTO docs** — check `agents/reference/docs/dto.md` (if it exists) for project-specific conventions.
2. **Check the base class** — search for the DTO base class in the project (e.g., `SimpleDto`, `LiteDto`, or a custom base).
Check `composer.json` for DTO-related packages.
3. **Check existing DTOs** — look at neighboring DTOs in the same directory to match the style.
4. **Understand the model** — if the DTO maps to a Model, read the model's properties and DB columns.
## DTO conventions
### Base class
- If the project has a DTO base class (typically `SimpleDto` or `LiteDto`), extend it.
- Without one, a plain `final readonly class` is fine — never add a dependency just for a base class.
### Property mapping
- Use `#[Map('db_column')]` attributes to map between DB column names and PHP properties.
- Put `#[Map]` and validation attributes on **constructor parameters**; on a plain property they are silently ignored.
- PHP properties: `camelCase`, English names.
- DB columns: `snake_case` — match what's in the database.
### Type casting
- Use typed properties (`int`, `string`, `float`, `bool`, `Carbon`, etc.).
- The base class handles casting from DB strings to PHP types automatically.
### Validation
- Use validation attributes where appropriate: `#[Length(50)]`, `#[Email]`, `#[Decimal(10,2)]`, `#[Unsigned]`.
- Add `#[ConvertEmptyToNull]` at class level if empty strings should become null.
### Model linkage
- Add `#[HasModel(ModelClass::class)]` on the DTO.
- Add `#[HasDto(DtoClass::class)]` and `DtoMappingTrait` on the Model (if not already present).
## Structure
```php
<?php
declare(strict_types=1);
namespace App\DTO;
use Vendor\DataHelpers\SimpleDto;
use Vendor\DataHelpers\SimpleDto\Attributes\HasModel;
use Vendor\DataHelpers\SimpleDto\Attributes\Map;
#[HasModel(MyModel::class)]
final class MyModelDto extends SimpleDto
{
public function __construct(
#[Map('id_column')]
public readonly ?int $id = null,
#[Map('name_column')]
public readonly string $name = '',
#[Map('amount_column')]
public readonly float $amount = 0.0,
) {}
}
```
## Project detection
The DTO pattern varies by project:
- **Projects with a DTO package**: Use the package's base class with attribute mapping.
Read `agents/reference/docs/dto.md` for full details (if it exists).
- **Projects without a DTO package**: Check existing DTOs for the local pattern.
Some projects use plain `readonly` classes, others have custom base classes.
Always check `composer.json` for DTO-related packages before choosing the approach.
## Rules
- **Match existing patterns** — if the project already has DTOs, follow their style.
- **Do NOT create DTOs for trivial data** — if a simple array or typed parameter suffices, don't over-engineer.
- **Use the project's decimal/precision abstraction** (if one exists) for calculated money values — never `float` arithmetic for money.
- **`declare(strict_types=1)`** in every new file.
## Output format
1. DTO class per the project's convention, with typed constructor-promoted properties
2. Static factory method(s) for construction from common sources
## Gotcha
- `#[Map]` on a property without a constructor is silently ignored.
- The model forgets to add the model linkage (`$modelClass`) when the DTO maps to an Eloquent model.
- Attribute names in the DTO must match the database column names (snake_case), not the PHP property names.
## Do NOT
- Do NOT add business logic to DTOs — they are data containers only.
- Do NOT use arrays when a DTO can provide type safety.
- Do NOT skip validation when creating DTOs from external input.
## Auto-trigger keywords
- DTO
- data transfer object
- SimpleDto
- attribute mapping