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

# Accesseurs, mutateurs et casts Eloquent

> Mécanismes de transformation des attributs Eloquent en lecture et à l'écriture. Définition d'accesseurs et de mutateurs, et utilisation des casts intégrés.

## Introduction

Les **accesseurs**, **mutateurs** et **casts d'attribut** transforment les valeurs d'un modèle Eloquent lors de la lecture et de la définition sur l'instance.

* **Accesseur** — transforme la valeur brute de la base avant de la passer à l'application
* **Mutateur** — transforme la valeur fournie par l'application avant de l'enregistrer
* **Cast** — permet de déclarer une conversion de type sans écrire de méthode

```mermaid theme={null}
flowchart LR
  DB["Base de données<br>(valeur brute)"] -->|"Lecture<br>Accesseur/Cast"| APP["Application<br>(valeur transformée)"]
  APP -->|"Écriture<br>Mutateur/Cast"| DB
```

## Définir un accesseur

Ajoutez une méthode `protected` sur le modèle. Nom en camelCase, retour de type `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
{
    /**
     * Récupère le prénom de l'utilisateur.
     */
    protected function firstName(): Attribute
    {
        return Attribute::make(
            get: fn (string $value) => ucfirst($value),
        );
    }
}
```

La closure `get` reçoit la valeur brute. Accédez au champ via `first_name`.

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

$firstName = $user->first_name; // Après application de ucfirst()
```

<Info>
  Pour inclure la valeur calculée dans le JSON / le tableau, ajoutez-la à `$appends` (en snake\_case).
</Info>

### Objet valeur à partir de plusieurs attributs

`get` peut recevoir `$attributes` (tous les attributs du modèle) en 2ᵉ argument, pour combiner des colonnes en un objet valeur.

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

### Mise en cache des accesseurs

Les accesseurs retournant un objet valeur mémorisent automatiquement l'instance. Pour mettre en cache les types primitifs, appelez `shouldCache()`.

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

Pour désactiver la mise en cache des objets, utilisez `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();
}
```

## Définir un mutateur

Le mutateur se définit via l'argument `set` de `Attribute::make()`. Il peut cohabiter avec l'accesseur.

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

À l'affectation, la closure `set` est appelée.

```php theme={null}
$user = User::find(1);
$user->first_name = 'SALLY'; // Enregistré sous 'sally'
```

### Écrire dans plusieurs attributs

Si `set` retourne un tableau, plusieurs colonnes sont mises à jour.

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

## Casts d'attribut

Les **casts** offrent une déclaration concise des conversions de type sans écrire d'accesseur/mutateur. La méthode `casts()` retourne un tableau.

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

### Casts intégrés

| Cast                        | Description            |
| --------------------------- | ---------------------- |
| `integer` / `int`           | Entier                 |
| `float` / `double` / `real` | Nombre à virgule       |
| `decimal:<digits>`          | Décimal avec précision |
| `string`                    | Chaîne                 |
| `boolean` / `bool`          | Booléen (incluant 0/1) |
| `array`                     | JSON ⇔ tableau         |
| `object`                    | JSON ⇔ objet           |
| `collection`                | JSON → Collection      |
| `date`                      | Date (Carbon)          |
| `datetime`                  | DateTime (Carbon)      |
| `immutable_date`            | Date immuable          |
| `immutable_datetime`        | DateTime immuable      |
| `timestamp`                 | Timestamp UNIX         |
| `hashed`                    | Haché à l'écriture     |
| `encrypted`                 | Chiffré à l'écriture   |

<Warning>
  Les attributs `null` ne sont pas castés. Ne définissez pas non plus de cast portant le même nom qu'une relation, ni sur la clé primaire.
</Warning>

### Cast Stringable

`AsStringable` traite l'attribut comme un `Illuminate\Support\Stringable`.

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

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

## Casts tableau et JSON

Les colonnes JSON/TEXT peuvent être manipulées comme des tableaux PHP.

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

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

// Récupération en tableau PHP
$options = $user->options;

// Sérialisation JSON automatique à l'enregistrement
$user->options = array_merge($options, ['theme' => 'dark']);
$user->save();
```

L'opérateur `->` met à jour une clé JSON précise.

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

### Casts AsArrayObject / AsCollection

Le cast standard `array` ne permet pas de modifier directement un offset. `AsArrayObject` ou `AsCollection` contournent ce problème.

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

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

Pour utiliser une classe de collection personnalisée, précisez `using()`.

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

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

## Casts de date/heure

`created_at` / `updated_at` sont castés en Carbon par défaut. Faites de même pour vos colonnes.

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

Un format spécifié détermine la sérialisation JSON.

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

Pour changer globalement le format de sérialisation, surchargez `serializeDate()` (n'affecte pas la persistance en base).

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

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

<Tip>
  `immutable_datetime` renvoie un `CarbonImmutable` au lieu de `Carbon`, ce qui évite les effets de bord lors des manipulations de dates.
</Tip>

## Casts Enum

Les Backed Enums de PHP 8.1+ peuvent servir de 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,
    ];
}
```

La base stocke la valeur backing (`string` ou `int`) ; la lecture retourne l'instance Enum.

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

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

### Tableau d'Enums

Pour stocker plusieurs valeurs Enum dans une seule colonne, utilisez `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 au niveau requête

Appliquez un cast dynamiquement à l'exécution de la requête avec `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();
```

## Casts personnalisés

Vous pouvez créer vos propres casts en implémentant `CastsAttributes` et en définissant `get` / `set`.

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

Pour l'implémentation détaillée (Value Object, casts entrants, Castables…), consultez la page avancée.

<Card title="Casts personnalisés avancés" icon="book" href="/fr/advanced/eloquent-casts">
  Implémentation de `CastsAttributes`, Value Object, Castables, etc.
</Card>

## Pages associées

<Card title="Eloquent API Resources" icon="link" href="/fr/eloquent-resources">
  Convertir des modèles en réponses JSON cohérentes.
</Card>


## Related topics

- [Le nouvel écosystème d'analyse de code Laravel — surveyor / ranger / roster](/fr/blog/laravel-ecosystem-analysis.md)
- [Casts personnalisés Eloquent](/fr/advanced/eloquent-casts.md)
- [Sérialisation Eloquent](/fr/eloquent-serialization.md)
- [Scopes Eloquent](/fr/advanced/eloquent-scopes.md)
- [Console Artisan](/fr/artisan.md)
