Estamos actualizando el sitio. Durante unos días es posible que veas fallos de diseño o de traducción. La documentación sigue disponible: si una página se ve mal, recárgala más tarde.

Inicio Laravel 10.x Difusión en tiempo real

Difusión en tiempo real

10.x 7 de mar. de 2026

#Introducción

En muchas aplicaciones web modernas, se utilizan WebSockets para implementar interfaces de usuario en tiempo real que se actualizan automáticamente. Cuando algunos datos se actualizan en el servidor, normalmente se envía un mensaje a través de una conexión WebSocket para que el cliente lo procese. Los WebSockets ofrecen una alternativa más eficiente que consultar continuamente el servidor de su aplicación para detectar cambios de datos que deben reflejarse en la interfaz.

Por ejemplo, imagine que su aplicación puede exportar los datos de un usuario a un archivo CSV y enviarlo por correo electrónico. Sin embargo, crear este archivo CSV toma varios minutos, por lo que decide crear y enviar el CSV dentro de un trabajo en cola. Cuando el CSV se ha creado y enviado al usuario, podemos usar la difusión de eventos para despachar un evento App\Events\UserDataExported que es recibido por el JavaScript de nuestra aplicación. Una vez recibido el evento, podemos mostrar un mensaje al usuario indicando que su CSV ha sido enviado por correo sin que tenga que actualizar la página.

Para ayudarle a construir este tipo de funcionalidades, Laravel facilita la "difusión" de sus eventos del lado servidor a través de una conexión WebSocket. Difundir sus eventos Laravel le permite compartir los mismos nombres y datos de eventos entre su aplicación Laravel del lado servidor y su aplicación JavaScript del lado cliente.

Los conceptos básicos detrás de la difusión son simples: los clientes se conectan a canales nombrados en el frontend, mientras que su aplicación Laravel difunde eventos a estos canales en el backend. Estos eventos pueden contener cualquier dato adicional que desee poner a disposición del frontend.

#Drivers soportados

Por defecto, Laravel incluye tres drivers de difusión del lado servidor para que elija: Laravel Reverb, Pusher Channels y Ably.

Примечание

Antes de profundizar en la difusión de eventos, asegúrese de haber leído la documentación de Laravel sobre eventos y listeners.

#Instalación en el servidor

Para comenzar a usar la difusión de eventos de Laravel, necesitamos hacer algunas configuraciones dentro de la aplicación Laravel y también instalar algunos paquetes.

La difusión de eventos se realiza mediante un driver de difusión del lado servidor que transmite sus eventos Laravel para que Laravel Echo (una biblioteca JavaScript) pueda recibirlos en el navegador. No se preocupe, recorreremos cada parte del proceso de instalación paso a paso.

#Configuración

Toda la configuración de difusión de eventos de su aplicación se almacena en el archivo de configuración config/broadcasting.php. Laravel soporta varios drivers de difusión listos para usar: Pusher Channels, Redis y un driver log para desarrollo local y depuración. Además, incluye un driver null que permite desactivar completamente la difusión durante las pruebas. En el archivo config/broadcasting.php encontrará ejemplos de configuración para cada uno de estos drivers.

#Proveedor de servicios de difusión

Antes de difundir cualquier evento, primero debe registrar el App\Providers\BroadcastServiceProvider. En aplicaciones Laravel nuevas, solo necesita descomentar este proveedor en el arreglo providers del archivo de configuración config/app.php. Este BroadcastServiceProvider contiene el código necesario para registrar las rutas y callbacks de autorización de difusión.

#Configuración de la cola

También deberá configurar y ejecutar un trabajador de colas. Toda la difusión de eventos se realiza mediante trabajos en cola para que el tiempo de respuesta de su aplicación no se vea afectado seriamente por la difusión de eventos.

#Reverb

Puede instalar Reverb usando el gestor de paquetes Composer:

composer require laravel/reverb

Una vez instalado el paquete, puede ejecutar el comando de instalación de Reverb para publicar la configuración, actualizar la configuración de difusión de su aplicación y agregar las variables de entorno requeridas por Reverb:

php artisan reverb:install

Puede encontrar instrucciones detalladas de instalación y uso de Reverb en la documentación de Reverb.

#Canales Pusher

Si planea difundir sus eventos usando Pusher Channels, debe instalar el SDK PHP de Pusher Channels usando el gestor de paquetes Composer:

composer require pusher/pusher-php-server

Luego, debe configurar sus credenciales de Pusher Channels en el archivo config/broadcasting.php. Este archivo ya incluye un ejemplo de configuración para Pusher Channels, permitiéndole especificar rápidamente su key, secret y application ID. Normalmente, estos valores se establecen mediante las variables de entorno PUSHER_APP_KEY, PUSHER_APP_SECRET y PUSHER_APP_ID:

PUSHER_APP_ID=your-pusher-app-id
PUSHER_APP_KEY=your-pusher-key
PUSHER_APP_SECRET=your-pusher-secret
PUSHER_APP_CLUSTER=mt1

La configuración pusher en el archivo config/broadcasting.php también le permite especificar options adicionales que son compatibles con Channels, como el cluster.

Luego, deberá cambiar su driver de difusión a pusher en su archivo .env:

BROADCAST_DRIVER=pusher

Finalmente, estará listo para instalar y configurar Laravel Echo, que recibirá los eventos difundidos en el cliente.

#Alternativas de código abierto a Pusher

soketi proporciona un servidor WebSocket compatible con Pusher para Laravel, permitiéndole aprovechar todo el poder de la difusión de Laravel sin un proveedor comercial de WebSocket. Para más información sobre la instalación y uso de paquetes de código abierto para difusión, consulte nuestra documentación sobre alternativas de código abierto.

#Ably

Примечание

La documentación a continuación explica cómo usar Ably en modo "compatibilidad con Pusher". Sin embargo, el equipo de Ably recomienda y mantiene un broadcaster y cliente Echo que aprovechan las capacidades únicas que ofrece Ably. Para más información sobre el uso de los drivers mantenidos por Ably, consulte la documentación del broadcaster Laravel de Ably.

