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

# Accessor, mutator e cast di Eloquent

> Meccanismo di trasformazione dei valori degli attributi dei modelli Eloquent in lettura e scrittura. Definizione di accessor e mutator e uso dei cast integrati.

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

```mermaid theme={null}
flowchart LR
  DB["Database<br>(valore grezzo)"] -->|"Lettura<br>Accessor/Cast"| APP["Applicazione<br>(valore trasformato)"]
  APP -->|"Salvataggio<br>Mutator/Cast"| DB
```

## 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 theme={null}
<?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`.

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

$firstName = $user->first_name; // valore con ucfirst() applicato
```

<Info>
  Se vuoi includere il valore calcolato dall'accessor in JSON/array, aggiungilo alla proprietà `$appends` del modello in snake\_case.
</Info>

### 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.

```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 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()`.

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

Per disabilitare la cache degli oggetti usa `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();
}
```

## Definizione di un mutator

Il mutator si definisce nell'argomento `set` di `Attribute::make()`. Può essere raccolto nello stesso metodo dell'accessor.

```php theme={null}
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`.

```php theme={null}
$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.

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

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

### Elenco dei cast integrati

| Cast                        | Descrizione                              |
| --------------------------- | ---------------------------------------- |
| `integer` / `int`           | Intero                                   |
| `float` / `double` / `real` | Numero in virgola mobile                 |
| `decimal:<cifre>`           | Decimale con cifre indicate              |
| `string`                    | Stringa                                  |
| `boolean` / `bool`          | Booleano (include `0`/`1`)               |
| `array`                     | Conversione bidirezionale JSON ↔ array   |
| `object`                    | Conversione bidirezionale JSON ↔ oggetto |
| `collection`                | JSON in Collection                       |
| `date`                      | Data (Carbon)                            |
| `datetime`                  | Data/ora (Carbon)                        |
| `immutable_date`            | Data immutabile                          |
| `immutable_datetime`        | Data/ora immutabile                      |
| `timestamp`                 | Timestamp UNIX                           |
| `hashed`                    | Hasha al salvataggio                     |
| `encrypted`                 | Cifra al salvataggio                     |

<Warning>
  Gli attributi `null` non vengono cast. Inoltre, non definire cast con lo stesso nome di una relazione né sulla chiave primaria.
</Warning>

### Cast Stringable

Con `AsStringable` gli attributi vengono trattati come `Illuminate\Support\Stringable`.

```php theme={null}
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.

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

```php theme={null}
$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.

```php theme={null}
$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.

```php theme={null}
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()`.

```php theme={null}
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.

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

Se specifichi un formato, viene usato in fase di serializzazione JSON.

```php theme={null}
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).

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

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

<Tip>
  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.
</Tip>

## Cast di Enum

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

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

Nel DB viene salvato il backing value (`string` o `int`); in lettura viene convertito nell'istanza Enum.

```php theme={null}
$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`.

```php theme={null}
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()`.

```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();
```

## Cast personalizzati

Puoi creare classi di cast personalizzate. Implementa l'interfaccia `CastsAttributes` e definisci `get` e `set`.

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

Per i dettagli implementativi (pattern value object, cast in ingresso, Castables, ecc.) consulta la pagina avanzata di seguito.

<Card title="Approfondimento sui cast personalizzati" icon="book" href="/it/advanced/eloquent-casts">
  Implementazione dell'interfaccia CastsAttributes e pattern avanzati come value object e Castables.
</Card>

## Pagine correlate

<Card title="Eloquent API Resource" icon="link" href="/it/eloquent-resources">
  Come usare le classi resource per trasformare i modelli in risposte JSON coerenti.
</Card>


## Related topics

- [Cast personalizzati di Eloquent](/it/advanced/eloquent-casts.md)
- [Il nuovo ecosistema di analisi del codice Laravel — surveyor / ranger / roster](/it/blog/laravel-ecosystem-analysis.md)
- [Scope di Eloquent](/it/advanced/eloquent-scopes.md)
- [Serializzazione Eloquent](/it/eloquent-serialization.md)
- [Eloquent Bootable Traits](/it/advanced/eloquent-bootable-traits.md)
