From a model | laravel-data | Spatie

 SPATIE

  Laravel Data
===============

spatie.be/open-source

  [Docs](https://spatie.be/docs)  [Laravel-data](https://spatie.be/docs/laravel-data/v4)  As-a-data-transfer-object  From a model

 Version   v4   v3   v2   v1

 Other versions for crawler [v4](https://spatie.be/docs/laravel-data/v4) [v3](https://spatie.be/docs/laravel-data/v3) [v2](https://spatie.be/docs/laravel-data/v2) [v1](https://spatie.be/docs/laravel-data/v1)

- [ Introduction ](https://spatie.be/docs/laravel-data/v4/introduction)
- [ Support us ](https://spatie.be/docs/laravel-data/v4/support-us)
- [ Requirements ](https://spatie.be/docs/laravel-data/v4/requirements)
- [ Installation &amp; setup ](https://spatie.be/docs/laravel-data/v4/installation-setup)
- [ Third party packages ](https://spatie.be/docs/laravel-data/v4/third-party-packages)
- [ Questions and issues ](https://spatie.be/docs/laravel-data/v4/questions-issues)
- [ Changelog ](https://spatie.be/docs/laravel-data/v4/changelog)
- [ About us ](https://spatie.be/docs/laravel-data/v4/about-us)

Getting started
---------------

- [ Quickstart ](https://spatie.be/docs/laravel-data/v4/getting-started/quickstart)

As a DTO
--------

- [ Creating a data object ](https://spatie.be/docs/laravel-data/v4/as-a-data-transfer-object/creating-a-data-object)
- [ Nesting ](https://spatie.be/docs/laravel-data/v4/as-a-data-transfer-object/nesting)
- [ Collections ](https://spatie.be/docs/laravel-data/v4/as-a-data-transfer-object/collections)
- [ Abstract Data ](https://spatie.be/docs/laravel-data/v4/as-a-data-transfer-object/abstract-data)
- [ Casts ](https://spatie.be/docs/laravel-data/v4/as-a-data-transfer-object/casts)
- [ Optional properties ](https://spatie.be/docs/laravel-data/v4/as-a-data-transfer-object/optional-properties)
- [ Mapping property names ](https://spatie.be/docs/laravel-data/v4/as-a-data-transfer-object/mapping-property-names)
- [ Default values ](https://spatie.be/docs/laravel-data/v4/as-a-data-transfer-object/defaults)
- [ Computed values ](https://spatie.be/docs/laravel-data/v4/as-a-data-transfer-object/computed)
- [ From a request ](https://spatie.be/docs/laravel-data/v4/as-a-data-transfer-object/request-to-data-object)
- [ From a model ](https://spatie.be/docs/laravel-data/v4/as-a-data-transfer-object/model-to-data-object)
- [ Injecting property values ](https://spatie.be/docs/laravel-data/v4/as-a-data-transfer-object/injecting-property-values)
- [ Factories ](https://spatie.be/docs/laravel-data/v4/as-a-data-transfer-object/factories)

Validation
----------

- [ Introduction ](https://spatie.be/docs/laravel-data/v4/validation/introduction)
- [ Auto rule inferring ](https://spatie.be/docs/laravel-data/v4/validation/auto-rule-inferring)
- [ Using validation attributes ](https://spatie.be/docs/laravel-data/v4/validation/using-validation-attributes)
- [ Manual rules ](https://spatie.be/docs/laravel-data/v4/validation/manual-rules)
- [ Working with the validator ](https://spatie.be/docs/laravel-data/v4/validation/working-with-the-validator)
- [ Nesting Data ](https://spatie.be/docs/laravel-data/v4/validation/nesting-data)
- [ Skipping validation ](https://spatie.be/docs/laravel-data/v4/validation/skipping-validation)

As a resource
-------------

- [ From data to array ](https://spatie.be/docs/laravel-data/v4/as-a-resource/from-data-to-array)
- [ From data to resource ](https://spatie.be/docs/laravel-data/v4/as-a-resource/from-data-to-resource)
- [ Mapping property names ](https://spatie.be/docs/laravel-data/v4/as-a-resource/mapping-property-names)
- [ Appending properties ](https://spatie.be/docs/laravel-data/v4/as-a-resource/appending-properties)
- [ Wrapping ](https://spatie.be/docs/laravel-data/v4/as-a-resource/wrapping)
- [ Including and excluding properties ](https://spatie.be/docs/laravel-data/v4/as-a-resource/lazy-properties)
- [ Transforming data ](https://spatie.be/docs/laravel-data/v4/as-a-resource/transformers)

Advanced usage
--------------

- [ Eloquent casting ](https://spatie.be/docs/laravel-data/v4/advanced-usage/eloquent-casting)
- [ Transforming to TypeScript ](https://spatie.be/docs/laravel-data/v4/advanced-usage/typescript)
- [ Working with dates ](https://spatie.be/docs/laravel-data/v4/advanced-usage/working-with-dates)
- [ Normalizers ](https://spatie.be/docs/laravel-data/v4/advanced-usage/normalizers)
- [ Pipeline ](https://spatie.be/docs/laravel-data/v4/advanced-usage/pipeline)
- [ Creating a cast ](https://spatie.be/docs/laravel-data/v4/advanced-usage/creating-a-cast)
- [ Creating a transformer ](https://spatie.be/docs/laravel-data/v4/advanced-usage/creating-a-transformer)
- [ Creating a rule inferrer ](https://spatie.be/docs/laravel-data/v4/advanced-usage/creating-a-rule-inferrer)
- [ Use with Inertia ](https://spatie.be/docs/laravel-data/v4/advanced-usage/use-with-inertia)
- [ Use with Livewire ](https://spatie.be/docs/laravel-data/v4/advanced-usage/use-with-livewire)
- [ Internal structures ](https://spatie.be/docs/laravel-data/v4/advanced-usage/internal-structures)
- [ Mapping rules ](https://spatie.be/docs/laravel-data/v4/advanced-usage/mapping-rules)
- [ Validation attributes ](https://spatie.be/docs/laravel-data/v4/advanced-usage/validation-attributes)
- [ Get data from a class quickly ](https://spatie.be/docs/laravel-data/v4/advanced-usage/get-data-from-a-class-quickly)
- [ Performance ](https://spatie.be/docs/laravel-data/v4/advanced-usage/performance)
- [ Commands ](https://spatie.be/docs/laravel-data/v4/advanced-usage/commands)
- [ Traits and interfaces ](https://spatie.be/docs/laravel-data/v4/advanced-usage/traits-and-interfaces)
- [ In Packages ](https://spatie.be/docs/laravel-data/v4/advanced-usage/in-packages)
- [ Available property mappers ](https://spatie.be/docs/laravel-data/v4/advanced-usage/available-property-mappers)

 From a model
============

###  On this page

1. [ Casts ](#content-casts)
2. [ Attributes &amp;amp; Accessors ](#content-attributes--accessors)
3. [ Mapping property names ](#content-mapping-property-names)
4. [ Relations ](#content-relations)
5. [ Missing attributes ](#content-missing-attributes)

It is possible to create a data object from a model, let's say we have the following model:

```
class Artist extends Model
{

}
```

It has the following columns in the database:

- id
- first\_name
- last\_name
- created\_at
- updated\_at

We can create a data object from this model like this:

```
class ArtistData extends Data
{
    public int $id;
    public string $first_name;
    public string $last_name;
    public CarbonImmutable $created_at;
    public CarbonImmutable $updated_at;
}
```

We now can create a data object from the model like this:

```
$artist = ArtistData::from(Artist::find(1));
```

Casts
-----------------------------------------------------------------------

A model can have casts, these casts will be called before a data object is created. Let's extend the model:

```
class Artist extends Model
{
    public function casts(): array
    {
       return [
            'properties' => 'array'
       ];
    }
}
```

Within the database the new column will be stored as a JSON string, but in the data object we can just use the array type:

```
class ArtistData extends Data
{
    public int $id;
    public string $first_name;
    public string $last_name;
    public array $properties;
    public CarbonImmutable $created_at;
    public CarbonImmutable $updated_at;
}
```

Attributes &amp; Accessors
----------------------------------------------------------------------------------------------------------------------------

Laravel allows you to define attributes on a model, these will be called before a data object is created. Let's extend the model:

```
class Artist extends Model
{
    protected function fullName(): Attribute
    {
        return Attribute::make(
            get: fn () => $this->first_name . ' ' . $this->last_name,
        );
    }
}
```

We now can use the attribute in the data object:

```
class ArtistData extends Data
{
    public int $id;
    public string $full_name;
    public CarbonImmutable $created_at;
    public CarbonImmutable $updated_at;
}
```

Remember: we need to use the snake\_case version of the attribute in the data object since that's how it is stored in the model. Read on for a more elegant solution when you want to use camelCase property names in your data object.

It is also possible to define accessors on a model which are the successor of the attributes:

```
class Artist extends Model
{
    public function getFullName(): Attribute
    {
        return Attribute::get(fn () => "{$this->first_name} {$this->last_name}");
    }
}
```

With the same data object we created earlier we can now use the accessor.

Mapping property names
--------------------------------------------------------------------------------------------------------------------------

Sometimes you want to use camelCase property names in your data object, but the model uses snake\_case. You can use an `MapInputName` to map the property names:

```
use Spatie\LaravelData\Attributes\MapInputName;
use Spatie\LaravelData\Mappers\SnakeCaseMapper;

class ArtistData extends Data
{
    public int $id;
    #[MapInputName(SnakeCaseMapper::class)]
    public string $fullName;
    public CarbonImmutable $created_at;
    public CarbonImmutable $updated_at;
}
```

An even more elegant solution would be to map every property within the data object:

```
#[MapInputName(SnakeCaseMapper::class)]
class ArtistData extends Data
{
    public int $id;
    public string $fullName;
    public CarbonImmutable $createdAt;
    public CarbonImmutable $updatedAt;
}
```

Relations
-----------------------------------------------------------------------------------

Let's create a new model:

```
class Song extends Model
{
    public function artist(): BelongsTo
    {
        return $this->belongsTo(Artist::class);
    }
}
```

Which has the following columns in the database:

- id
- artist\_id
- title

We update our previous model as such:

```
class Artist extends Model
{
    public function songs(): HasMany
    {
        return $this->hasMany(Song::class);
    }
}
```

We can now create a data object like this:

```
class SongData extends Data
{
    public int $id;
    public string $title;
}
```

And update our previous data object like this:

```
class ArtistData extends Data
{
    public int $id;
    /** @var array  */
    public array $songs;
    public CarbonImmutable $created_at;
    public CarbonImmutable $updated_at;
}
```

We can now create a data object with the relations like this:

```
$artist = ArtistData::from(Artist::with('songs')->find(1));
```

When you're not loading the relations in advance, `null` will be returned for the relation.

It is however possible to load the relation on the fly by adding the `LoadRelation` attribute to the property:

```
class ArtistData extends Data
{
    public int $id;
    /** @var array  */
    #[LoadRelation]
    public array $songs;
    public CarbonImmutable $created_at;
    public CarbonImmutable $updated_at;
}
```

Now the data object with relations can be created like this:

```
$artist = ArtistData::from(Artist::find(1));
```

We even eager-load the relation for performance, neat!

### Be careful with automatic loading of relations

Let's update the `SongData` class like this:

```
class SongData extends Data
{
    public int $id;
    public string $title;
    #[LoadRelation]
    public ArtistData $artist;
}
```

When we now create a data object like this:

```
$song = SongData::from(Song::find(1));
```

We'll end up in an infinite loop, since the `SongData` class will try to load the `ArtistData` class, which will try to load the `SongData` class, and so on.

Missing attributes
--------------------------------------------------------------------------------------------------------------

When a model is missing attributes and `preventAccessingMissingAttributes` is enabled for a model the `MissingAttributeException` won't be thrown when creating a data object with a property that can be null or Optional.