Si planea difundir sus eventos usando Ably, debe instalar el SDK PHP de Ably usando el gestor de paquetes Composer:

composer require ably/ably-php

Luego, debe configurar sus credenciales de Ably en el archivo config/broadcasting.php. Este archivo ya incluye un ejemplo de configuración para Ably, permitiéndole especificar rápidamente su key. Normalmente, este valor se establece mediante la variable de entorno ABLY_KEY:

ABLY_KEY=your-ably-key

Luego, deberá cambiar su driver de difusión a ably en su archivo .env:

BROADCAST_DRIVER=ably

Finalmente, estará listo para instalar y configurar Laravel Echo, que recibirá los eventos difundidos en el cliente.

#Alternativas de código abierto

#Node

Soketi es un servidor WebSocket basado en Node compatible con Pusher para Laravel. Bajo el capó, Soketi utiliza µWebSockets.js para una escalabilidad y velocidad extremas. Este paquete le permite aprovechar todo el poder de la difusión de Laravel sin un proveedor comercial de WebSocket. Para más información sobre la instalación y uso de este paquete, consulte su documentación oficial.

#Instalación en el cliente

#Reverb

Laravel Echo es una biblioteca JavaScript que facilita suscribirse a canales y escuchar eventos difundidos por su driver de difusión del lado servidor. Puede instalar Echo mediante el gestor de paquetes NPM. En este ejemplo, también instalaremos el paquete pusher-js ya que Reverb utiliza el protocolo Pusher para suscripciones WebSocket, canales y mensajes:

npm install --save-dev laravel-echo pusher-js

Una vez instalado Echo, estará listo para crear una nueva instancia de Echo en el JavaScript de su aplicación. Un buen lugar para hacerlo es al final del archivo resources/js/bootstrap.js que se incluye con el framework Laravel. Por defecto, este archivo ya incluye una configuración de ejemplo para Echo; solo necesita descomentarla y actualizar la opción broadcaster a reverb:

import Echo from 'laravel-echo';

import Pusher from 'pusher-js';
window.Pusher = Pusher;

window.Echo = new Echo({
    broadcaster: 'reverb',
    key: import.meta.env.VITE_REVERB_APP_KEY,
    wsHost: import.meta.env.VITE_REVERB_HOST,
    wsPort: import.meta.env.VITE_REVERB_PORT,
    wssPort: import.meta.env.VITE_REVERB_PORT,
    forceTLS: (import.meta.env.VITE_REVERB_SCHEME ?? 'https') === 'https',
    enabledTransports: ['ws', 'wss'],
});

Luego, debe compilar los assets de su aplicación:

npm run build
Внимание

El broadcaster reverb de Laravel Echo requiere laravel-echo v1.16.0 o superior.

#Canales Pusher

Laravel Echo es una biblioteca JavaScript que facilita suscribirse a canales y escuchar eventos difundidos por su driver de difusión del lado servidor. Puede instalar Echo mediante el gestor de paquetes NPM. En este ejemplo, también instalaremos el paquete pusher-js ya que usaremos el broadcaster Pusher Channels:

npm install --save-dev laravel-echo pusher-js

Una vez instalado Echo, estará listo para crear una nueva instancia de Echo en el JavaScript de su aplicación. Un buen lugar para hacerlo es al final del archivo resources/js/bootstrap.js que se incluye con el framework Laravel. Por defecto, este archivo ya incluye una configuración de ejemplo para Echo; solo necesita descomentarla:

import Echo from 'laravel-echo';
import Pusher from 'pusher-js';

window.Pusher = Pusher;

window.Echo = new Echo({
    broadcaster: 'pusher',
    key: import.meta.env.VITE_PUSHER_APP_KEY,
    cluster: import.meta.env.VITE_PUSHER_APP_CLUSTER,
    forceTLS: true
});

Una vez que haya descomentado y ajustado la configuración de Echo según sus necesidades, puede compilar los assets de su aplicación:

npm run build
Примечание

Para aprender más sobre cómo compilar los assets JavaScript de su aplicación, consulte la documentación sobre Vite.

#Usando una instancia cliente existente

Si ya tiene una instancia cliente preconfigurada de Pusher Channels que desea que Echo utilice, puede pasarla a Echo mediante la opción de configuración client:

import Echo from 'laravel-echo';
import Pusher from 'pusher-js';

const options = {
    broadcaster: 'pusher',
    key: 'your-pusher-channels-key'
}

window.Echo = new Echo({
    ...options,
    client: new Pusher(options.key, options)
});

#Ably

Примечание

La documentación a continuación explica cómo usar Ably en modo "compatibilidad con Pusher". Sin embargo, el equipo de Ably recomienda y mantiene un broadcaster y cliente Echo que aprovechan las capacidades únicas que ofrece Ably. Para más información sobre el uso de los drivers mantenidos por Ably, consulte la documentación del broadcaster Laravel de Ably.

Laravel Echo es una biblioteca JavaScript que facilita suscribirse a canales y escuchar eventos difundidos por su driver de difusión del lado servidor. Puede instalar Echo mediante el gestor de paquetes NPM. En este ejemplo, también instalaremos el paquete pusher-js.

Quizás se pregunte por qué instalamos la biblioteca JavaScript pusher-js aunque usemos Ably para difundir nuestros eventos. Afortunadamente, Ably incluye un modo de compatibilidad con Pusher que nos permite usar el protocolo Pusher al escuchar eventos en nuestra aplicación del lado cliente:

npm install --save-dev laravel-echo pusher-js

Antes de continuar, debe habilitar el soporte para el protocolo Pusher en la configuración de su aplicación Ably. Puede activar esta función en la sección "Protocol Adapter Settings" del panel de configuración de su aplicación Ably.

