Hướng dẫn xử lý realtime trong laravel

Chào các bạn, như các bạn đã biết các vấn đề xử lý realtime trên website ngày nay càng phổ biến. Hầu hết những người mới lập trình thường gặp phải nhiều khó khăn cho vấn đề trên và không biết xử lý như thế nào thì hôm nay mình xin chia sẻ đến mọi người một cách xử lý realtime trên ứng dụng web của mình.
Bài viết dưới trình bày cách xử lý realtime trong laravel

Nội dung bài viết gồm các phần:

  • Giới thiệu
  • Cấu hình các thư viện và kết nối với pusher
  • Xử lý logic
  • Kết quả

1. Giới thiệu

Hiện nay có rất nhiều cách để xử lý realtime trong laravel như tạo một server nodejs kết hợp cùng với laravel nhưng cách này rất khó xử lý đối với các bạn mới học lập trình, vậy giải tối ưu nhất cho các bạn mới học là gì? Đó là sử dụng dịch vụ của bên thứ 3 như Firebase, Pusher,... Trong bài này mình sẽ hướng dẫn các bạn sử dụng Pusher làm server trung gian để xử lý kết nối realtime. Lí do mình sử dụng Pusher là vì do trong laravel đã được tích hợp sẵn một số config và thư viện cần thiết để kết nối với Pusher.

Đến đây cũng nhiều bạn thắc mắc Pusher là gì?, tại sao nó lại có thể xử lý được vấn đề realtime trên website. Pusher là một dịch vụ bên thứ 3 hay nó như là một server trung gian có thể xử lý các tác vụ thời gian thực thông qua kết nối http socket, các dữ liệu từ ứng dụng của bạn sẽ được đẩy lên Pusher rồi Pusher sẽ phân phối các thông tin cho người dùng dựa vào các kênh mà bạn đã chỉ định trên ứng dụng của mình.

2. Cấu hình các thư viện và kết nối với Pusher

  • Khởi tạo project laravel
composer create-project laravel/laravel [Tên project của các bạn]
  • Cài đặt các gói thư viện mặc định trong laravel và pusher
composer install && composer require pusher/pusher-php-server
  • Cài đặt các thư viện javascript và pusher js
npm install && npm install --save laravel-echo pusher-js
  • Lên Pusher đăng kí môt app để làm server trung gian (https://pusher.com/)

    Sau khi đăng kí xong các bạn sẽ nhận được các thông tin kết nối app_id, key, secret, cluster

    Rồi điền thông tin vào trong file .env trong project của các bạn
PUSHER_APP_ID= [app_id]
PUSHER_APP_KEY= [key]
PUSHER_APP_SECRET= [secret]
PUSHER_APP_CLUSTER= [cluster]
BROADCAST_DRIVER=log (chuyển thành) BROADCAST_DRIVER=pusher
  • Tiếp theo các bạn vào file bootrap.js bỏ comment các dòng
// import Echo from 'laravel-echo';

// window.Pusher = require('pusher-js');

// window.Echo = new Echo({
//     broadcaster: 'pusher',
//     key: process.env.MIX_PUSHER_APP_KEY,
//     cluster: process.env.MIX_PUSHER_APP_CLUSTER,
//     forceTLS: true
// });
  • Cuối cùng các bạn vào file broadcasting.php tìm đến phần providersbỏ comment dòng //App\Providers\BroadcastServiceProvider::class,
    Tìm đến phần aliases thêm 'Pusher' => Pusher\Pusher::class,

Cuối cùng cũng xong phần cấu hình, hơi nhiều đúng không các bạn ;)). Tiếp đến chúng ta sẽ xử ly phần logic, ở đây mình xây dựng một ví dụ đơn giản về gửi thông báo realtime cho tất cả mọi người trong ứng dụng web.

3. Sử lí logic

  • Tạo database và một table có tên là: blogs (gồm 2 cột id và content)
php artisan make:migration create_blogs_table
  • Tạo môt model và controller
php artisan make:model Blog --controller
  • Tạo một event để có thể đăng kí các Channel có thể gửi thông tin cho Pusher
php artisan make:event BlogPusherEvent
  • Định nghĩa các route và viết code Controller, BlogPusherEvent

Route

//routes\web.php

Route::post('send-message', 'BlogController@sendMessage')->name('send.message');
Route::get('get-message', 'BlogController@getMessage')->name('get.message');

BlogController

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Models\Blog;

class BlogController extends Controller
{
    public function sendMessage(Request $request) {
        $content = $request->content;
        Blog::create(['content' => $content]);
        event(new BlogPusherEvent($content));
        return redirect()->back()->with(['success' => 'Bạn đã tạo thông báo thành công']);
    }

    public function createMessage () {
        return view('create_message');
    }

    public function getMessage() {
        return view('room');
    }
}

BlogPusherEvent

<?php

namespace App\Events;

use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Contracts\Broadcasting\ShouldBroadcastNow;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;

class BlogPusherEvent implements ShouldBroadcastNow
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

    public $message;

    /**
     * Create a new event instance.
     *
     * @return void
     */
    public function __construct($message)
    {
        $this->message = $message;
    }

    /**
     * Get the channels the event should broadcast on.
     *
     * @return \Illuminate\Broadcasting\Channel|array
     */
    public function broadcastOn()
    {
        return new Channel('notify-channel');
    }
}

Chú ý: có 3 loại channel là: Channel(public channel), PresenceChannel, PrivateChannel. Ở đây mình dùng Public Channel do mình gửi thông tin cho tất cả mọi người nên mình chỉ cần dùng public channer là đủ.

View send message

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        form {
            padding: 15px;
            display: flex;
            width: 575px;
            background: whitesmoke;
            justify-content: space-between;
            align-items: center;
        }

        textarea {
            border-radius: 5px;
        }
    </style>
</head>
<body>
    @if(Session::has('success'))
        <h4>
            {{ session('success') }}
        </h4>
    @endif
    <form action="{{ route('send.message') }} " method="POST">
        @csrf
        <label for="">Tạo thông báo:</label>
        <textarea type="text" name="content" rows="5" cols="50"></textarea>
        <input type="submit" value="Gửi">
    </form>
</body>
</html>

View user

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="{{ asset('js/app.js') }}"></script>
    <style>
        h5 {
            background: rgb(51, 198, 243)
        }
    </style>
</head>
<body>
    <h1>Demo pusher trong laravel</h1>
</body>
<script type="text/javascript">
    window.onload = function () {
        var pusher = new Pusher("[YOUR_KEY_PUSHER]", {
                cluster: 'ap1',
                encrypted: true
        });
        var channel = pusher.subscribe('notify-channel');
        channel.bind('App\\Events\\BlogPusherEvent', function (data) {
            let message = data.message;
            $('body').prepend(`<h5>${message}</h5>`);
        });
    }
</script>
</html>

4. Kết quả

Tạo thông báo

![](/content/images/2021/08/create-1.png)
*Gửi thành công*
![](/content/images/2021/08/fuk.png)
*Thông tin được gửi lên Pusher*
![](/content/images/2021/08/pusher-1.png)
*Hiện thị thông báo mọi người*
![](/content/images/2021/08/success-1.png)
![]()