Mapping DTO properties

Mapping data on instantiation

Sometimes the data you have to validate is not the same as you want in your DTO. You can use the mapData method to map your data when the DTO instantiation occurs:

protected function mapData(): array
{
    return [
        'full_name' => 'name',
    ];
}

The code above will map the full_name property to the name property before the DTO instantiation. So your Request/Array/etc can have a full_name property and your DTO will have a name property instead.

Alternatively, for simpler cases, you can use the Map attribute, defining the data parameter:

use WendellAdriel\ValidatedDTO\Attributes\Map;

class UserDTO extends ValidatedDTO
{
    #[Map(data: 'full_name')]
    public string $name;

    public string $email;

    public bool $active;
}

Mapping nested data to flat data

Imagine that you have a NameDTO like this:

class NameDTO extends ValidatedDTO
{
    public string $first_name;

    public string $last_name;

    protected function rules(): array
    {
        return [
            'first_name' => ['required', 'string'],
            'last_name' => ['required', 'string'],
        ];
    }
}

But in your Request, the data comes like this:

[
    'name' => [
        'first_name' => 'John',
        'last_name' => 'Doe',
    ],
]

You can add this to the mapData method:

protected function mapData(): array
{
    return [
        'first_name' => 'name.first_name',
        'last_name' => 'name.last_name',
    ];
}

This way, the first_name and last_name properties will be mapped to the name.first_name and name.last_name properties of your request.

Mapping data before transforming

Sometimes the data you have in your DTO is not the same you want to your Model, Array, JSON. You can use the mapToTransform method to map your data before transforming your DTO to another type:

protected function mapToTransform(): array
{
    return [
        'name' => 'username',
    ];
}

The code above will map the name property to the username property before transforming your DTO to another type. So the resulting type will have a username property instead of a name property.

Alternatively, for simpler cases, you can use the Map attribute, defining the transform parameter:

use WendellAdriel\ValidatedDTO\Attributes\Map;

class UserDTO extends ValidatedDTO
{
    #[Map(transform: 'username')]
    public string $name;

    public string $email;

    public bool $active;
}

Mapping nested data to flat data

Imagine that you have a UserDTO like this:

class UserDTO extends ValidatedDTO
{
    public NameDTO $name;

    public string $email;

    protected function rules(): array
    {
        return [
            'name' => ['required', 'array'],
            'email' => ['required', 'email'],
        ];
    }

But your User model is like this:

class User extends Model
{
    protected $fillable = [
        'first_name',
        'last_name',
        'email',
    ];
}

You can add this to the mapToTransform method:

protected function mapToTransform(): array
{
    return [
        'name.first_name' => 'first_name',
        'name.last_name' => 'last_name',
    ];
}

This way, when calling the toModel method, the name.first_name and name.last_name properties of your DTO will be mapped to the first_name and last_name properties of your Model.

You can combine both methods to map your data before instantiation and before transformation. If you combine both examples above your request will have a full_name property, your DTO will have a name property and when transformed the result will have a username property.

Last updated