Saltar al contenido principal

Qué son los eventos

El sistema de eventos de Laravel es una implementación sencilla del patrón observer. Al despachar los sucesos (eventos) que ocurren en la aplicación y definir listeners que reaccionan a ellos, se reduce al mínimo la dependencia entre componentes. Por ejemplo, al despachar el evento «pedido confirmado» pueden ejecutarse de forma independiente varios listeners: «enviar correo de confirmación», «descontar stock», «notificar a Slack», etc. El código de procesamiento del pedido no necesita saber absolutamente nada de la implementación del envío del correo ni de la notificación a Slack.
Las clases de evento se ubican en app/Events y las de listener en app/Listeners. Si esos directorios no existen, los comandos Artisan los crean automáticamente.

Generar eventos y listeners

Utiliza los comandos Artisan make:event y make:listener para generar el esqueleto.
php artisan make:event UserRegistered

php artisan make:listener SendWelcomeEmail --event=UserRegistered
Sin argumentos, los comandos te preguntan de forma interactiva.
php artisan make:event

php artisan make:listener

Registro de eventos

Descubrimiento automático de eventos

Por defecto, Laravel escanea el directorio app/Listeners y registra los listeners automáticamente. Deduce la asociación con el evento inspeccionando el tipo del argumento del método handle o __invoke.
use App\Events\UserRegistered;

class SendWelcomeEmail
{
    public function handle(UserRegistered $event): void
    {
        // Enviar el correo de bienvenida
    }
}
Usando tipos union de PHP puedes escuchar varios eventos en el mismo método.
public function handle(UserRegistered|UserUpdated $event): void
{
    // ...
}
Si tus listeners están en otro directorio, indícalo en bootstrap/app.php.
->withEvents(discover: [
    __DIR__.'/../app/Domain/Orders/Listeners',
])
Puedes usar comodines para incluir varios directorios de una vez.
->withEvents(discover: [
    __DIR__.'/../app/Domain/*/Listeners',
])
Puedes ver la lista de listeners registrados con este comando:
php artisan event:list
En producción, cachear el manifiesto de listeners mejora el rendimiento. Al desplegar ejecuta php artisan optimize o php artisan event:cache. Para borrar la caché usa php artisan event:clear.

Registro manual

También puedes registrar los listeners manualmente en el método boot de AppServiceProvider con el facade Event.
use App\Events\UserRegistered;
use App\Listeners\SendWelcomeEmail;
use Illuminate\Support\Facades\Event;

public function boot(): void
{
    Event::listen(
        UserRegistered::class,
        SendWelcomeEmail::class,
    );
}
También puedes registrarlos como closure.
use App\Events\UserRegistered;
use Illuminate\Support\Facades\Event;

public function boot(): void
{
    Event::listen(function (UserRegistered $event) {
        // ...
    });
}

Definir el evento

Las clases de evento son contenedores de datos. No contienen lógica y guardan como propiedades la información asociada al evento.
<?php

namespace App\Events;

use App\Models\User;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;

class UserRegistered
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

    public function __construct(
        public User $user,
    ) {}
}
El trait SerializesModels garantiza que los modelos Eloquent se manejen correctamente cuando los listeners encolados serialicen el evento.

Despachar eventos

Despacha eventos con el método estático dispatch o con el helper event().
use App\Events\UserRegistered;

// Método estático
UserRegistered::dispatch($user);

// Función auxiliar
event(new UserRegistered($user));
También hay métodos para despachar de forma condicional.
UserRegistered::dispatchIf($condition, $user);

UserRegistered::dispatchUnless($condition, $user);

Despachar tras una transacción de base de datos

Cuando quieras despachar el evento solo después de que la transacción se haya confirmado, implementa la interfaz ShouldDispatchAfterCommit en la clase del evento. Si la transacción falla, el evento se descarta.
<?php

namespace App\Events;

use App\Models\User;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Contracts\Events\ShouldDispatchAfterCommit;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;

class UserRegistered implements ShouldDispatchAfterCommit
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

    public function __construct(
        public User $user,
    ) {}
}

Implementar el listener

El listener recibe el evento en su método handle. En el constructor, el contenedor de servicios inyecta automáticamente las dependencias.
<?php

namespace App\Listeners;

use App\Events\UserRegistered;
use App\Mail\WelcomeMail;
use Illuminate\Support\Facades\Mail;

class SendWelcomeEmail
{
    public function __construct() {}

    public function handle(UserRegistered $event): void
    {
        Mail::to($event->user->email)
            ->send(new WelcomeMail($event->user));
    }
}
Si el método handle devuelve false, se detiene la propagación del evento a los siguientes listeners.

Listeners encolados

Los procesos lentos, como el envío de correos o las peticiones HTTP, pueden ejecutarse de forma asíncrona con listeners encolados. Con solo implementar la interfaz ShouldQueue, el listener se encolará automáticamente al despachar el evento.
<?php

namespace App\Listeners;

