> ## 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 Observers ed eventi del modello

> Il meccanismo degli eventi emessi dai modelli Eloquent e come gestirli in modo centralizzato con le classi Observer. Include le novità di Laravel 13 come l'attributo `#[ObservedBy]`.

## Cosa sono gli eventi del modello

I modelli Eloquent emettono automaticamente eventi nei diversi momenti del ciclo di vita. Agganciandoti a questi eventi puoi inserire logica prima e dopo il salvataggio, la cancellazione, ecc.

Gli eventi emessi da Eloquent sono i seguenti.

| Evento          | Momento di emissione                                 |
| --------------- | ---------------------------------------------------- |
| `retrieved`     | Modello letto dal DB                                 |
| `creating`      | Subito prima di salvare un nuovo modello             |
| `created`       | Subito dopo aver salvato un nuovo modello            |
| `updating`      | Subito prima di aggiornare un modello esistente      |
| `updated`       | Subito dopo aver aggiornato un modello esistente     |
| `saving`        | Subito prima di salvare (creazione o aggiornamento)  |
| `saved`         | Subito dopo aver salvato (creazione o aggiornamento) |
| `deleting`      | Subito prima di cancellare un modello                |
| `deleted`       | Subito dopo aver cancellato un modello               |
| `trashed`       | Subito dopo il soft delete                           |
| `forceDeleting` | Subito prima della cancellazione fisica              |
| `forceDeleted`  | Subito dopo la cancellazione fisica                  |
| `restoring`     | Subito prima di ripristinare un soft delete          |
| `restored`      | Subito dopo il ripristino di un soft delete          |
| `replicating`   | Alla chiamata di `replicate()`                       |

Gli eventi che finiscono in `-ing` vengono emessi **prima** che la modifica sia persistita sul DB; quelli in `-ed` **dopo**.

<Warning>
  Sugli aggiornamenti e le cancellazioni di massa (`User::where(...)->update(...)`, ecc.), gli eventi `saving`, `saved`, `updating`, `updated`, `deleting`, `deleted` non vengono emessi, perché i modelli non vengono effettivamente recuperati.
</Warning>

## Listener con closure

Per una gestione semplice degli eventi puoi registrare closure nel metodo `booted` del modello.

```php theme={null}
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    protected static function booted(): void
    {
        static::created(function (User $user) {
            // logica eseguita dopo la creazione dell'utente
        });

        static::deleting(function (User $user) {
            // logica eseguita prima della cancellazione dell'utente
        });
    }
}
```

Per eseguire l'elaborazione in modo asincrono via queue, usa l'helper `queueable`.

```php theme={null}
use function Illuminate\Events\queueable;

static::created(queueable(function (User $user) {
    // eseguito in coda in modo asincrono
}));
```

## Proprietà `$dispatchesEvents`

Se vuoi integrarti con il sistema eventi di Laravel, mappa gli eventi del modello a tue classi evento con la proprietà `$dispatchesEvents`.

```php theme={null}
<?php

namespace App\Models;

use App\Events\UserDeleted;
use App\Events\UserSaved;
use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable
{
    /**
     * Mapping tra eventi del modello e classi evento
     *
     * @var array<string, string>
     */
    protected $dispatchesEvents = [
        'saved' => UserSaved::class,
        'deleted' => UserDeleted::class,
    ];
}
```

La classe evento mappata riceve nel costruttore l'istanza del modello.

```php theme={null}
<?php

namespace App\Events;

use App\Models\User;

class UserSaved
{
    public function __construct(
        public readonly User $user,
    ) {}
}
```

## Creare una classe Observer

Quando gestisci più eventi per un unico modello, raggruppare in una classe Observer è più ordinato che elencare closure.

<Steps>
  <Step title="Generare la classe con Artisan">
    Genera lo scaffold con `make:observer`. Con l'opzione `--model` vengono aggiunti automaticamente i metodi corrispondenti.

    ```bash theme={null}
    php artisan make:observer UserObserver --model=User
    ```

    Viene generato `app/Observers/UserObserver.php`.
  </Step>

  <Step title="Implementare i metodi per ciascun evento">
    Il nome del metodo corrisponde al nome dell'evento. L'argomento è l'istanza del modello.

    ```php theme={null}
    <?php

    namespace App\Observers;

    use App\Models\User;

    class UserObserver
    {
        public function created(User $user): void
        {
            // logica dopo la creazione dell'utente
        }

        public function updated(User $user): void
        {
            // logica dopo l'aggiornamento dell'utente
        }

        public function deleted(User $user): void
        {
            // logica dopo la cancellazione dell'utente
        }

        public function restored(User $user): void
        {
            // logica dopo il ripristino di un soft delete
        }

        public function forceDeleted(User $user): void
        {
            // logica dopo la cancellazione fisica
        }
    }
    ```
  </Step>

  <Step title="Registrare l'Observer sul modello">
    Ci sono due modi. In Laravel 13 è consigliato l'attributo `#[ObservedBy]`.

    **Metodo 1: attributo `#[ObservedBy]` (consigliato)**

    Basta applicare l'attributo alla classe del modello: nessuna modifica ad `AppServiceProvider`.

    ```php theme={null}
    <?php

    namespace App\Models;

    use App\Observers\UserObserver;
    use Illuminate\Database\Eloquent\Attributes\ObservedBy;
    use Illuminate\Foundation\Auth\User as Authenticatable;

    #[ObservedBy(UserObserver::class)]
    class User extends Authenticatable
    {
        //
    }
    ```

    Per registrare più Observer ripeti l'attributo o passa un array.

    ```php theme={null}
    #[ObservedBy(UserObserver::class)]
    #[ObservedBy(AuditObserver::class)]
    class User extends Authenticatable
    {
        //
    }
    ```

    **Metodo 2: registrazione in `AppServiceProvider`**

    Nel metodo `boot` di `AppServiceProvider` chiami `observe`.

    ```php theme={null}
    <?php

    namespace App\Providers;

    use App\Models\User;
    use App\Observers\UserObserver;
    use Illuminate\Support\ServiceProvider;

    class AppServiceProvider extends ServiceProvider
    {
        public function boot(): void
        {
            User::observe(UserObserver::class);
        }
    }
    ```
  </Step>
