Injecting property values | 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  Injecting property values

 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)

  Injecting property values
- [ 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)

 Injecting property values
=========================

###  On this page

1. [ Filling properties from a route parameter ](#content-filling-properties-from-a-route-parameter)
2. [ Filling properties from route parameter properties ](#content-filling-properties-from-route-parameter-properties)
3. [ Route parameters take priority over request body ](#content-route-parameters-take-priority-over-request-body)
4. [ Filling properties from the authenticated user ](#content-filling-properties-from-the-authenticated-user)
5. [ Filling properties from the container ](#content-filling-properties-from-the-container)
6. [ Creating your own injectable attributes ](#content-creating-your-own-injectable-attributes)

When creating a data object, it is possible to inject values into properties from all kinds of sources like route parameters, the current user or dependencies in the container.

Filling properties from a route parameter
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

When creating data objects from requests, it's possible to automatically fill data properties from request route parameters, such as route models.

The `FromRouteParameter` attribute allows filling properties with route parameter values.

### Using scalar route parameters

```
Route::patch('/songs/{songId}', [SongController::class, 'update']);

class SongData extends Data {
    #[FromRouteParameter('songId')]
    public int $id;
    public string $name;
}
```

Here, the `$id` property will be filled with the `songId` route parameter value (which most likely is a string or integer).

### Using Models, objects or arrays as route parameters

Given that we have a route to create songs for a specific author, and that the `` route parameter uses route model binding to automatically bind to an `Author` model:

```
Route::post('/songs/{artist}', [SongController::class, 'store']);

class SongData extends Data {
    public int $id;
    #[FromRouteParameter('artist')]
    public ArtistData $author;
}
```

Here, the `$artist` property will be filled with the `artist` route parameter value, which will be an instance of the `Artist` model. Note that the package will automatically cast the model to `ArtistData`.

Filling properties from route parameter properties
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

The `FromRouteParameterProperty` attribute allows filling properties with values from route parameter properties. The main difference from `FromRouteParameter` is that the former uses the full route parameter value, while `FromRouteParameterProperty` uses a single property from the route parameter.

In the example below, we're using route model binding. `` represents an instance of the `Song` model. `FromRouteParameterProperty` automatically attempts to fill the `SongData` `$id` property from `$song->id`.

```
Route::patch('/songs/{song}', [SongController::class, 'update']);

class SongData extends Data {
    #[FromRouteParameterProperty('song')]
    public int $id;
    public string $name;
}
```

### Using custom property mapping

In the example below, `$name` property will be filled with `$song->title` (instead of `$song-&gt;name).

```
Route::patch('/songs/{song}', [SongController::class, 'update']);

class SongData extends Data {
    #[FromRouteParameterProperty('song')]
    public int $id;
    #[FromRouteParameterProperty('song', 'title')]
    public string $name;
}
```

### Nested property mapping

Nested properties are supported as well. Here, we fill `$singerName` from `$artist->leadSinger->name`:

```
Route::patch('/artists/{artist}/songs/{song}', [SongController::class, 'update']);

class SongData extends Data {
    #[FromRouteParameterProperty('song')]
    public int $id;
    #[FromRouteParameterProperty('artist', 'leadSinger.name')]
    public string $singerName;
}
```

Route parameters take priority over request body
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

By default, route parameters take priority over values in the request body. For example, when the song ID is present in the route model as well as request body, the ID from route model is used.

```
Route::patch('/songs/{song}', [SongController::class, 'update']);

// PATCH /songs/123
// { "id": 321, "name": "Never gonna give you up" }

class SongData extends Data {
    #[FromRouteParameterProperty('song')]
    public int $id;
    public string $name;
}
```

Here, `$id` will be `123` even though the request body has `321` as the ID value.

In most cases, this is useful - especially when you need the ID for a validation rule. However, there may be cases when the exact opposite is required.

The above behavior can be turned off by switching the `replaceWhenPresentInPayload` flag off. This can be useful when you *intend* to allow updating a property that is present in a route parameter, such as a slug:

```
Route::patch('/songs/{slug}', [SongController::class, 'update']);

// PATCH /songs/never
// { "slug": "never-gonna-give-you-up", "name": "Never gonna give you up" }

class SongData extends Data {
    #[FromRouteParameter('slug', replaceWhenPresentInPayload: false )]
    public string $slug;
}
```

Here, `$slug` will be `never-gonna-give-you-up` even though the route parameter value is `never`.

Filling properties from the authenticated user
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

The `FromCurrentUser` attribute allows filling properties with values from the authenticated user.

```
class SongData extends Data {
    #[FromAuthenticatedUser]
    public UserData $user;
}
```

It is possible to specify the guard to use when fetching the user:

```
class SongData extends Data {
    #[FromAuthenticatedUser('api')]
    public UserData $user;
}
```

Just like with route parameters, it is possible to fill properties with specific user properties using `FromAuthenticatedUserProperty`:

```
class SongData extends Data {
    #[FromAuthenticatedUserProperty('api','name')]
    public string $username;
}
```

All the other features like custom property mapping and not replacing values when present in the payload are supported as well.

Filling properties from the container
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------

The `FromContainer` attribute allows filling properties with dependencies from the container.

```
class SongData extends Data {
    #[FromContainer(SongService::class)]
    public SongService $song_service;
}
```

When a dependency requires additional parameters these can be provided as such:

```
class SongData extends Data {
    #[FromContainer(SongService::class, parameters: ['year' => 1984])]
    public SongService $song_service;
}
```

It is even possible to completely inject the container itself:

```
class SongData extends Data {
    #[FromContainer]
    public Container $container;
}
```

Selecting a property from a dependency can be done using `FromContainerProperty`:

```
class SongData extends Data {
    #[FromContainerProperty(SongService::class, 'name')]
    public string $service_name;
}
```

Again, all the other features like custom property mapping and not replacing values when present in the payload are supported as well.

Creating your own injectable attributes
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------

All the attributes we saw earlier implement the `InjectsPropertyValue` interface:

```
interface InjectsPropertyValue
{
    public function resolve(
        DataProperty $dataProperty,
        mixed $payload,
        array $properties,
        CreationContext $creationContext
    ): mixed;

    public function shouldBeReplacedWhenPresentInPayload() : bool;
}
```

It is possible to create your own attribute by implementing this interface. The `resolve` method is responsible for returning the value that should be injected into the property. The `shouldBeReplacedWhenPresentInPayload` method should return `true` if the value should be replaced when present in the payload.

 A good
match?
-------------

### What we do best

- All things Laravel
- Custom frontend components
- Building APIs
- AI-powered features
- Simplifying things
- Clean solutions
- Integrating services

### Not our cup of tea

- WordPress themes
- Cutting corners
- Free mockups to win a job
- "Just execute the briefing"

 In short: we'd like to be a **substantial part** of your project.

 [ Get in touch via email ](mailto:info@spatie.be?subject=A%20good%20match%21&body=Tell%20us%20as%20much%20as%20you%20can%20about%0A-%20your%20online%20project%0A-%20your%20planning%0A-%20your%20budget%0A-%20%E2%80%A6%0A%0AAnything%20that%20helps%20us%20to%20start%20straightforward%21)
