Latest News

首頁 » Laravel 實作 Event & Pusher篇

Laravel 實作 Event & Pusher篇

Pusher 官網:
為移動裝置和網路提供實時體驗
靈活、可擴展且易於使用的雙向託管 API。
我們建立並維護複雜的訊息傳遞基礎設施,以便您可以快速構建使用者所需的實時功能。

Pusher 所提供的服務介紹:

我們所熟知的Http server-client架構一向都是由client向server發送請求,server再吐回對應的內容。
那假如今天我們希望能在server資料庫被更動時立即通知client端,即時更新使用者介面,除了client端不斷的輪詢來取得後端資料外,是否有更高端、有效率的方式?
我們可以透過WebSocket實作上述的功能,Laravel中的BroadCast支援Redis和Pusher這兩個服務,而這篇文章會示範如何透過簡單的pusher來完成主動發送事件內容到前端畫面

event

第一步:註冊eventServiceProvider到Laravel Container中

先在eventServiceProvider中加入

        'App\Events\Event名稱' => [
                'App\Listeners\Event名稱',
        ],

範例–新增食物:

 'App\Events\FoodAdded' => [
            'App\Listeners\FoodAddedListener',
        ],

接著用artisan產生event $php artisan event:generate

第二步:撰寫event內容

event class裡描述的是該事件的內容,事件如何才會被觸發則是在controller中被定義
範例是新增食物主動推播到訂閱指定餐廳的頻道的事件
專案目錄下的app/Event/FoodAdded.php

<?php

namespace App\Events;

//加入會用到的model
use App\Food;
use App\Restaurant;

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 FoodAdded implements ShouldBroadcast //若是主動發送推播通知的事件,這邊要改成ShouldBroadcast
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

    public $restaurant;
    public $food;
    public $class = 'food added';

    /**
     * Create a new event instance.
     *
     * @return void
     */
    public function __construct(Food $food)
    {   //這邊描述的是推播通知的內容
        $this->food = $food;
        $this->restaurant = Restaurant::find($food->restaurant_id);
    }

    /**
     * Get the channels the event should broadcast on.
     *
     * @return \Illuminate\Broadcasting\Channel|array
     */
    public function broadcastOn()
    {
        //定義新增食物的通知只會發送到指定的餐廳
        return ['food-channel.'.$this->restaurant->id];

    }
    public function broadcastAs()
    {
        //命名推播的事件
        return 'food-event';

    }
}

FoodController.php

function store(Request $request)
    {
    //...
       $food = Food::create([
                'name' => $request->name,
                'remaining' => $request->remaining,
                'original_price' => $request->original_price,
                'discounted_price' => $request->discounted_price,
                'image' => $parameters['image'],
                'restaurant_id' => $request->restaurant_id,
            ]);
        //每當該餐廳有食物上架時,會觸發FoodAdded事件,發送推播通知訂閱該餐廳的頻道
        event(new FoodAdded($food));
        return response()->json($food, 200);
    }

Pusher

此範例用Pusher來實作推播通知
首先要在專案目錄下安裝pusher套件 composer require pusher/pusher-php-server
接著更改.env內容:

BROADCAST_DRIVER=pusher

//以下欄位要先去pusher官網申請一組專案,申請完後即可在官網拿到以下四個欄位

PUSHER_APP_ID='你的pusher app id'
PUSHER_APP_KEY='你的pusher app key'
PUSHER_APP_SECRET='你的pusher app secret'
PUSHER_APP_CLUSTER='你的pusher app cluster'

MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"

我寫的是後端api,要怎麼知道推播通知有沒有成功?

Pusher官網有提供一個簡單的blade範例來檢查自己寫的推播通知事件是否能成功發送


<!DOCTYPE html>
<head>
    <title>New Food Pusher Test</title>
    <script src="https://js.pusher.com/5.1/pusher.min.js"></script>
    <script>
        var restaurant_id = 2; //測試2號餐廳食物上架時能不能收到主動發送的通知
        // Enable pusher logging - don't include this in production
        Pusher.logToConsole = true;

        var pusher = new Pusher('{{env('MIX_PUSHER_APP_KEY')}}', {
            cluster: '{{env('MIX_PUSHER_APP_CLUSTER')}}',
            forceTLS: true
        });

        var channel = pusher.subscribe('food-channel.'+restaurant_id);
        channel.bind('food-event', function(data) {
            console.log('Pusher');
            alert(JSON.stringify(data));
        });


    </script>
</head>
<body>
<h1>New Food Pusher Test</h1>
<p>
    Try publishing an event to channel <code>food-channel+restaurant_id</code>
    with event name <code>food-event</code>.
    <script>

    </script>
</p>
</body>

遇到的issue

  1. 瀏覽器的console:
pusher.min.js:8 Pusher : : [{"type":"WebSocketError","error":{"type":"PusherError","data":{"code":4005,"message":"Path not found"}}}]

Solution:
.env要加上

MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"

2.前端看不到pusher該顯示的資料
Solution:檢查 .env

BROADCAST_DRIVER=pusher

【網路技術密訓基地】莫忘記初衷! (堅持!直到成功!)

【洪總教頭】曾說:過去的理念已經實現的叫做:【成就】,而還未實現的就叫:【夢想】!我們從來沒因已有的【成就】而放棄【夢想】!
唯有你我知道的秘密,就不可能到處去說給別人聽,因為:到處宣揚的就不叫做【密技】!

E-Mail:ster168ster@gmail.com