> ## Documentation Index
> Fetch the complete documentation index at: https://kawax.biz/llms.txt
> Use this file to discover all available pages before exploring further.

# Eloquent accessors, mutators en casts

> Uitleg over het mechanisme waarmee attribuutwaarden van Eloquent-modellen worden getransformeerd bij het ophalen en opslaan. Praktische introductie tot het definiëren van accessors en mutators en het gebruik van ingebouwde casts.

## Aan de slag

**Accessors**, **mutators** en **attribuut-casts** zijn mechanismen waarmee attribuutwaarden van Eloquent-modellen worden getransformeerd wanneer je ze via een modelinstantie ophaalt of instelt.

* **Accessor** — bewerkt de ruwe waarde uit de DB en geeft die door aan je applicatie
* **Mutator** — bewerkt de waarde die vanuit je applicatie wordt gezet en slaat die op in de DB
* **Cast** — definieert declaratief typeconversie van attributen zonder extra methoden

```mermaid theme={null}
flowchart LR
  DB["Database<br>(ruwe waarde)"] -->|"Bij ophalen<br>accessor/cast"| APP["Applicatie<br>(getransformeerde waarde)"]
  APP -->|"Bij opslaan<br>mutator/cast"| DB
```

## Accessors definiëren

Om een accessor te definiëren, voeg je een `protected` methode toe aan je model. De methodenaam is in camelCase en het retourtype is `Illuminate\Database\Eloquent\Casts\Attribute`.

```php theme={null}
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    /**
     * Haal de voornaam van de gebruiker op.
     */
    protected function firstName(): Attribute
    {
        return Attribute::make(
            get: fn (string $value) => ucfirst($value),
        );
    }
}
```

De ruwe waarde uit de DB wordt doorgegeven aan de `get`-closure. Je benadert de waarde via de modelinstantie als de property `first_name`.

```php theme={null}
$user = User::find(1);

$firstName = $user->first_name; // Waarde waarop ucfirst() is toegepast
```

<Info>
  Wil je een door een accessor berekende waarde opnemen in JSON/arrays, voeg die dan in snake\_case toe aan de `$appends`-property van je model.
</Info>

### Een value object maken uit meerdere attributen

De `get`-closure kan als tweede argument `$attributes` (alle attributen van het model) ontvangen. Zo kun je meerdere kolommen combineren tot één value object.

```php theme={null}
use App\Support\Address;
use Illuminate\Database\Eloquent\Casts\Attribute;

protected function address(): Attribute
{
    return Attribute::make(
        get: fn (mixed $value, array $attributes) => new Address(
            $attributes['address_line_one'],
            $attributes['address_line_two'],
        ),
    );
}
```

### Accessors cachen

Accessors die value objects teruggeven, worden automatisch door Eloquent gecachet zodat dezelfde instantie wordt teruggegeven. Wil je ook basistypen zoals strings en getallen cachen, roep dan `shouldCache()` aan.

```php theme={null}
protected function hash(): Attribute
{
    return Attribute::make(
        get: fn (string $value) => bcrypt(gzuncompress($value)),
    )->shouldCache();
}
```

Wil je het cachen van objecten uitschakelen, gebruik dan `withoutObjectCaching()`.

```php theme={null}
protected function address(): Attribute
{
    return Attribute::make(
        get: fn (mixed $value, array $attributes) => new Address(
            $attributes['address_line_one'],
            $attributes['address_line_two'],
        ),
    )->withoutObjectCaching();
}
```

## Mutators definiëren

Mutators definieer je als het `set`-argument van `Attribute::make()`. Ze kunnen in dezelfde methode als de accessor.

```php theme={null}
protected function firstName(): Attribute
{
    return Attribute::make(
        get: fn (string $value) => ucfirst($value),
        set: fn (string $value) => strtolower($value),
    );
}
```

Wanneer je een waarde op het model zet, wordt de `set`-closure aangeroepen.

```php theme={null}
$user = User::find(1);
$user->first_name = 'SALLY'; // strtolower() wordt toegepast en 'sally' wordt opgeslagen
```

### Naar meerdere attributen schrijven

Als je vanuit de `set`-closure een array teruggeeft, kun je meerdere kolommen tegelijk bijwerken.