Una vez instalado Echo, estará listo para crear una nueva instancia de Echo en el JavaScript de su aplicación. Un buen lugar para hacerlo es al final del archivo resources/js/bootstrap.js que se incluye con el framework Laravel. Por defecto, este archivo ya incluye una configuración de ejemplo para Echo; sin embargo, la configuración predeterminada en bootstrap.js está pensada para Pusher. Puede copiar la configuración siguiente para adaptar su configuración a Ably:

import Echo from 'laravel-echo';
import Pusher from 'pusher-js';

window.Pusher = Pusher;

window.Echo = new Echo({
    broadcaster: 'pusher',
    key: import.meta.env.VITE_ABLY_PUBLIC_KEY,
    wsHost: 'realtime-pusher.ably.io',
    wsPort: 443,
    disableStats: true,
    encrypted: true,
});

Tenga en cuenta que nuestra configuración de Echo para Ably hace referencia a una variable de entorno VITE_ABLY_PUBLIC_KEY. El valor de esta variable debe ser su clave pública de Ably. Su clave pública es la parte de su clave Ably que aparece antes del carácter :.

Una vez que haya descomentado y ajustado la configuración de Echo según sus necesidades, puede compilar los assets de su aplicación:

npm run dev
Примечание

Para aprender más sobre cómo compilar los assets JavaScript de su aplicación, consulte la documentación sobre Vite.

#Descripción general del concepto

La difusión de eventos de Laravel le permite transmitir sus eventos Laravel del lado servidor a su aplicación JavaScript del lado cliente usando un enfoque basado en drivers para WebSockets. Actualmente, Laravel incluye drivers para Pusher Channels y Ably. Los eventos pueden ser consumidos fácilmente en el cliente usando el paquete JavaScript Laravel Echo.

Los eventos se transmiten a través de "canales", que pueden ser públicos o privados. Cualquier visitante de su aplicación puede suscribirse a un canal público sin autenticación ni autorización; sin embargo, para suscribirse a un canal privado, un usuario debe estar autenticado y autorizado para escuchar en ese canal.

Примечание

Si desea explorar alternativas de código abierto a Pusher, consulte las alternativas de código abierto.

#Usando una aplicación de ejemplo

Antes de profundizar en cada componente de la difusión de eventos, veamos una visión general usando una tienda de comercio electrónico como ejemplo.

En nuestra aplicación, supongamos que tenemos una página que permite a los usuarios ver el estado de envío de sus pedidos. También supongamos que se dispara un evento OrderShipmentStatusUpdated cuando se procesa una actualización del estado de envío:

use App\Events\OrderShipmentStatusUpdated;

OrderShipmentStatusUpdated::dispatch($order);

#La interfaz ShouldBroadcast

Cuando un usuario está viendo uno de sus pedidos, no queremos que tenga que actualizar la página para ver las actualizaciones de estado. En cambio, queremos difundir las actualizaciones a la aplicación a medida que se crean. Por lo tanto, necesitamos marcar el evento OrderShipmentStatusUpdated con la interfaz ShouldBroadcast. Esto indicará a Laravel que difunda el evento cuando se dispare:

<?php

namespace App\Events;

use App\Models\Order;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Queue\SerializesModels;

class OrderShipmentStatusUpdated implements ShouldBroadcast
{
    /**
     * La instancia del pedido.
     *
     * @var \App\Models\Order
     */
    public $order;
}

La interfaz ShouldBroadcast requiere que nuestro evento defina un método broadcastOn. Este método es responsable de devolver los canales en los que el evento debe difundirse. Un esqueleto vacío de este método ya está definido en las clases de eventos generadas, por lo que solo necesitamos completar sus detalles. Solo queremos que el creador del pedido pueda ver las actualizaciones de estado, así que difundiremos el evento en un canal privado vinculado al pedido:

use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\PrivateChannel;

/**
 * Obtener el canal en el que el evento debe difundirse.
 */
public function broadcastOn(): Channel
{
    return new PrivateChannel('orders.'.$this->order->id);
}

Si desea que el evento se difunda en múltiples canales, puede devolver un array en su lugar:

use Illuminate\Broadcasting\PrivateChannel;

/**
 * Obtener los canales en los que el evento debe difundirse.
 *
 * @return array<int, \Illuminate\Broadcasting\Channel>
 */
public function broadcastOn(): array
{
    return [
        new PrivateChannel('orders.'.$this->order->id),
        // ...
    ];
}

#Autorizando canales

Recuerde, los usuarios deben estar autorizados para escuchar en canales privados. Podemos definir nuestras reglas de autorización de canales en el archivo routes/channels.php de nuestra aplicación. En este ejemplo, necesitamos verificar que cualquier usuario que intente escuchar en el canal privado orders.1 sea realmente el creador del pedido:

use App\Models\Order;
use App\Models\User;

Broadcast::channel('orders.{orderId}', function (User $user, int $orderId) {
    return $user->id === Order::findOrNew($orderId)->user_id;
});

El método channel acepta dos argumentos: el nombre del canal y un callback que devuelve true o false indicando si el usuario está autorizado para escuchar en el canal.

Todos los callbacks de autorización reciben como primer argumento al usuario autenticado actualmente y cualquier parámetro comodín adicional como argumentos posteriores. En este ejemplo, usamos el marcador {orderId} para indicar que la parte "ID" del nombre del canal es un comodín.

#Escuchando transmisiones de eventos

A continuación, solo queda escuchar el evento en nuestra aplicación JavaScript. Podemos hacerlo usando Laravel Echo. Primero, usaremos el método private para suscribirnos al canal privado. Luego, podemos usar el método listen para escuchar el evento OrderShipmentStatusUpdated. Por defecto, todas las propiedades públicas del evento se incluirán en la transmisión:

Echo.private(`orders.${orderId}`)
    .listen('OrderShipmentStatusUpdated', (e) => {
        console.log(e.order);
    });

#Definiendo eventos de difusión

