⚙️

Cài Đặt Broadcasting

Cấu hình Pusher

# Cài đặt dependencies
composer require pusher/pusher-php-server

# Frontend
npm install --save-dev laravel-echo pusher-js
<?php
// .env
BROADCAST_DRIVER=pusher
PUSHER_APP_ID=your-app-id
PUSHER_APP_KEY=your-app-key
PUSHER_APP_SECRET=your-secret
PUSHER_APP_CLUSTER=ap1

// config/broadcasting.php
'pusher' => [
    'driver' => 'pusher',
    'key' => env('PUSHER_APP_KEY'),
    'secret' => env('PUSHER_APP_SECRET'),
    'app_id' => env('PUSHER_APP_ID'),
    'options' => [
        'cluster' => env('PUSHER_APP_CLUSTER'),
        'useTLS' => true,
    ],
],

Laravel Echo (Frontend)

// resources/js/bootstrap.js

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
});

// Lắng nghe public channel
Echo.channel('orders')
    .listen('OrderShipped', (e) => {
        console.log('Order shipped:', e.order);
    });

// Private channel (requires auth)
Echo.private(`orders.${userId}`)
    .listen('OrderStatusChanged', (e) => {
        console.log('Your order:', e.order.status);
    });

// Presence channel (who's online)
Echo.join(`chat.${roomId}`)
    .here((users) => {
        console.log('Users in room:', users);
    })
    .joining((user) => {
        console.log('User joined:', user.name);
    })
    .leaving((user) => {
        console.log('User left:', user.name);
    })
    .listen('MessageSent', (e) => {
        console.log('New message:', e.message);
    });
📡

Broadcast Events

Tạo Broadcast Event

<?php
// app/Events/MessageSent.php

namespace App\Events;

use App\Models\Message;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;

class MessageSent implements ShouldBroadcast
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

    public function __construct(
        public Message $message
    ) {}

    // Public channel - ai cũng nghe được
    public function broadcastOn(): Channel
    {
        return new Channel('chat');
    }

    // Private channel - cần auth
    public function broadcastOn(): PrivateChannel
    {
        return new PrivateChannel('chat.' . $this->message->room_id);
    }

    // Presence channel - biết ai online
    public function broadcastOn(): PresenceChannel
    {
        return new PresenceChannel('chat.' . $this->message->room_id);
    }

    // Customize broadcast data
    public function broadcastWith(): array
    {
        return [
            'id' => $this->message->id,
            'content' => $this->message->content,
            'user' => [
                'id' => $this->message->user->id,
                'name' => $this->message->user->name,
            ],
            'created_at' => $this->message->created_at->toIso8601String(),
        ];
    }

    // Custom event name
    public function broadcastAs(): string
    {
        return 'message.sent';
    }
}

// routes/channels.php - Authorization
Broadcast::channel('chat.{roomId}', function ($user, $roomId) {
    return $user->rooms()->where('id', $roomId)->exists();
});

// Dispatch
broadcast(new MessageSent($message));
💡 Best Practice: Dùng broadcastWith() để kiểm soát data gửi đi, tránh expose sensitive data.
← Bài 6: Events Bài 8: Reverb →