> ## 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, Casts

> Erläutert, wie Sie Attributwerte von Eloquent-Modellen beim Lesen und Schreiben transformieren. Vermittelt die Definition von Accessors und Mutators sowie die Verwendung der eingebauten Casts anhand praktischer Beispiele.

## Einführung

**Accessors**, **Mutators** und **Attribute Casts** transformieren Werte eines Eloquent-Modells beim Lesen und Schreiben auf einer Modellinstanz.

* **Accessor** – veredelt den Rohwert aus der Datenbank für die Verwendung in der Anwendung
* **Mutator** – transformiert den in der Anwendung gesetzten Wert, bevor er in die Datenbank geht
* **Cast** – definiert deklarativ Typkonvertierungen für Attribute, ohne dass zusätzliche Methoden nötig wären

```mermaid theme={null}
flowchart LR
  DB["Datenbank<br>(Rohwert)"] -->|"beim Lesen<br>Accessor/Cast"| APP["Anwendung<br>(transformierter Wert)"]
  APP -->|"beim Speichern<br>Mutator/Cast"| DB
```

## Accessor definieren

Für einen Accessor fügen Sie eine `protected` Methode zum Modell hinzu. Der Methodenname folgt CamelCase-Konvention, der Rückgabetyp ist `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
{
    /**
     * Liefert den Vornamen des Nutzers.
     */
    protected function firstName(): Attribute
    {
        return Attribute::make(
            get: fn (string $value) => ucfirst($value),
        );
    }
}
```

Die `get`-Closure erhält den Rohwert aus der Datenbank. Auf der Modellinstanz greifen Sie über die Property `first_name` zu.

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

$firstName = $user->first_name; // Wert nach ucfirst()
```

<Info>
  Wenn Sie den vom Accessor berechneten Wert in JSON- oder Array-Ausgaben aufnehmen möchten, tragen Sie ihn in der `$appends`-Property des Modells als Snake-Case ein.
</Info>

### Wertobjekt aus mehreren Attributen erzeugen

Die `get`-Closure kann als zweites Argument `$attributes` erhalten (alle Attribute des Modells). Damit können Sie mehrere Spalten zu einem Wertobjekt kombinieren.

```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'],
        ),
    );
}
```

### Caching von Accessors

Accessors, die Wertobjekte zurückgeben, cachet Eloquent automatisch, sodass dieselbe Instanz zurückgegeben wird. Möchten Sie auch primitive Typen wie Strings oder Zahlen cachen, rufen Sie `shouldCache()` auf.

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

Um das Objekt-Caching auszuschalten, verwenden Sie `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();
}
```

## Mutator definieren

Ein Mutator wird über das Argument `set` von `Attribute::make()` definiert und lässt sich zusammen mit dem Accessor in derselben Methode ablegen.

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

Beim Setzen des Werts wird die `set`-Closure aufgerufen.

```php theme={null}
$user = User::find(1);
$user->first_name = 'SALLY'; // strtolower() wird angewendet, 'sally' wird gespeichert
```

### In mehrere Attribute schreiben

Gibt die `set`-Closure ein Array zurück, können mehrere Spalten gleichzeitig aktualisiert werden.

```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,
        ],
    );
}
```

## Attribute Casts

**Casts** sind eine bequeme Möglichkeit, Typkonvertierungen deklarativ zu definieren, ohne dafür Accessors und Mutators zu schreiben. Über die Methode `casts()` Ihres Modells geben Sie ein Array zurück.

```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',
        ];
    }
}
```

### Eingebaute Casts im Überblick

| Cast                         | Beschreibung                                |
| ---------------------------- | ------------------------------------------- |
| `integer` / `int`            | Ganzzahl                                    |
| `float` / `double` / `real`  | Gleitkommazahl                              |
| `decimal:<Nachkommastellen>` | Dezimalzahl mit fester Nachkommastellenzahl |
| `string`                     | Zeichenkette                                |
| `boolean` / `bool`           | Boolescher Wert (auch aus `0`/`1`)          |
| `array`                      | Wandelt JSON in ein Array um und zurück     |
| `object`                     | Wandelt JSON in ein Objekt um und zurück    |
| `collection`                 | Wandelt JSON in eine Collection             |
| `date`                       | Datum (Carbon)                              |
| `datetime`                   | Datum und Uhrzeit (Carbon)                  |
| `immutable_date`             | Unveränderliches Datum                      |
| `immutable_datetime`         | Unveränderliches Datum und Uhrzeit          |
| `timestamp`                  | UNIX-Timestamp                              |
| `hashed`                     | Hasht den Wert beim Speichern               |
| `encrypted`                  | Verschlüsselt den Wert beim Speichern       |

<Warning>
  Attribute mit `null`-Wert werden nicht gecastet. Legen Sie außerdem keine Casts an, deren Name dem einer Relation entspricht, und wandeln Sie den Primärschlüssel nicht per Cast um.
</Warning>

### Stringable-Cast

Mit `AsStringable` verwenden Sie ein Attribut als `Illuminate\Support\Stringable`-Objekt.

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

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

## Array-/JSON-Casts

JSON- oder TEXT-Spalten können transparent als PHP-Array behandelt werden.

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

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

// Automatisch als PHP-Array geladen
$options = $user->options;

// Beim Speichern automatisch als JSON serialisiert
$user->options = array_merge($options, ['theme' => 'dark']);
$user->save();
```