Para informar a Laravel que un evento dado debe difundirse, debe implementar la interfaz Illuminate\Contracts\Broadcasting\ShouldBroadcast en la clase del evento. Esta interfaz ya está importada en todas las clases de eventos generadas por el framework, por lo que puede agregarla fácilmente a cualquiera de sus eventos.

La interfaz ShouldBroadcast requiere que implemente un único método: broadcastOn. El método broadcastOn debe devolver un canal o un array de canales en los que el evento debe difundirse. Los canales deben ser instancias de Channel, PrivateChannel o PresenceChannel. Las instancias de Channel representan canales públicos a los que cualquier usuario puede suscribirse, mientras que PrivateChannels y PresenceChannels representan canales privados que requieren autorización de canal:

<?php

namespace App\Events;

use App\Models\User;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Queue\SerializesModels;

class ServerCreated implements ShouldBroadcast
{
    use SerializesModels;

    /**
     * Crear una nueva instancia del evento.
     */
    public function __construct(
        public User $user,
    ) {}

    /**
     * Obtener los canales en los que el evento debe difundirse.
     *
     * @return array<int, \Illuminate\Broadcasting\Channel>
     */
    public function broadcastOn(): array
    {
        return [
            new PrivateChannel('user.'.$this->user->id),
        ];
    }
}

Después de implementar la interfaz ShouldBroadcast, solo necesita disparar el evento como normalmente lo haría. Una vez que el evento se ha disparado, un trabajo en cola difundirá automáticamente el evento usando el driver de difusión especificado.

#Nombre de la difusión

Por defecto, Laravel difundirá el evento usando el nombre de la clase del evento. Sin embargo, puede personalizar el nombre de la difusión definiendo un método broadcastAs en el evento:

/**
 * El nombre de difusión del evento.
 */
public function broadcastAs(): string
{
    return 'server.created';
}

Si personaliza el nombre de la difusión usando el método broadcastAs, debe asegurarse de registrar su listener con un carácter . inicial. Esto indicará a Echo que no anteponga el namespace de la aplicación al evento:

.listen('.server.created', function (e) {
    ....
});

#Datos de la difusión

Cuando un evento se difunde, todas sus propiedades public se serializan automáticamente y se transmiten como la carga útil del evento, permitiéndole acceder a cualquiera de sus datos públicos desde su aplicación JavaScript. Por ejemplo, si su evento tiene una única propiedad pública $user que contiene un modelo Eloquent, la carga útil de la difusión del evento sería:

{
    "user": {
        "id": 1,
        "name": "Patrick Stewart"
        ...
    }
}

Sin embargo, si desea tener un control más detallado sobre la carga útil de su difusión, puede agregar un método broadcastWith a su evento. Este método debe devolver el array de datos que desea difundir como carga útil del evento:

/**
 * Obtener los datos para difundir.
 *
 * @return array<string, mixed>
 */
public function broadcastWith(): array
{
    return ['id' => $this->user->id];
}

#Cola de difusión

Por defecto, cada evento de difusión se coloca en la cola predeterminada para la conexión de cola predeterminada especificada en su archivo de configuración queue.php. Puede personalizar la conexión y el nombre de la cola usados por el broadcaster definiendo las propiedades connection y queue en su clase de evento:

/**
 * El nombre de la conexión de cola a usar al difundir el evento.
 *
 * @var string
 */
public $connection = 'redis';

/**
 * El nombre de la cola en la que colocar el trabajo de difusión.
 *
 * @var string
 */
public $queue = 'default';

Alternativamente, puede personalizar el nombre de la cola definiendo un método broadcastQueue en su evento:

/**
 * El nombre de la cola en la que colocar el trabajo de difusión.
 */
public function broadcastQueue(): string
{
    return 'default';
}

Si desea difundir su evento usando la cola sync en lugar del driver de cola predeterminado, puede implementar la interfaz ShouldBroadcastNow en lugar de ShouldBroadcast:

<?php

use Illuminate\Contracts\Broadcasting\ShouldBroadcastNow;

class OrderShipmentStatusUpdated implements ShouldBroadcastNow
{
    // ...
}

#Condiciones de difusión

A veces desea difundir su evento solo si se cumple una condición determinada. Puede definir estas condiciones agregando un método broadcastWhen a su clase de evento:

/**
 * Determinar si este evento debe difundirse.
 */
public function broadcastWhen(): bool
{
    return $this->order->value > 100;
}

#Difusión y transacciones de base de datos

Cuando los eventos de difusión se despachan dentro de transacciones de base de datos, pueden ser procesados por la cola antes de que la transacción de base de datos se haya confirmado. Cuando esto sucede, cualquier actualización que haya hecho a modelos o registros de base de datos durante la transacción puede que aún no se refleje en la base de datos. Además, cualquier modelo o registro creado dentro de la transacción puede que no exista aún en la base de datos. Si su evento depende de estos modelos, pueden ocurrir errores inesperados cuando se procesa el trabajo que difunde el evento.

Si la opción de configuración after_commit de la conexión de su cola está establecida en false, aún puede indicar que un evento de broadcast en particular debe despacharse después de que todas las transacciones abiertas de la base de datos hayan sido confirmadas implementando la interfaz ShouldDispatchAfterCommit en la clase del evento:

<?php

namespace App\Events;

use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Contracts\Events\ShouldDispatchAfterCommit;
use Illuminate\Queue\SerializesModels;

class ServerCreated implements ShouldBroadcast, ShouldDispatchAfterCommit
{
    use SerializesModels;
}
Примечание

Para aprender más sobre cómo solucionar estos problemas, por favor revise la documentación sobre trabajos en cola y transacciones de base de datos.

#Autorización de canales

Los canales privados requieren que autorice que el usuario autenticado actualmente pueda realmente escuchar en el canal. Esto se logra haciendo una solicitud HTTP a su aplicación Laravel con el nombre del canal y permitiendo que su aplicación determine si el usuario puede escuchar en ese canal. Al usar Laravel Echo, la solicitud HTTP para autorizar suscripciones a canales privados se realizará automáticamente; sin embargo, debe definir las rutas adecuadas para responder a estas solicitudes.

