Vai al contenuto principale

Introduzione

Accessor, mutator e cast sono meccanismi per trasformare i valori degli attributi dei modelli Eloquent quando li leggi o li imposti sull’istanza del modello.
  • Accessor — trasforma il valore grezzo letto dal DB prima di passarlo all’applicazione
  • Mutator — trasforma il valore impostato dall’applicazione prima di salvarlo nel DB
  • Cast — definisce in modo dichiarativo la conversione di tipo di un attributo, senza scrivere metodi aggiuntivi

Definizione di un accessor

Per definire un accessor aggiungi un metodo protected al modello. Nome del metodo in camelCase e tipo di ritorno Illuminate\Database\Eloquent\Casts\Attribute.
<?php

namespace App\Models;

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

class User extends Model
{
    /**
     * Ottiene il nome dell'utente.
     */
    protected function firstName(): Attribute
    {
        return Attribute::make(
            get: fn (string $value) => ucfirst($value),
        );
    }
}
Alla closure get viene passato il valore grezzo dal DB. Accedi dall’istanza del modello come proprietà first_name.
$user = User::find(1);

$firstName = $user->first_name; // valore con ucfirst() applicato
Se vuoi includere il valore calcolato dall’accessor in JSON/array, aggiungilo alla proprietà $appends del modello in snake_case.

Creare un value object da più attributi

La closure get può ricevere come secondo argomento $attributes (tutti gli attributi del modello). Combinando più colonne puoi restituire un value object.
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 degli accessor

Gli accessor che restituiscono value object vengono memorizzati in cache automaticamente per restituire la stessa istanza. Per fare cache anche di tipi base come stringhe e numeri, chiama shouldCache().
protected function hash(): Attribute
{
    return Attribute::make(
        get: fn (string $value) => bcrypt(gzuncompress($value)),
    )->shouldCache();
}
Per disabilitare la cache degli oggetti usa withoutObjectCaching().
protected function address(): Attribute
{
    return Attribute::make(
        get: fn (mixed $value, array $attributes) => new Address(
            $attributes['address_line_one'],
            $attributes['address_line_two'],
        ),
    )->withoutObjectCaching();
}

Definizione di un mutator

Il mutator si definisce nell’argomento set di Attribute::make(). Può essere raccolto nello stesso metodo dell’accessor.
protected function firstName(): Attribute
{
    return Attribute::make(
        get: fn (string $value) => ucfirst($value),
        set: fn (string $value) => strtolower($value),
    );
}
Quando imposti un valore sul modello, viene chiamata la closure set.
$user = User::find(1);
$user->first_name = 'SALLY'; // viene applicato strtolower() e viene salvato 'sally'

Scrivere su più attributi

Se la closure set restituisce un array, puoi aggiornare più colonne insieme.
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,
        ],
    );
}

Cast degli attributi

I cast sono un modo pratico per dichiarare la conversione di tipo di un attributo senza scrivere accessor/mutator. Nel metodo casts() del modello restituisci un array.
<?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',
        ];
    }
}

Elenco dei cast integrati

CastDescrizione
integer / intIntero
float / double / realNumero in virgola mobile
decimal:<cifre>Decimale con cifre indicate
stringStringa
boolean / boolBooleano (include 0/1)
arrayConversione bidirezionale JSON ↔ array
objectConversione bidirezionale JSON ↔ oggetto
collectionJSON in Collection
dateData (Carbon)
datetimeData/ora (Carbon)
immutable_dateData immutabile
immutable_datetimeData/ora immutabile
timestampTimestamp UNIX
hashedHasha al salvataggio
encryptedCifra al salvataggio
Gli attributi null non vengono cast. Inoltre, non definire cast con lo stesso nome di una relazione né sulla chiave primaria.

Cast Stringable

Con AsStringable gli attributi vengono trattati come Illuminate\Support\Stringable.
use Illuminate\Database\Eloquent\Casts\AsStringable;

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

Cast array / JSON

Puoi trattare in modo trasparente colonne JSON/TEXT come array PHP.
protected function casts(): array
{
    return [
        'options' => 'array',
    ];
}
$user = User::find(1);

// Ottieni automaticamente come array PHP
$options = $user->options;

// Se lo modifichi e salvi, viene serializzato automaticamente in JSON
$user->options = array_merge($options, ['theme' => 'dark']);
$user->save();
Con l’operatore -> puoi aggiornare anche una specifica chiave del JSON.
$user->update(['options->theme' => 'dark']);

Cast AsArrayObject / AsCollection

Il cast standard array non consente di modificare direttamente un offset. Con AsArrayObject o AsCollection eviti questo limite.
use Illuminate\Database\Eloquent\Casts\AsArrayObject;
use Illuminate\Database\Eloquent\Casts\AsCollection;

protected function casts(): array
{
    return [
        'options' => AsArrayObject::class,   // trattalo come ArrayObject
        'tags'    => AsCollection::class,    // trattalo come Collection
    ];
}
Per usare una collection personalizzata indica using().
use App\Collections\TagCollection;
use Illuminate\Database\Eloquent\Casts\AsCollection;

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

Cast di data e ora

created_at / updated_at sono di default castati a Carbon. Puoi definire allo stesso modo altre colonne data/ora.
protected function casts(): array
{
    return [
        'published_at' => 'datetime',
        'expires_at'   => 'immutable_datetime',
    ];
}
Se specifichi un formato, viene usato in fase di serializzazione JSON.
protected function casts(): array
{
    return [
        'published_at' => 'datetime:Y-m-d',
    ];
}
Per cambiare il formato di serializzazione predefinito per tutte le date, sovrascrivi serializeDate() (non influisce sul formato di salvataggio nel DB).
use DateTimeInterface;

protected function serializeDate(DateTimeInterface $date): string
{
    return $date->format('Y-m-d');
}
Con immutable_datetime viene restituito un CarbonImmutable al posto di Carbon. Poiché le manipolazioni non modificano l’istanza originale, è più semplice scrivere codice senza effetti collaterali.

Cast di Enum

Puoi specificare come cast un Backed Enum di PHP 8.1+.
<?php

namespace App\Enums;

enum ServerStatus: string
{
    case Provisioned = 'provisioned';
    case Ready       = 'ready';
    case Archived    = 'archived';
}
use App\Enums\ServerStatus;

protected function casts(): array
{
    return [
        'status' => ServerStatus::class,
    ];
}
Nel DB viene salvato il backing value (string o int); in lettura viene convertito nell’istanza Enum.
$server = Server::find(1);

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

Cast di array di Enum

Per salvare più valori Enum in un array in una sola colonna, usa AsEnumCollection.
use App\Enums\ServerStatus;
use Illuminate\Database\Eloquent\Casts\AsEnumCollection;

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

Cast a livello di query

Per applicare cast dinamicamente all’esecuzione di una query usa withCasts().
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();

Cast personalizzati

Puoi creare classi di cast personalizzate. Implementa l’interfaccia CastsAttributes e definisci get e set.
php artisan make:cast AsJson
Per i dettagli implementativi (pattern value object, cast in ingresso, Castables, ecc.) consulta la pagina avanzata di seguito.

Approfondimento sui cast personalizzati

Implementazione dell’interfaccia CastsAttributes e pattern avanzati come value object e Castables.

Pagine correlate

Eloquent API Resource

Come usare le classi resource per trasformare i modelli in risposte JSON coerenti.
Ultima modifica il 13 luglio 2026