```php theme={null}
use App\Support\Address;
use Illuminate\Database\Eloquent\Casts\Attribute;

protected function address(): Attribute
{
    return Attribute::make(
        get: fn (mixed $value, array $attributes) => new Address(
            $attributes['address_line_one'],
            $attributes['address_line_two'],
        ),
        set: fn (Address $value) => [
            'address_line_one' => $value->lineOne,
            'address_line_two' => $value->lineTwo,
        ],
    );
}
```

## Attribuut-casts

**Casts** zijn een eenvoudige manier om typeconversie van attributen te declareren zonder accessors of mutators te schrijven. Je geeft een array terug in de `casts()`-methode van je model.

```php theme={null}
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    protected function casts(): array
    {
        return [
            'is_admin'   => 'boolean',
            'score'      => 'float',
            'settings'   => 'array',
            'created_at' => 'datetime',
        ];
    }
}
```

### Overzicht van ingebouwde casts

| Cast                        | Beschrijving                                                        |
| --------------------------- | ------------------------------------------------------------------- |
| `integer` / `int`           | Geheel getal                                                        |
| `float` / `double` / `real` | Drijvendekommagetal                                                 |
| `decimal:<aantal cijfers>`  | Decimaal getal met opgegeven aantal cijfers                         |
| `string`                    | String                                                              |
| `boolean` / `bool`          | Booleaanse waarde (inclusief `0`/`1`)                               |
| `array`                     | Zet JSON om van/naar een array                                      |
| `object`                    | Zet JSON om van/naar een object                                     |
| `collection`                | Zet JSON om naar een collectie                                      |
| `date`                      | Datum (Carbon)                                                      |
| `datetime`                  | Datum en tijd (Carbon)                                              |
| `immutable_date`            | Immutabele datum                                                    |
| `immutable_datetime`        | Immutabele datum en tijd                                            |
| `timestamp`                 | UNIX-timestamp                                                      |
| `hashed`                    | Hasht bij het opslaan                                               |
| `encrypted`                 | Versleutelt bij het opslaan                                         |
| `AsVector::class`           | Zet een databasevector om naar een array van drijvendekommagetallen |

<Warning>
  Attributen met `null` worden niet gecast. Definieer bovendien geen casts met dezelfde naam als een relatie en geen casts op de primaire sleutel.
</Warning>

### De Stringable-cast

Met `AsStringable` kun je een attribuut behandelen als een `Illuminate\Support\Stringable`-object.

```php theme={null}
use Illuminate\Database\Eloquent\Casts\AsStringable;

protected function casts(): array
{
    return [
        'bio' => AsStringable::class,
    ];
}
```

## Array- en JSON-casts

Je kunt JSON/TEXT-kolommen transparant behandelen als PHP-arrays.

```php theme={null}
protected function casts(): array
{
    return [
        'options' => 'array',
    ];
}
```

```php theme={null}
$user = User::find(1);

// Automatisch opgehaald als PHP-array
$options = $user->options;

// Bij wijzigen en opslaan wordt automatisch naar JSON geserialiseerd
$user->options = array_merge($options, ['theme' => 'dark']);
$user->save();
```

Met de `->`-operator kun je ook alleen een specifieke JSON-sleutel bijwerken.

```php theme={null}
$user->update(['options->theme' => 'dark']);
```

### De AsArrayObject- en AsCollection-casts

Bij de standaard `array`-cast krijg je een fout als je een specifieke offset van de array rechtstreeks probeert te wijzigen. Met `AsArrayObject` of `AsCollection` omzeil je dit probleem.

```php theme={null}
use Illuminate\Database\Eloquent\Casts\AsArrayObject;
use Illuminate\Database\Eloquent\Casts\AsCollection;

protected function casts(): array
{
    return [
        'options' => AsArrayObject::class,   // Behandelen als ArrayObject
        'tags'    => AsCollection::class,    // Behandelen als Collection
    ];
}
```

Wil je een eigen collectieklasse gebruiken, geef die dan op met `using()`.

```php theme={null}
use App\Collections\TagCollection;
use Illuminate\Database\Eloquent\Casts\AsCollection;

protected function casts(): array
{
    return [
        'tags' => AsCollection::using(TagCollection::class),
    ];
}
```

## De vector-cast

Met de cast `Illuminate\Database\Eloquent\Casts\AsVector` kun je een vectorkolom in de database omzetten van en naar een PHP-array.

```php theme={null}
use Illuminate\Database\Eloquent\Casts\AsVector;

protected function casts(): array
{
    return [
        'embedding' => AsVector::class,
    ];
}
```