#Definiendo rutas de autorización

Afortunadamente, Laravel facilita la definición de las rutas para responder a las solicitudes de autorización de canales. En el App\Providers\BroadcastServiceProvider incluido con su aplicación Laravel, verá una llamada al método Broadcast::routes. Este método registrará la ruta /broadcasting/auth para manejar las solicitudes de autorización:

Broadcast::routes();

El método Broadcast::routes colocará automáticamente sus rutas dentro del grupo de middleware web; sin embargo, puede pasar un arreglo de atributos de ruta al método si desea personalizar los atributos asignados:

Broadcast::routes($attributes);

#Personalizando el endpoint de autorización

Por defecto, Echo usará el endpoint /broadcasting/auth para autorizar el acceso a canales. Sin embargo, puede especificar su propio endpoint de autorización pasando la opción de configuración authEndpoint a su instancia de Echo:

window.Echo = new Echo({
    broadcaster: 'pusher',
    // ...
    authEndpoint: '/custom/endpoint/auth'
});

#Personalizando la solicitud de autorización

Puede personalizar cómo Laravel Echo realiza las solicitudes de autorización proporcionando un autorizador personalizado al inicializar Echo:

window.Echo = new Echo({
    // ...
    authorizer: (channel, options) => {
        return {
            authorize: (socketId, callback) => {
                axios.post('/api/broadcasting/auth', {
                    socket_id: socketId,
                    channel_name: channel.name
                })
                .then(response => {
                    callback(null, response.data);
                })
                .catch(error => {
                    callback(error);
                });
            }
        };
    },
})

#Definiendo callbacks de autorización

A continuación, necesitamos definir la lógica que realmente determinará si el usuario autenticado actualmente puede escuchar un canal dado. Esto se hace en el archivo routes/channels.php que se incluye con su aplicación. En este archivo, puede usar el método Broadcast::channel para registrar callbacks de autorización de canales:

use App\Models\User;

Broadcast::channel('orders.{orderId}', function (User $user, int $orderId) {
    return $user->id === Order::findOrNew($orderId)->user_id;
});

El método channel acepta dos argumentos: el nombre del canal y un callback que devuelve true o false indicando si el usuario está autorizado para escuchar en el canal.

Todos los callbacks de autorización reciben al usuario autenticado actualmente como su primer argumento y cualquier parámetro comodín adicional como argumentos subsecuentes. En este ejemplo, usamos el marcador {orderId} para indicar que la parte "ID" del nombre del canal es un comodín.

Puede ver una lista de los callbacks de autorización de broadcast de su aplicación usando el comando Artisan channel:list:

php artisan channel:list

#Enlace de modelo en callback de autorización

Al igual que las rutas HTTP, las rutas de canales también pueden aprovechar el enlace de modelo implícito y explícito. Por ejemplo, en lugar de recibir un ID de orden como cadena o número, puede solicitar una instancia real del modelo Order:

use App\Models\Order;
use App\Models\User;

Broadcast::channel('orders.{order}', function (User $user, Order $order) {
    return $user->id === $order->user_id;
});
Внимание

A diferencia del enlace de modelo en rutas HTTP, el enlace de modelo en canales no soporta el scoping implícito de enlace de modelo. Sin embargo, esto rara vez es un problema porque la mayoría de los canales pueden ser limitados basándose en la clave primaria única de un solo modelo.

#Autenticación en callback de autorización

Los canales privados y de presencia autentican al usuario actual mediante el guardia de autenticación predeterminado de su aplicación. Si el usuario no está autenticado, la autorización del canal se deniega automáticamente y el callback de autorización nunca se ejecuta. Sin embargo, puede asignar múltiples guardias personalizados que deberían autenticar la solicitud entrante si es necesario:

Broadcast::channel('channel', function () {
    // ...
}, ['guards' => ['web', 'admin']]);

#Definiendo clases de canal

Si su aplicación consume muchos canales diferentes, su archivo routes/channels.php podría volverse pesado. Por lo tanto, en lugar de usar closures para autorizar canales, puede usar clases de canal. Para generar una clase de canal, use el comando Artisan make:channel. Este comando colocará una nueva clase de canal en el directorio App/Broadcasting.

php artisan make:channel OrderChannel

Luego, registre su canal en su archivo routes/channels.php:

use App\Broadcasting\OrderChannel;

Broadcast::channel('orders.{order}', OrderChannel::class);

Finalmente, puede colocar la lógica de autorización para su canal en el método join de la clase del canal. Este método join contendrá la misma lógica que normalmente habría colocado en su closure de autorización de canal. También puede aprovechar el enlace de modelo en canales:

<?php

namespace App\Broadcasting;

use App\Models\Order;
use App\Models\User;

class OrderChannel
{
    /**
     * Crear una nueva instancia del canal.
     */
    public function __construct()
    {
        // ...
    }

    /**
     * Autenticar el acceso del usuario al canal.
     */
    public function join(User $user, Order $order): array|bool
    {
        return $user->id === $order->user_id;
    }
}
Примечание

Como muchas otras clases en Laravel, las clases de canal serán resueltas automáticamente por el contenedor de servicios. Por lo tanto, puede indicar cualquier dependencia requerida por su canal en su constructor.

#Transmitiendo eventos

Una vez que haya definido un evento y lo haya marcado con la interfaz ShouldBroadcast, solo necesita disparar el evento usando el método dispatch del evento. El despachador de eventos notará que el evento está marcado con la interfaz ShouldBroadcast y pondrá el evento en cola para su transmisión:

use App\Events\OrderShipmentStatusUpdated;

OrderShipmentStatusUpdated::dispatch($order);

#Solo para otros

Al construir una aplicación que utiliza transmisión de eventos, puede que ocasionalmente necesite transmitir un evento a todos los suscriptores de un canal dado excepto al usuario actual. Puede lograr esto usando el helper broadcast y el método toOthers:

