Saltar al contenido principal

Qué son los eventos del modelo

Los modelos Eloquent disparan eventos automáticamente en cada etapa de su ciclo de vida. Al engancharte a ellos puedes intercalar tu propia lógica antes o después de guardar, borrar, etc. Los eventos que dispara Eloquent son los siguientes.
EventoMomento en el que se dispara
retrievedAl recuperar un modelo de la BD.
creatingJusto antes de guardar un modelo nuevo.
createdJusto después de guardar un modelo nuevo.
updatingJusto antes de actualizar un modelo existente.
updatedJusto después de actualizar un modelo existente.
savingJusto antes de guardar (tanto en creación como en actualización).
savedJusto después de guardar (tanto en creación como en actualización).
deletingJusto antes de borrar el modelo.
deletedJusto después de borrar el modelo.
trashedJusto después de un soft delete.
forceDeletingJusto antes de un borrado físico.
forceDeletedJusto después de un borrado físico.
restoringJusto antes de restaurar un soft delete.
restoredJusto después de restaurar un soft delete.
replicatingAl llamar a replicate().
Los eventos terminados en -ing se disparan antes de persistir los cambios; los terminados en -ed, después.
Las actualizaciones y borrados masivos (como User::where(...)->update(...)) no disparan los eventos saving, saved, updating, updated, deleting ni deleted, porque en realidad no se recuperan modelos.

Listeners de eventos mediante closures

Si quieres tratar los eventos de forma sencilla, puedes registrar closures dentro del método booted del modelo.
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    protected static function booted(): void
    {
        static::created(function (User $user) {
            // Se ejecuta después de crear un usuario
        });

        static::deleting(function (User $user) {
            // Se ejecuta antes de eliminar un usuario
        });
    }
}
Si quieres ejecutar la lógica de forma asíncrona en una cola, utiliza el helper queueable.
use function Illuminate\Events\queueable;

static::created(queueable(function (User $user) {
    // Se ejecuta de forma asíncrona en la cola
}));

Propiedad $dispatchesEvents

Si quieres integrarte con el sistema de eventos de Laravel, la propiedad $dispatchesEvents te permite mapear eventos del modelo a tus propias clases de evento.
<?php

namespace App\Models;

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

class User extends Authenticatable
{
    /**
     * Mapping entre eventos del modelo y clases de evento
     *
     * @var array<string, string>
     */
    protected $dispatchesEvents = [
        'saved' => UserSaved::class,
        'deleted' => UserDeleted::class,
    ];
}
Las clases de evento mapeadas reciben la instancia del modelo en el constructor.
<?php

namespace App\Events;

use App\Models\User;

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

Crear una clase Observer

Si vas a manejar varios eventos de un mismo modelo, es más limpio reunirlos en una clase Observer que ir apilando closures.
1

Generar la clase con un comando Artisan

Genera el esqueleto con make:observer. Con la opción --model indica el modelo y se añaden automáticamente los métodos correspondientes.
php artisan make:observer UserObserver --model=User
Se crea app/Observers/UserObserver.php.
2

Implementar los métodos de cada evento

Los nombres de los métodos se corresponden con los nombres de los eventos. El argumento recibe la instancia del modelo.
<?php

namespace App\Observers;

use App\Models\User;

class UserObserver
{
    public function created(User $user): void
    {
        // Lógica tras crear el usuario
    }

    public function updated(User $user): void
    {
        // Lógica tras actualizar el usuario
    }

    public function deleted(User $user): void
    {
        // Lógica tras eliminar el usuario
    }

    public function restored(User $user): void
    {
        // Lógica tras restaurar un soft delete
    }

    public function forceDeleted(User $user): void
    {
        // Lógica tras el borrado físico
    }
}
3

Registrar el Observer en el modelo

Hay dos formas de registrarlo. En Laravel 13, la recomendación es usar el atributo #[ObservedBy].Opción 1: atributo #[ObservedBy] (recomendado)Basta con añadir el atributo a la clase del modelo. No necesitas tocar AppServiceProvider.
<?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
{
    //
}
Para registrar varios observers, repite el atributo o pásalos como array.
#[ObservedBy(UserObserver::class)]
#[ObservedBy(AuditObserver::class)]
class User extends Authenticatable
{
    //
}
Opción 2: registrarlo en AppServiceProviderLlama a observe en el método boot de AppServiceProvider.
<?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);
    }
}
El atributo #[ObservedBy] está en el namespace Illuminate\Database\Eloquent\Attributes. Es sintaxis nativa de PHP 8.0 y Laravel 13 la utiliza de forma activa.

Observers dentro de transacciones de base de datos

Si un modelo se crea o actualiza dentro de una transacción, a veces querrás que el Observer se ejecute después del commit. Implementando la interfaz ShouldHandleEventsAfterCommit obtendrás ese comportamiento.
<?php

namespace App\Observers;

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

class UserObserver implements ShouldHandleEventsAfterCommit
{
    public function created(User $user): void
    {
        // Se ejecuta tras el commit de la transacción
    }
}
Fuera de transacciones, se ejecuta inmediatamente como de costumbre.

Desactivar los eventos temporalmente

withoutEvents para silenciar eventos solo en un bloque

Dentro del closure que pasas a User::withoutEvents(), no se dispara ningún evento del modelo.
use App\Models\User;

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

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

saveQuietly para no disparar eventos al guardar

Si quieres guardar sin disparar eventos, utiliza saveQuietly.
$user = User::findOrFail(1);

$user->name = 'Victoria Faith';

$user->saveQuietly();
Existen métodos equivalentes para borrado, restauración y replicación.
$user->deleteQuietly();
$user->restoreQuietly();

Casos de uso prácticos

Limpieza automática de caché

Cuando un modelo se actualiza o se borra, limpia automáticamente la caché relacionada.
<?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');
    }
}

Registro de audit log

Registra automáticamente el histórico de cambios de un modelo. Con getDirty() obtienes los valores modificados.
<?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(),
        ]);
    }
}
El evento updating se dispara antes de persistir en la BD, así que getDirty() te devuelve los valores que van a cambiar. Si lo llamas después de updated, getDirty() estará vacío.

Actualización automática de modelos relacionados

Ejemplo para actualizar automáticamente el stock cuando se completa un pedido.
<?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);
        }
    }
}

Próximos pasos

Avanzado: Atributos de PHP

Aprende los atributos de PHP de Laravel 13, incluido #[ObservedBy], en un solo lugar.
Última modificación el 13 de julio de 2026