</Steps>

<Info>
  L'attributo `#[ObservedBy]` si trova nel namespace `Illuminate\Database\Eloquent\Attributes`. È sintassi nativa PHP dalla versione 8.0 ed è adottata attivamente in Laravel 13.
</Info>

## Observer dentro una transazione del database

Se un modello viene creato o aggiornato in una transazione, a volte vuoi che l'Observer venga eseguito dopo il commit. Implementando l'interfaccia `ShouldHandleEventsAfterCommit` ottieni questo comportamento.

```php theme={null}
<?php

namespace App\Observers;

use App\Models\User;
use Illuminate\Contracts\Events\ShouldHandleEventsAfterCommit;

class UserObserver implements ShouldHandleEventsAfterCommit
{
    public function created(User $user): void
    {
        // eseguito dopo il commit della transazione
    }
}
```

Fuori da una transazione l'esecuzione avviene immediatamente come al solito.

## Disabilitare temporaneamente gli eventi

### Fermare gli eventi solo per una specifica operazione con `withoutEvents`

Dentro la closure passata a `User::withoutEvents()` non viene emesso alcun evento del modello.

```php theme={null}
use App\Models\User;

$user = User::withoutEvents(function () {
    User::findOrFail(1)->delete();

    return User::find(2);
});
```

### Fermare gli eventi al salvataggio con `saveQuietly`

Per salvare un modello senza emettere eventi usa `saveQuietly`.

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

$user->name = 'Victoria Faith';

$user->saveQuietly();
```

Metodi analoghi sono disponibili per cancellazione, ripristino e replica.

```php theme={null}
$user->deleteQuietly();
$user->restoreQuietly();
```

## Casi d'uso pratici

### Invalidazione automatica della cache

Quando un modello viene aggiornato o cancellato, invalidi automaticamente le cache correlate.

```php theme={null}
<?php

namespace App\Observers;

use App\Models\Post;
use Illuminate\Support\Facades\Cache;

class PostObserver
{
    public function saved(Post $post): void
    {
        Cache::forget("post:{$post->id}");
        Cache::forget('posts:latest');
    }

    public function deleted(Post $post): void
    {
        Cache::forget("post:{$post->id}");
        Cache::forget('posts:latest');
    }
}
```

### Registrazione di audit log

Registri automaticamente la cronologia delle modifiche. Con `getDirty()` ottieni i valori prima e dopo la modifica.

```php theme={null}
<?php

namespace App\Observers;

use App\Models\AuditLog;
use App\Models\User;

class UserObserver
{
    public function updating(User $user): void
    {
        AuditLog::create([
            'model_type' => User::class,
            'model_id'   => $user->id,
            'changes'    => $user->getDirty(),
            'user_id'    => auth()->id(),
        ]);
    }

    public function deleted(User $user): void
    {
        AuditLog::create([
            'model_type' => User::class,
            'model_id'   => $user->id,
            'changes'    => ['deleted' => true],
            'user_id'    => auth()->id(),
        ]);
    }
}
```

<Tip>
  L'evento `updating` viene emesso **prima** del salvataggio su DB, quindi puoi ottenere i valori in procinto di essere modificati con `getDirty()`. Se lo chiami dopo `updated`, `getDirty()` sarà vuoto.
</Tip>

### Aggiornamento automatico di modelli correlati

Esempio in cui, al completamento di un ordine, il magazzino viene aggiornato automaticamente.

```php theme={null}
<?php

namespace App\Observers;

use App\Models\Order;

class OrderObserver
{
    public function created(Order $order): void
    {
        foreach ($order->items as $item) {
            $item->product->decrement('stock', $item->quantity);
        }
    }

    public function deleted(Order $order): void
    {
        foreach ($order->items as $item) {
            $item->product->increment('stock', $item->quantity);
        }
    }
}
```

## Prossimi passi

<Card title="Argomenti avanzati: attributi PHP" icon="tag" href="/it/advanced/php-attributes">
  Impara insieme gli attributi PHP di Laravel 13, compreso `#[ObservedBy]`.
</Card>


## Related topics

- [Cast personalizzati di Eloquent](/it/advanced/eloquent-casts.md)
- [Eventi](/it/packages/laravel-copilot-sdk/events.md)
- [Introduzione a Eloquent](/it/eloquent.md)
- [Verifica email (Email Verification)](/it/verification.md)
- [Eventi e listener](/it/events.md)