use App\Events\OrderShipmentStatusUpdated;

broadcast(new OrderShipmentStatusUpdated($update))->toOthers();

Para entender mejor cuándo puede querer usar el método toOthers, imaginemos una aplicación de lista de tareas donde un usuario puede crear una nueva tarea ingresando un nombre de tarea. Para crear una tarea, su aplicación podría hacer una solicitud a una URL /task que transmite la creación de la tarea y devuelve una representación JSON de la nueva tarea. Cuando su aplicación JavaScript recibe la respuesta del endpoint, podría insertar directamente la nueva tarea en su lista de tareas así:

axios.post('/task', task)
    .then((response) => {
        this.tasks.push(response.data);
    });

Sin embargo, recuerde que también transmitimos la creación de la tarea. Si su aplicación JavaScript también está escuchando este evento para agregar tareas a la lista, tendrá tareas duplicadas en su lista: una desde el endpoint y otra desde la transmisión. Puede resolver esto usando el método toOthers para indicar al broadcaster que no transmita el evento al usuario actual.

Внимание

Su evento debe usar el trait Illuminate\Broadcasting\InteractsWithSockets para poder llamar al método toOthers.

#Configuración

Cuando inicializa una instancia de Laravel Echo, se asigna un ID de socket a la conexión. Si está usando una instancia global de Axios para hacer solicitudes HTTP desde su aplicación JavaScript, el ID de socket se adjuntará automáticamente a cada solicitud saliente como un encabezado X-Socket-ID. Luego, cuando llame al método toOthers, Laravel extraerá el ID de socket del encabezado e indicará al broadcaster que no transmita a ninguna conexión con ese ID de socket.

Si no está usando una instancia global de Axios, deberá configurar manualmente su aplicación JavaScript para enviar el encabezado X-Socket-ID con todas las solicitudes salientes. Puede obtener el ID de socket usando el método Echo.socketId:

var socketId = Echo.socketId();

#Personalizando la conexión

Si su aplicación interactúa con múltiples conexiones de broadcast y desea transmitir un evento usando un broadcaster distinto al predeterminado, puede especificar a qué conexión enviar un evento usando el método via:

use App\Events\OrderShipmentStatusUpdated;

broadcast(new OrderShipmentStatusUpdated($update))->via('pusher');

Alternativamente, puede especificar la conexión de broadcast del evento llamando al método broadcastVia dentro del constructor del evento. Sin embargo, antes de hacerlo, debe asegurarse de que la clase del evento use el trait InteractsWithBroadcasting:

<?php

namespace App\Events;

use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithBroadcasting;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Queue\SerializesModels;

class OrderShipmentStatusUpdated implements ShouldBroadcast
{
    use InteractsWithBroadcasting;

    /**
     * Crear una nueva instancia del evento.
     */
    public function __construct()
    {
        $this->broadcastVia('pusher');
    }
}

#Recibiendo transmisiones

#Escuchando eventos

Una vez que haya instalado e instanciado Laravel Echo, estará listo para comenzar a escuchar eventos que se transmiten desde su aplicación Laravel. Primero, use el método channel para obtener una instancia de un canal, luego llame al método listen para escuchar un evento especificado:

Echo.channel(`orders.${this.order.id}`)
    .listen('OrderShipmentStatusUpdated', (e) => {
        console.log(e.order.name);
    });

Si desea escuchar eventos en un canal privado, use el método private en su lugar. Puede continuar encadenando llamadas al método listen para escuchar múltiples eventos en un solo canal:

Echo.private(`orders.${this.order.id}`)
    .listen(/* ... */)
    .listen(/* ... */)
    .listen(/* ... */);

#Dejar de escuchar eventos

Si desea dejar de escuchar un evento dado sin salir del canal, puede usar el método stopListening:

Echo.private(`orders.${this.order.id}`)
    .stopListening('OrderShipmentStatusUpdated')

#Salir de un canal

Para salir de un canal, puede llamar al método leaveChannel en su instancia de Echo:

Echo.leaveChannel(`orders.${this.order.id}`);

Si desea salir de un canal y también de sus canales privados y de presencia asociados, puede llamar al método leave:

Echo.leave(`orders.${this.order.id}`);

#Espacios de nombres

Probablemente haya notado en los ejemplos anteriores que no especificamos el espacio de nombres completo App\Events para las clases de eventos. Esto se debe a que Echo asumirá automáticamente que los eventos están ubicados en el espacio de nombres App\Events. Sin embargo, puede configurar el espacio de nombres raíz cuando instancie Echo pasando una opción de configuración namespace:

window.Echo = new Echo({
    broadcaster: 'pusher',
    // ...
    namespace: 'App.Other.Namespace'
});

Alternativamente, puede anteponer un . a las clases de eventos al suscribirse a ellas usando Echo. Esto le permitirá siempre especificar el nombre de clase completamente calificado:

Echo.channel('orders')
    .listen('.Namespace\\Event\\Class', (e) => {
        // ...
    });

#Canales de presencia

Los canales de presencia se basan en la seguridad de los canales privados mientras exponen la característica adicional de conocimiento sobre quién está suscrito al canal. Esto facilita construir funciones colaborativas poderosas, como notificar a los usuarios cuando otro usuario está viendo la misma página o listar los habitantes de una sala de chat.

#Autorizando canales de presencia

Todos los canales de presencia también son canales privados; por lo tanto, los usuarios deben estar autorizados para acceder a ellos. Sin embargo, al definir callbacks de autorización para canales de presencia, no debe devolver true si el usuario está autorizado para unirse al canal. En su lugar, debe devolver un arreglo de datos sobre el usuario.

Los datos devueltos por el callback de autorización estarán disponibles para los escuchas de eventos del canal de presencia en su aplicación JavaScript. Si el usuario no está autorizado para unirse al canal de presencia, debe devolver false o null:

use App\Models\User;

Broadcast::channel('chat.{roomId}', function (User $user, int $roomId) {
    if ($user->canJoinRoom($roomId)) {
        return ['id' => $user->id, 'name' => $user->name];
    }
});