Bij het instellen van het attribuut kun je een PHP-array of een `Arrayable`-instantie zoals een Laravel-collectie opgeven. Bij het ophalen van het attribuut geeft de cast een array van drijvendekommagetallen terug.

## Datum- en tijdcasts

`created_at` / `updated_at` worden standaard naar Carbon gecast. Extra datum-/tijdkolommen kun je op dezelfde manier definiëren.

```php theme={null}
protected function casts(): array
{
    return [
        'published_at' => 'datetime',
        'expires_at'   => 'immutable_datetime',
    ];
}
```

Als je een formaat opgeeft, wordt dat formaat gebruikt bij JSON-serialisatie.

```php theme={null}
protected function casts(): array
{
    return [
        'published_at' => 'datetime:Y-m-d',
    ];
}
```

Wil je het standaard serialisatieformaat van alle datums wijzigen, override dan `serializeDate()` (dit heeft geen invloed op het opslagformaat in de DB).

```php theme={null}
use DateTimeInterface;

protected function serializeDate(DateTimeInterface $date): string
{
    return $date->format('Y-m-d');
}
```

<Tip>
  Met `immutable_datetime` krijg je CarbonImmutable terug in plaats van Carbon. Omdat je datum- en tijdbewerkingen kunt uitvoeren zonder de oorspronkelijke instantie te wijzigen, schrijf je gemakkelijker code zonder bijwerkingen.
</Tip>

## Enum-casts

Je kunt een backed enum van PHP 8.1 of hoger opgeven als cast.

```php theme={null}
<?php

namespace App\Enums;

enum ServerStatus: string
{
    case Provisioned = 'provisioned';
    case Ready       = 'ready';
    case Archived    = 'archived';
}
```

```php theme={null}
use App\Enums\ServerStatus;

protected function casts(): array
{
    return [
        'status' => ServerStatus::class,
    ];
}
```

In de DB wordt de backing-waarde van de enum opgeslagen (`string` of `int`), en bij het ophalen wordt die omgezet naar een enum-instantie.

```php theme={null}
$server = Server::find(1);

if ($server->status === ServerStatus::Provisioned) {
    $server->status = ServerStatus::Ready;
    $server->save();
}
```

### Array-casts van enums

Wil je meerdere enum-waarden als array in één kolom opslaan, gebruik dan `AsEnumCollection`.

```php theme={null}
use App\Enums\ServerStatus;
use Illuminate\Database\Eloquent\Casts\AsEnumCollection;

protected function casts(): array
{
    return [
        'statuses' => AsEnumCollection::of(ServerStatus::class),
    ];
}
```

## Casts tijdens queries

Om casts dynamisch toe te passen tijdens het uitvoeren van een query, gebruik je `withCasts()`.

```php theme={null}
use App\Models\Post;
use App\Models\User;

$users = User::select([
    'users.*',
    'last_posted_at' => Post::selectRaw('MAX(created_at)')
        ->whereColumn('user_id', 'users.id'),
])->withCasts([
    'last_posted_at' => 'datetime',
])->get();
```

## Eigen casts

Je kunt ook eigen castklassen maken. Implementeer de `CastsAttributes`-interface en definieer de methoden `get` en `set`.

```shell theme={null}
php artisan make:cast AsJson
```

Voor gedetailleerde implementatiemethoden (het value-objectpatroon, inbound casts, Castables, enz.) verwijzen we naar de volgende geavanceerde pagina.

<Card title="Eigen casts in detail" icon="book" href="/nl/advanced/eloquent-casts">
  Uitleg over de implementatie van de CastsAttributes-interface en geavanceerde eigen casts zoals het value-objectpatroon en Castables.
</Card>

## Gerelateerde pagina's

<Card title="Eloquent API-resources" icon="link" href="/nl/eloquent-resources">
  Bekijk het gebruik van resourceklassen die modellen omzetten naar consistente JSON-API-responses.
</Card>


## Related topics

- [Het nieuwe code-analyse-ecosysteem van Laravel — surveyor / ranger / roster](/nl/blog/laravel-ecosystem-analysis.md)
- [Custom casts van Eloquent](/nl/advanced/eloquent-casts.md)
- [Eloquent-serialisatie](/nl/eloquent-serialization.md)
- [Scopes in Eloquent](/nl/advanced/eloquent-scopes.md)
- [Upgraden van Laravel 10 naar 11](/nl/blog/upgrade-10-to-11.md)
