Passer au contenu principal

Qu’est-ce qu’un cast

Les casts Eloquent permettent de convertir la valeur brute récupérée en base en un type PHP et d’effectuer l’opération inverse lors de la sauvegarde. Ils sont définis via la méthode casts.
protected function casts(): array
{
    return [
        'is_admin'   => 'boolean',
        'settings'   => 'array',
        'created_at' => 'datetime',
    ];
}

Types de casts intégrés

Voici la liste des casts fournis en standard par Laravel.
CastDescription
integer / intConvertit en entier
float / doubleConvertit en nombre à virgule flottante
stringConvertit en chaîne de caractères
boolean / boolConvertit en booléen (inclut 0/1)
arrayChaîne JSON ↔ tableau PHP
collectionChaîne JSON ↔ instance Collection
objectChaîne JSON ↔ instance stdObject
datetimeChaîne ↔ instance Carbon
immutable_datetimeChaîne ↔ instance CarbonImmutable
dateChaîne ↔ Carbon (sans heure)
timestampChaîne ↔ timestamp UNIX
encryptedChiffré à la sauvegarde, déchiffré à la lecture
hashedHaché à la sauvegarde (à combiner avec un cast en lecture seule)
AsStringable::classChaîne ↔ objet Stringable
AsArrayObject::classJSON ↔ instance ArrayObject
AsCollection::classJSON ↔ instance Collection
AsArrayObject et AsCollection sont implémentés en interne dans Laravel comme des casts personnalisés, afin de permettre la modification directe d’offsets spécifiques du tableau.

Création d’une classe de cast personnalisée

Lorsque les casts intégrés ne suffisent pas, créez un cast personnalisé en implémentant l’interface CastsAttributes.

Définition de l’interface

Le contrat du framework est défini ainsi :
// src/Illuminate/Contracts/Database/Eloquent/CastsAttributes.php

interface CastsAttributes
{
    /**
     * Convertit la valeur brute de la BDD en valeur PHP (en lecture)
     *
     * @param  array<string, mixed>  $attributes  Toutes les valeurs d'attributs du modèle
     */
    public function get(Model $model, string $key, mixed $value, array $attributes);

    /**
     * Convertit la valeur PHP en une forme stockable en BDD (en écriture)
     *
     * @param  array<string, mixed>  $attributes  Toutes les valeurs d'attributs du modèle
     */
    public function set(Model $model, string $key, mixed $value, array $attributes);
}
L’argument $attributes contient tous les attributs du modèle, ce qui rend possible une conversion s’étendant sur plusieurs colonnes (voir le pattern Value Object ci-dessous).

Implémentation d’un cast personnalisé de base

Générez un squelette avec la commande make:cast.
php artisan make:cast AsMoney
app/Casts/AsMoney.php est généré. Comme exemple, implémentons un cast qui convertit un montant (stocké sous forme d’entier) en Value Object Money.
<?php

namespace App\Casts;

use App\ValueObjects\Money;
use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
use Illuminate\Database\Eloquent\Model;

class AsMoney implements CastsAttributes
{
    /**
     * Convertit l'entier en BDD (en centimes) en objet Money
     */
    public function get(
        Model $model,
        string $key,
        mixed $value,
        array $attributes,
    ): Money {
        return new Money((int) $value);
    }

    /**
     * Convertit l'objet Money en entier stockable en BDD
     */
    public function set(
        Model $model,
        string $key,
        mixed $value,
        array $attributes,
    ): int {
        if ($value instanceof Money) {
            return $value->amount;
        }

        return (int) $value;
    }
}
Appliquez le cast au modèle.
<?php

namespace App\Models;

use App\Casts\AsMoney;
use Illuminate\Database\Eloquent\Model;

class Order extends Model
{
    protected function casts(): array
    {
        return [
            'price' => AsMoney::class,
        ];
    }
}
Désormais, $order->price retourne une instance de Money.

Cast Value Object

Pattern qui regroupe plusieurs colonnes BDD en un seul Value Object.

Exemple d’implémentation : cast Adresse

Regroupez les deux colonnes address_line_one et address_line_two dans un Value Object Address.
<?php

namespace App\ValueObjects;

use Illuminate\Contracts\Support\Arrayable;

class Address implements Arrayable, \JsonSerializable
{
    public function __construct(
        public readonly string $lineOne,
        public readonly string $lineTwo,
    ) {}

    public function toArray(): array
    {
        return [
            'line_one' => $this->lineOne,
            'line_two' => $this->lineTwo,
        ];
    }

    public function jsonSerialize(): array
    {
        return $this->toArray();
    }
}
<?php

namespace App\Casts;

use App\ValueObjects\Address;
use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
use Illuminate\Database\Eloquent\Model;
use InvalidArgumentException;

class AsAddress implements CastsAttributes
{
    /**
     * Construit un objet Address à partir de plusieurs colonnes
     */
    public function get(
        Model $model,
        string $key,
        mixed $value,
        array $attributes,
    ): Address {
        return new Address(
            $attributes['address_line_one'],
            $attributes['address_line_two'],
        );
    }