#Uniéndose a canales de presencia

Para unirse a un canal de presencia, puede usar el método join de Echo. El método join devolverá una implementación de PresenceChannel que, además de exponer el método listen, le permite suscribirse a los eventos here, joining y leaving.

Echo.join(`chat.${roomId}`)
    .here((users) => {
        // ...
    })
    .joining((user) => {
        console.log(user.name);
    })
    .leaving((user) => {
        console.log(user.name);
    })
    .error((error) => {
        console.error(error);
    });

El callback here se ejecutará inmediatamente una vez que el canal se haya unido con éxito, y recibirá un arreglo con la información de usuario de todos los demás usuarios actualmente suscritos al canal. El método joining se ejecutará cuando un nuevo usuario se una a un canal, mientras que el método leaving se ejecutará cuando un usuario salga del canal. El método error se ejecutará cuando el endpoint de autenticación devuelva un código de estado HTTP distinto de 200 o si hay un problema al analizar el JSON devuelto.

#Transmitiendo a canales de presencia

Los canales de presencia pueden recibir eventos igual que los canales públicos o privados. Usando el ejemplo de una sala de chat, podemos querer transmitir eventos NewMessage al canal de presencia de la sala. Para hacerlo, devolveremos una instancia de PresenceChannel desde el método broadcastOn del evento:

/**
 * Obtener los canales en los que el evento debe transmitirse.
 *
 * @return array<int, \Illuminate\Broadcasting\Channel>
 */
public function broadcastOn(): array
{
    return [
        new PresenceChannel('chat.'.$this->message->room_id),
    ];
}

Como con otros eventos, puede usar el helper broadcast y el método toOthers para excluir al usuario actual de recibir la transmisión:

broadcast(new NewMessage($message));

broadcast(new NewMessage($message))->toOthers();

Como es típico en otros tipos de eventos, puede escuchar eventos enviados a canales de presencia usando el método listen de Echo:

Echo.join(`chat.${roomId}`)
    .here(/* ... */)
    .joining(/* ... */)
    .leaving(/* ... */)
    .listen('NewMessage', (e) => {
        // ...
    });

#Transmisión de modelos

Внимание

Antes de leer la siguiente documentación sobre transmisión de modelos, le recomendamos familiarizarse con los conceptos generales de los servicios de transmisión de modelos de Laravel, así como cómo crear y escuchar eventos de broadcast manualmente.

Es común transmitir eventos cuando los modelos Eloquent de su aplicación son creados, actualizados o eliminados. Por supuesto, esto se puede lograr fácilmente definiendo manualmente eventos personalizados para cambios de estado de modelos Eloquent y marcando esos eventos con la interfaz ShouldBroadcast.

Sin embargo, si no está usando estos eventos para otros propósitos en su aplicación, puede ser engorroso crear clases de eventos solo para transmitirlos. Para solucionar esto, Laravel le permite indicar que un modelo Eloquent debe transmitir automáticamente sus cambios de estado.

Para comenzar, su modelo Eloquent debe usar el trait Illuminate\Database\Eloquent\BroadcastsEvents. Además, el modelo debe definir un método broadcastOn, que devolverá un arreglo de canales en los que los eventos del modelo deben transmitirse:

<?php

namespace App\Models;

use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Database\Eloquent\BroadcastsEvents;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;

class Post extends Model
{
    use BroadcastsEvents, HasFactory;

    /**
     * Obtener el usuario al que pertenece el post.
     */
    public function user(): BelongsTo
    {
        return $this->belongsTo(User::class);
    }

    /**
     * Obtener los canales en los que los eventos del modelo deben transmitirse.
     *
     * @return array<int, \Illuminate\Broadcasting\Channel|\Illuminate\Database\Eloquent\Model>
     */
    public function broadcastOn(string $event): array
    {
        return [$this, $this->user];
    }
}

Una vez que su modelo incluya este trait y defina sus canales de transmisión, comenzará a transmitir automáticamente eventos cuando una instancia del modelo sea creada, actualizada, eliminada, enviada a la papelera o restaurada.

Además, puede haber notado que el método broadcastOn recibe un argumento string $event. Este argumento contiene el tipo de evento que ha ocurrido en el modelo y tendrá un valor de created, updated, deleted, trashed o restored. Al inspeccionar el valor de esta variable, puede determinar a qué canales (si los hay) el modelo debe transmitir para un evento particular:

/**
 * Obtener los canales en los que los eventos del modelo deben transmitirse.
 *
 * @return array<string, array<int, \Illuminate\Broadcasting\Channel|\Illuminate\Database\Eloquent\Model>>
 */
public function broadcastOn(string $event): array
{
    return match ($event) {
        'deleted' => [],
        default => [$this, $this->user],
    };
}

#Personalizando la creación de eventos de transmisión de modelos

Ocasionalmente, puede desear personalizar cómo Laravel crea el evento subyacente de transmisión de modelo. Puede lograr esto definiendo un método newBroadcastableEvent en su modelo Eloquent. Este método debe devolver una instancia de Illuminate\Database\Eloquent\BroadcastableModelEventOccurred:

use Illuminate\Database\Eloquent\BroadcastableModelEventOccurred;

/**
 * Crear un nuevo evento de modelo transmisible para el modelo.
 */
protected function newBroadcastableEvent(string $event): BroadcastableModelEventOccurred
{
    return (new BroadcastableModelEventOccurred(
        $this, $event
    ))->dontBroadcastToCurrentUser();
}

#Convenciones de transmisión de modelos

#Convenciones de canales

Como habrá notado, el método broadcastOn en el ejemplo del modelo anterior no devolvió instancias de Channel. En cambio, se devolvieron modelos Eloquent directamente. Si una instancia de modelo Eloquent es devuelta por el método broadcastOn de su modelo (o está contenida en un arreglo devuelto por el método), Laravel instanciará automáticamente una instancia de canal privado para el modelo usando el nombre de la clase del modelo y el identificador de clave primaria como nombre del canal.

