Skip to content

Broadcasting

Giới thiệu (Introduction)

Trong nhiều ứng dụng web hiện đại, WebSockets được sử dụng để xây dựng giao diện cập nhật theo thời gian thực (realtime). Khi dữ liệu thay đổi trên server, message được gửi qua WebSocket connection để client xử lý — hiệu quả hơn nhiều so với polling liên tục.

Laravel giúp "broadcast" (phát sóng) server-side events qua WebSocket connection dễ dàng, cho phép chia sẻ cùng event names và data giữa server-side và client-side JavaScript.

Drivers hỗ trợ

Laravel bao gồm 3 server-side broadcasting drivers:

DriverMô tả
Laravel ReverbWebSocket server tích hợp sẵn cho Laravel
Pusher ChannelsDịch vụ WebSocket hosted
AblyNền tảng realtime messaging

Cài đặt nhanh (Quickstart)

Server Side

Cài đặt và cấu hình broadcasting channel:

bash
php artisan install:broadcasting

Client Side

Cài đặt Laravel Echo — JavaScript library lắng nghe events:

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

Tổng quan khái niệm (Concept Overview)

Broadcasting Laravel cho phép broadcast server-side events đến client-side JavaScript application qua cách tiếp cận driver-based. Events phát sóng qua channels:

  • Public channels: Bất kỳ visitor nào đều có thể subscribe
  • Private channels: User phải authenticated và authorized
  • Presence channels: Kênh private, thêm khả năng biết ai đang online

Luồng hoạt động

  1. User thực hiện action (ví dụ: tạo đơn hàng)
  2. Server fire event implement ShouldBroadcast
  3. Event được broadcast qua WebSocket driver
  4. Client-side JavaScript (Echo) nhận và xử lý event

Cấu hình Reverb

Reverb là WebSocket server của chính Laravel:

bash
php artisan install:broadcasting

Cấu hình trong .env:

env
BROADCAST_CONNECTION=reverb
REVERB_APP_ID=my-app-id
REVERB_APP_KEY=my-app-key
REVERB_APP_SECRET=my-app-secret

Khởi động Reverb server:

bash
php artisan reverb:start

Client-Side với Reverb

js
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 ?? 80,
    wssPort: import.meta.env.VITE_REVERB_PORT ?? 443,
    forceTLS: (import.meta.env.VITE_REVERB_SCHEME ?? 'https') === 'https',
    enabledTransports: ['ws', 'wss'],
});

Định nghĩa Broadcast Events

Implement interface ShouldBroadcast trong event class:

php
<?php

namespace App\Events;

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

class ServerCreated implements ShouldBroadcast
{
    use SerializesModels;

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

    /**
     * Channels mà event broadcast.
     */
    public function broadcastOn(): array
    {
        return [
            new PrivateChannel('user.'.$this->user->id),
        ];
    }
}

Broadcast Name

Mặc định dùng tên class. Tùy chỉnh:

php
public function broadcastAs(): string
{
    return 'server.created';
}

Broadcast Data

php
public function broadcastWith(): array
{
    return ['id' => $this->user->id];
}

Broadcast Queue

php
public $connection = 'sqs';
public $queue = 'broadcasting';

Authorizing Channels (Xác thực Channels)

Private và Presence channels yêu cầu authorization. Định nghĩa trong routes/channels.php:

php
use Illuminate\Support\Facades\Broadcast;

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

Broadcasting Events

Fire event như bình thường:

php
use App\Events\OrderShipmentStatusUpdated;

OrderShipmentStatusUpdated::dispatch($order);

Only to Others

Khi user trigger action, broadcast đến mọi người trừ user hiện tại:

php
broadcast(new ShippingStatusUpdated($update))->toOthers();

Anonymous Events

Broadcast events không cần tạo event class:

php
use Illuminate\Broadcasting\Channel;

Broadcast::on(new Channel('orders'))->send(['status' => 'shipped']);

Nhận Broadcasts (Receiving Broadcasts)

Lắng nghe Events

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

Private Channels

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

Presence Channels

Biết ai đang online:

js
Echo.join(`chat.${roomId}`)
    .here((users) => {
        // Danh sách users online...
    })
    .joining((user) => {
        // User mới tham gia...
    })
    .leaving((user) => {
        // User rời đi...
    });

Client Events

Gửi events từ client (không phải server):

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

Lắng nghe client events:

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

Notifications

Kết hợp với Notifications — broadcast notifications đến JavaScript:

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