Mit dem Operator `->` können Sie auch einzelne Schlüssel innerhalb des JSON aktualisieren.

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

### Casts AsArrayObject / AsCollection

Der Standard-`array`-Cast führt zu einem Fehler, wenn Sie einzelne Array-Offsets direkt ändern möchten. Mit `AsArrayObject` und `AsCollection` umgehen Sie dieses Problem.

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

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

Für eine eigene Collection-Klasse verwenden Sie `using()`.

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

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

## Datums-Casts

`created_at` und `updated_at` werden standardmäßig zu Carbon gecastet. Weitere Datumsfelder können auf dieselbe Weise definiert werden.

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

Wenn Sie ein Format angeben, wird dieses bei der JSON-Serialisierung verwendet.

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

Möchten Sie das Standard-Serialisierungsformat für alle Datumsfelder ändern, überschreiben Sie `serializeDate()` (das Speicherformat in der Datenbank bleibt davon unberührt).

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

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

<Tip>
  Mit `immutable_datetime` erhalten Sie statt eines Carbon-Objekts eine `CarbonImmutable`-Instanz. Da sich diese Instanz beim Manipulieren nicht ändert, lässt sich damit besonders nebeneffektfreier Code schreiben.
</Tip>

## Enum-Casts

Ab PHP 8.1 lassen sich Backed Enums als Cast angeben.

```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 der Datenbank wird der Backing-Wert (`string` oder `int`) des Enums gespeichert; beim Lesen wird eine Enum-Instanz zurückgegeben.

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

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

### Array-Cast für Enums

Wenn Sie mehrere Enum-Werte als Array in einer Spalte speichern möchten, verwenden Sie `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 zur Query-Laufzeit

Um Casts dynamisch beim Ausführen einer Query anzuwenden, verwenden Sie `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();
```

## Benutzerdefinierte Casts

Sie können eigene Cast-Klassen erstellen. Implementieren Sie das Interface `CastsAttributes` und definieren Sie die Methoden `get` und `set`.

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

Details zur Umsetzung (Value-Object-Muster, Inbound Casts, Castables usw.) finden Sie auf der weiterführenden Seite.

<Card title="Benutzerdefinierte Casts im Detail" icon="book" href="/de/advanced/eloquent-casts">
  Erläutert die Implementierung des `CastsAttributes`-Interfaces sowie fortgeschrittene Muster wie Value Objects und Castables.
</Card>

## Verwandte Seiten

<Card title="Eloquent-API-Ressourcen" icon="link" href="/de/eloquent-resources">
  Erfahren Sie, wie Sie Modelle mit Resource-Klassen in konsistente JSON-API-Antworten umwandeln.
</Card>


## Related topics

- [Eigene Casts in Eloquent](/de/advanced/eloquent-casts.md)
- [Eloquent-Serialisierung](/de/eloquent-serialization.md)
- [Eloquent-Scopes](/de/advanced/eloquent-scopes.md)
- [Eloquent Bootable Traits](/de/advanced/eloquent-bootable-traits.md)
- [Upgrade von Laravel 10 auf 11](/de/blog/upgrade-10-to-11.md)
