Lazy properties | laravel-data | Spatie

 SPATIE

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

spatie.be/open-source

  [Docs](https://spatie.be/docs)  [Laravel-data](https://spatie.be/docs/laravel-data/v1)  As-a-resource  Lazy properties

 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/v1/introduction)
- [ Support us ](https://spatie.be/docs/laravel-data/v1/support-us)
- [ Requirements ](https://spatie.be/docs/laravel-data/v1/requirements)
- [ Installation &amp; setup ](https://spatie.be/docs/laravel-data/v1/installation-setup)
- [ Questions and issues ](https://spatie.be/docs/laravel-data/v1/questions-issues)
- [ Changelog ](https://spatie.be/docs/laravel-data/v1/changelog)
- [ About us ](https://spatie.be/docs/laravel-data/v1/about-us)

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

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

As a DTO
--------

- [ Creating a data object ](https://spatie.be/docs/laravel-data/v1/as-a-data-transfer-object/creating-a-data-object)
- [ Nesting ](https://spatie.be/docs/laravel-data/v1/as-a-data-transfer-object/nesting)
- [ Collections ](https://spatie.be/docs/laravel-data/v1/as-a-data-transfer-object/collections)
- [ Casts ](https://spatie.be/docs/laravel-data/v1/as-a-data-transfer-object/casts)
- [ From a request ](https://spatie.be/docs/laravel-data/v1/as-a-data-transfer-object/request-to-data-object)

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

- [ From data to resource ](https://spatie.be/docs/laravel-data/v1/as-a-resource/from-data-to-resource)
- [ Transforming data ](https://spatie.be/docs/laravel-data/v1/as-a-resource/transformers)
- [ Lazy properties ](https://spatie.be/docs/laravel-data/v1/as-a-resource/lazy-properties)

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

- [ Eloquent casting ](https://spatie.be/docs/laravel-data/v1/advanced-usage/eloquent-casting)
- [ Transforming to TypeScript ](https://spatie.be/docs/laravel-data/v1/advanced-usage/typescript)
- [ Creating a cast ](https://spatie.be/docs/laravel-data/v1/advanced-usage/creating-a-cast)
- [ Creating a transformer ](https://spatie.be/docs/laravel-data/v1/advanced-usage/creating-a-transformer)
- [ Creating a rule inferrer ](https://spatie.be/docs/laravel-data/v1/advanced-usage/creating-a-rule-inferrer)
- [ Internal structures ](https://spatie.be/docs/laravel-data/v1/advanced-usage/internal-structures)
- [ Validation attributes ](https://spatie.be/docs/laravel-data/v1/advanced-usage/validation-attributes)

      You are viewing the documentation for **an older version** of this package. You can check the version you are using with the following command:

 `                                    composer show spatie/laravel-data                                                                                                                                                                                                                                    `

Lazy properties
===============

###  On this page

1. [ Including lazy properties ](#content-including-lazy-properties)
2. [ Types of Lazy properties ](#content-types-of-lazy-properties)
3. [ Default included lazy properties ](#content-default-included-lazy-properties)
4. [ Including by query string ](#content-including-by-query-string)

Sometimes you don't want all the properties included when transforming a data object to an array, for example:

```
class AlbumData extends Data
{
    public function __construct(
        public string $title,
        /** @var SongData[] */
        public DataCollection $songs,
    ) {
    }
}
```

This will always output a collection of songs, which can become quite large. With lazy properties, we can include properties when we want to:

```
use Spatie\LaravelData\Data;
use Spatie\LaravelData\DataCollection;
use Spatie\LaravelData\Lazy;

class AlbumData extends Data
{
    public function __construct(
        public string $title,
        /** @var SongData[] */
        public Lazy|DataCollection $songs,
    ) {
    }

    public static function fromModel(Album $album): self
    {
        return new self(
            $album->title,
            Lazy::create(fn() => SongData::collection($album->songs))
        );
    }
}
```

The `songs` key won't be included in the resource when transforming it from a model. Because the closure that provides the data won't be called when transforming the data object unless we explicitly demand it.

Now when we transform the data object as such:

```
AlbumData::from(Album::first())->toArray();
```

We get the following JSON:

```
{
    "name": "Together Forever"
}
```

As you can see, the `songs` property is missing in the JSON output. Here's how you can include it.

```
AlbumData::from(Album::first())->include('songs');
```

Including lazy properties
-----------------------------------------------------------------------------------------------------------------------------------

Properties will only be included when the `include` method is called on the data object with the property's name.

It is also possible to nest these includes. For example, let's update the `SongData` class and make all of its properties lazy:

```
use Spatie\LaravelData\Lazy;

class SongData extends Data
{
    public function __construct(
        public Lazy|string $title,
        public Lazy|string $artist,
    ) {
    }

    public static function fromModel(Song $song): self
    {
        return new self(
            Lazy::create(fn() => $song->title),
            Lazy::create(fn() => $song->artist)
        );
    }
}
```

Now `name` or `artist` should be explicitly included. This can be done as such on the `AlbumData`:

```
AlbumData::from(Album::first())->include('songs.name', 'songs.artist');
```

Or you could combine these includes:

```
AlbumData::from(Album::first())->include('songs.{name, artist}');
```

If you want to include all the properties of a data object, you can do the following:

```
AlbumData::from(Album::first())->include('songs.*');
```

Explicitly including properties of data objects also works on a single data object. For example, our `UserData` looks like this:

```
class UserData extends Data
{
    public function __construct(
        public string $title,
        public Lazy|SongData $favorite_song,
    ) {
    }

    public static function fromModel(User $user): self
    {
        return new self(
            $user->title,
            Lazy::create(fn() => SongData::create($user->favorite_song))
        );
    }
}
```

We can include properties of the data object just like we would with collections of data objects:

```
return UserData::from(Auth::user())->include('favorite_song.name');
```

Types of Lazy properties
--------------------------------------------------------------------------------------------------------------------------------

### Conditional Lazy properties

You can include lazy properties in different ways:

```
Lazy::create(fn() => SongData::collection($album->songs));
```

With a basic `Lazy` property, you must explicitly include it when the data object is transformed.

Sometimes you only want to include a property when a specific condition is true. This can be done with conditional lazy properties:

```
Lazy::when($this->is_admin, fn() => SongData::collection($album->songs));
```

The property will only be included when the `is_admin` property of the data object is true. It is not possible to include the property later on with the `include` method when a condition is not accepted.

### Relational Lazy properties

You can also only include a lazy property when a particular relation is loaded on the model as such:

```
Lazy::whenLoaded('songs', $album, fn() => SongData::collection($album->songs));
```

Now the property will only be included when the song's relation is loaded on the model.

Default included lazy properties
--------------------------------------------------------------------------------------------------------------------------------------------------------

It is possible to mark a lazy property as included by default:

```
Lazy::create(fn() => SongData::collection($album->songs))->defaultIncluded();
```

The property will now always be included when the data object is transformed. You can explicitly exclude properties that were default included as such:

```
AlbumData::create(Album::first())->exclude('songs');
```

Including by query string
-----------------------------------------------------------------------------------------------------------------------------------

It is possible to include or exclude lazy properties by the URL query string:

For example, when we create a route `my-account`:

```
// in web.php

Route::get('my-account', fn() => UserData::from(User::first()));
```

Our JSON would look like this when we request `https://spatie.be/my-account`:

```
{
    "name": "Ruben Van Assche"
}
```

We can include `favorite_song` by adding it to the query in the URL as such:

```
https://spatie.be/my-account?include=favorite_song
```

It is also possible to define excludes with the `exclude` key in the URL query.

Including and excluding lazy properties works for data objects and data collections.