    /**
     * Décompose l'objet Address en un tableau par colonne
     *
     * @return array<string, string>
     */
    public function set(
        Model $model,
        string $key,
        mixed $value,
        array $attributes,
    ): array {
        if (! $value instanceof Address) {
            throw new InvalidArgumentException('The given value is not an Address instance.');
        }

        return [
            'address_line_one' => $value->lineOne,
            'address_line_two' => $value->lineTwo,
        ];
    }
}
Si set retourne un tableau, Eloquent utilise les clés comme noms de colonnes et sauvegarde chaque valeur dans la colonne correspondante. Pour un cast à une seule colonne, retournez une chaîne ou un entier.
L’application au modèle et l’utilisation sont les suivantes :
<?php

namespace App\Models;

use App\Casts\AsAddress;
use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    protected function casts(): array
    {
        return [
            'address' => AsAddress::class,
        ];
    }
}
$user = User::find(1);

// Récupéré comme objet Address
echo $user->address->lineOne;

// Modifier le Value Object le reflète automatiquement en BDD à la sauvegarde
$user->address = new Address('123 Main St', 'Apt 4B');
$user->save();

Mise en cache des Value Objects

Les attributs convertis en Value Object sont mis en cache par Eloquent. Accéder deux fois au même attribut retourne la même instance d’objet. Pour désactiver la mise en cache, ajoutez la propriété $withoutObjectCaching à la classe de cast.
class AsAddress implements CastsAttributes
{
    public bool $withoutObjectCaching = true;

    // ...
}

Cast entrant (inbound, écriture seule)

Cast qui effectue la conversion uniquement lors de l’écriture en BDD, sans conversion lors de la lecture. Implémentez l’interface CastsInboundAttributes. Le cas d’usage typique est le hachage. Convertir uniquement à la sauvegarde d’un mot de passe ou d’une valeur secrète, la lecture retourne le hash tel quel.
php artisan make:cast AsHash --inbound
<?php

namespace App\Casts;

use Illuminate\Contracts\Database\Eloquent\CastsInboundAttributes;
use Illuminate\Database\Eloquent\Model;

class AsHash implements CastsInboundAttributes
{
    public function __construct(
        protected string|null $algorithm = null,
    ) {}

    /**
     * Hache lors de la sauvegarde
     */
    public function set(
        Model $model,
        string $key,
        mixed $value,
        array $attributes,
    ): string {
        return is_null($this->algorithm)
            ? bcrypt($value)
            : hash($this->algorithm, $value);
    }
}

Paramètres de cast

Pour passer des paramètres à un cast personnalisé, spécifiez-les après le nom de la classe séparés par un :. Plusieurs paramètres sont séparés par des virgules.
protected function casts(): array
{
    return [
        'secret' => AsHash::class.':sha256',
        'data'   => AsHash::class.':sha512',
    ];
}
Les paramètres sont passés au constructeur de la classe de cast.
class AsHash implements CastsInboundAttributes
{
    public function __construct(
        protected string|null $algorithm = null, // ':sha256' est passé
    ) {}
}

Castables : porter la logique de cast dans le Value Object

Un Value Object implémentant l’interface Castable a une méthode castUsing qui retourne sa propre classe de cast. Comme le modèle n’a plus besoin de connaître la classe de cast, la logique métier gagne en clarté.
<?php

namespace App\ValueObjects;

use App\Casts\AsAddress;
use Illuminate\Contracts\Database\Eloquent\Castable;

class Address implements Castable
{
    /**
     * Retourne la classe utilisée pour le cast de cet objet
     *
     * @param  array<string, mixed>  $arguments
     */
    public static function castUsing(array $arguments): string
    {
        return AsAddress::class;
    }
}
Côté modèle, spécifiez la classe Value Object au lieu de la classe de cast.
protected function casts(): array
{
    return [
        'address' => Address::class,
    ];
}
En combinant Castable avec une classe anonyme, vous pouvez regrouper le Value Object et la logique de cast dans un même fichier.
class Address implements Castable
{
    public static function castUsing(array $arguments): CastsAttributes
    {
        return new class implements CastsAttributes
        {
            public function get(Model $model, string $key, mixed $value, array $attributes): Address
            {
                return new Address(
                    $attributes['address_line_one'],
                    $attributes['address_line_two'],
                );
            }

            public function set(Model $model, string $key, mixed $value, array $attributes): array
            {
                return [
                    'address_line_one' => $value->lineOne,
                    'address_line_two' => $value->lineTwo,
                ];
            }
        };
    }
}

Interaction avec $appends et $hidden

Les casts, $appends et $hidden sont des mécanismes indépendants, mais leur combinaison demande de l’attention.
class User extends Model
{
    protected function casts(): array
    {
        return [
            'address' => AsAddress::class,
        ];
    }

    // Exclure address_line_one/two du toArray() / toJson()
    protected $hidden = ['address_line_one', 'address_line_two'];

    // Inclure l'address casté dans la sérialisation
    protected $appends = ['address'];
}
Ce qui est spécifié dans $hidden correspond aux noms de colonnes BDD. Précisez les noms de colonnes originales (address_line_one, address_line_two) plutôt que le nom d’attribut produit par le cast (address).

Ajout de casts au runtime

Pour ajouter des casts uniquement pour une requête ou un traitement particulier, utilisez la méthode mergeCasts.
$user = User::find(1);

$user->mergeCasts([
    'extra_data' => 'array',
]);

Étapes suivantes

Observateurs Eloquent et événements de modèle

Apprenez à ajouter du traitement en s’accrochant aux événements du cycle de vie du modèle (sauvegarde, suppression, etc.).
Dernière modification le 13 juillet 2026