Así, un modelo App\Models\User con un id de 1 se convertiría en una instancia de Illuminate\Broadcasting\PrivateChannel con un nombre App.Models.User.1. Por supuesto, además de devolver instancias de modelos Eloquent desde el método broadcastOn de su modelo, puede devolver instancias completas de Channel para tener control total sobre los nombres de canal del modelo:

use Illuminate\Broadcasting\PrivateChannel;

/**
 * Obtener los canales en los que los eventos del modelo deben transmitirse.
 *
 * @return array<int, \Illuminate\Broadcasting\Channel>
 */
public function broadcastOn(string $event): array
{
    return [
        new PrivateChannel('user.'.$this->id)
    ];
}

Si planea devolver explícitamente una instancia de canal desde el método broadcastOn de su modelo, puede pasar una instancia de modelo Eloquent al constructor del canal. Al hacerlo, Laravel usará las convenciones de canal de modelo mencionadas arriba para convertir el modelo Eloquent en un nombre de canal string:

return [new Channel($this->user)];

Si necesita determinar el nombre del canal de un modelo, puede llamar al método broadcastChannel en cualquier instancia de modelo. Por ejemplo, este método devuelve el string App.Models.User.1 para un modelo App\Models\User con un id de 1:

$user->broadcastChannel()

#Convenciones de eventos

Dado que los eventos de transmisión de modelos no están asociados con un evento "real" dentro del directorio App\Events de su aplicación, se les asigna un nombre y una carga útil basados en convenciones. La convención de Laravel es transmitir el evento usando el nombre de la clase del modelo (sin incluir el espacio de nombres) y el nombre del evento del modelo que disparó la transmisión.

Así, por ejemplo, una actualización al modelo App\Models\Post transmitiría un evento a su aplicación del lado cliente como PostUpdated con la siguiente carga útil:

{
    "model": {
        "id": 1,
        "title": "My first post"
        ...
    },
    ...
    "socket": "someSocketId",
}

La eliminación del modelo App\Models\User transmitiría un evento llamado UserDeleted.

Si lo desea, puede definir un nombre de transmisión personalizado y una carga útil agregando un método broadcastAs y broadcastWith a su modelo. Estos métodos reciben el nombre del evento/operación del modelo que está ocurriendo, permitiéndole personalizar el nombre y la carga útil del evento para cada operación del modelo. Si el método broadcastAs devuelve null, Laravel usará las convenciones de nombres de eventos de transmisión de modelos mencionadas arriba al transmitir el evento:

/**
 * El nombre de transmisión del evento del modelo.
 */
public function broadcastAs(string $event): string|null
{
    return match ($event) {
        'created' => 'post.created',
        default => null,
    };
}

/**
 * Obtener los datos para transmitir del modelo.
 *
 * @return array<string, mixed>
 */
public function broadcastWith(string $event): array
{
    return match ($event) {
        'created' => ['title' => $this->title],
        default => ['model' => $this],
    };
}

#Escuchando transmisiones de modelos

Una vez que haya agregado el trait BroadcastsEvents a su modelo y definido el método broadcastOn de su modelo, estará listo para comenzar a escuchar eventos de modelo transmitidos dentro de su aplicación del lado cliente. Antes de comenzar, puede consultar la documentación completa sobre escuchar eventos.

Primero, use el método private para obtener una instancia de un canal, luego llame al método listen para escuchar un evento especificado. Normalmente, el nombre del canal dado al método private debería corresponder a las convenciones de transmisión de modelos de Laravel.

Una vez que haya obtenido una instancia de canal, puede usar el método listen para escuchar un evento en particular. Dado que los eventos de transmisión de modelos no están asociados con un evento "real" dentro del directorio App\Events de su aplicación, el nombre del evento debe tener un prefijo . para indicar que no pertenece a un espacio de nombres específico. Cada evento de transmisión de modelo tiene una propiedad model que contiene todas las propiedades transmitibles del modelo:

Echo.private(`App.Models.User.${this.user.id}`)
    .listen('.PostUpdated', (e) => {
        console.log(e.model);
    });

#Eventos del cliente

Примечание

Al usar Pusher Channels, debe habilitar la opción "Client Events" en la sección "App Settings" de su panel de control de la aplicación para poder enviar eventos del cliente.

A veces puede desear transmitir un evento a otros clientes conectados sin pasar por su aplicación Laravel. Esto puede ser especialmente útil para cosas como notificaciones de "escribiendo", donde quiere alertar a los usuarios de su aplicación que otro usuario está escribiendo un mensaje en una pantalla determinada.

Para transmitir eventos del cliente, puede usar el método whisper de Echo:

Echo.private(`chat.${roomId}`)
    .whisper('typing', {
        name: this.user.name
    });

Para escuchar eventos del cliente, puede usar el método listenForWhisper:

Echo.private(`chat.${roomId}`)
    .listenForWhisper('typing', (e) => {
        console.log(e.name);
    });

#Notificaciones

Al combinar la transmisión de eventos con las notificaciones, su aplicación JavaScript puede recibir nuevas notificaciones a medida que ocurren sin necesidad de actualizar la página. Antes de comenzar, asegúrese de leer la documentación sobre el uso del canal de notificaciones por broadcast.

Una vez que haya configurado una notificación para usar el canal de broadcast, puede escuchar los eventos de transmisión usando el método notification de Echo. Recuerde, el nombre del canal debe coincidir con el nombre de la clase de la entidad que recibe las notificaciones:

Echo.private(`App.Models.User.${userId}`)
    .notification((notification) => {
        console.log(notification.type);
    });

En este ejemplo, todas las notificaciones enviadas a instancias de App\Models\User a través del canal broadcast serían recibidas por el callback. Un callback de autorización de canal para el canal App.Models.User.{id} está incluido en el BroadcastServiceProvider predeterminado que viene con el framework Laravel.