use App\Events\UserRegistered;
use Illuminate\Contracts\Queue\ShouldQueue;

class SendWelcomeEmail implements ShouldQueue
{
    public function handle(UserRegistered $event): void
    {
        // El worker de la cola lo ejecutará de forma asíncrona
    }
}
Antes de usar listeners encolados necesitas configurar la cola y arrancar el worker. Consulta la página de colas y jobs para más detalles.

Personalizar conexión, nombre de cola y retraso

Con atributos PHP puedes definir la conexión, la cola y el retraso.
<?php

namespace App\Listeners;

use App\Events\UserRegistered;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\Attributes\Connection;
use Illuminate\Queue\Attributes\Delay;
use Illuminate\Queue\Attributes\Queue;

#[Connection('redis')]
#[Queue('emails')]
#[Delay(10)]
class SendWelcomeEmail implements ShouldQueue
{
    public function handle(UserRegistered $event): void
    {
        // ...
    }
}
También puedes calcular los valores dinámicamente mediante métodos.
public function viaConnection(): string
{
    return 'redis';
}

public function viaQueue(): string
{
    return 'emails';
}

public function withDelay(UserRegistered $event): int
{
    return 10;
}

Reintentos y timeout máximos

Con los atributos #[Tries] y #[Timeout] puedes controlar el comportamiento ante fallos.
use Illuminate\Queue\Attributes\Tries;
use Illuminate\Queue\Attributes\Timeout;

#[Tries(3)]
#[Timeout(30)]
class SendWelcomeEmail implements ShouldQueue
{
    // ...
}

Gestión de fallos

Si defines el método failed, puedes ejecutar código adicional cuando el listener agote los reintentos.
use Throwable;

public function failed(UserRegistered $event, Throwable $exception): void
{
    // Notificar al administrador, etc.
}

Suscriptores de eventos

Los suscriptores permiten agrupar varios handlers relacionados en una única clase.

Crear un suscriptor

En el método subscribe devuelves un array con la asignación entre eventos y handlers.
<?php

namespace App\Listeners;

use Illuminate\Auth\Events\Login;
use Illuminate\Auth\Events\Logout;
use Illuminate\Events\Dispatcher;

class UserActivitySubscriber
{
    public function handleLogin(Login $event): void
    {
        // Lógica de login
    }

    public function handleLogout(Logout $event): void
    {
        // Lógica de logout
    }

    /**
     * @return array<string, string>
     */
    public function subscribe(Dispatcher $events): array
    {
        return [
            Login::class => 'handleLogin',
            Logout::class => 'handleLogout',
        ];
    }
}

Registrar el suscriptor

Con el descubrimiento automático activado, los suscriptores cuyo subscribe devuelve un array se registran automáticamente. Para registrarlos manualmente utiliza Event::subscribe en el método boot de AppServiceProvider.
use App\Listeners\UserActivitySubscriber;
use Illuminate\Support\Facades\Event;

public function boot(): void
{
    Event::subscribe(UserActivitySubscriber::class);
}

Ejemplo práctico: enviar un correo de bienvenida al registrarse un usuario

1

Crear la clase de evento

php artisan make:event UserRegistered
Edita app/Events/UserRegistered.php para añadir una propiedad con el usuario registrado.
<?php

namespace App\Events;

use App\Models\User;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;

class UserRegistered
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

    public function __construct(
        public User $user,
    ) {}
}
2

Crear la clase de listener

php artisan make:listener SendWelcomeEmail --event=UserRegistered
Para enviar el correo de forma asíncrona en la cola, implementa ShouldQueue.
<?php

namespace App\Listeners;

use App\Events\UserRegistered;
use App\Mail\WelcomeMail;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Support\Facades\Mail;

class SendWelcomeEmail implements ShouldQueue
{
    public function handle(UserRegistered $event): void
    {
        Mail::to($event->user->email)
            ->send(new WelcomeMail($event->user));
    }
}
3

Despachar el evento desde el controlador

Llama a UserRegistered::dispatch() después de crear el usuario.
<?php

namespace App\Http\Controllers\Auth;

use App\Events\UserRegistered;
use App\Models\User;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;

class RegisterController extends Controller
{
    public function store(Request $request): RedirectResponse
    {
        $user = User::create($request->validated());

        UserRegistered::dispatch($user);

        return redirect('/dashboard');
    }
}
El RegisterController se limita a despachar el evento UserRegistered sin saber nada del envío del correo. Si en el futuro quisiéramos «enviar además una notificación a Slack al registrarse», no habría que tocar el controlador.
4

Arrancar el worker

Arranca el worker para procesar los listeners encolados.
php artisan queue:work
Con el descubrimiento automático activado no hace falta registrar los listeners manualmente en AppServiceProvider. Se detectan automáticamente todos los que estén en app/Listeners.
Con php artisan event:list puedes revisar los eventos y listeners registrados. Revisa periódicamente que no haya listeners inesperados en la lista.
Última modificación el 13 de julio de 2026