web-dev-qa-db-ja.com

Laravel socket-ioのイベント[通知の受信]

laravelと_socket-io_を使用した初めての試みで、管理者に非常に簡単な通知を送信しようとしています。 これまでのところイベントは発生していますが、イベント通知の受信についてサポートが必要です

論理

プロセスを理解したいので、とても基本的です。

  1. ユーザーがページを開く_Add Product_
  2. 管理者は、_user X_が_App Product_ページにあるという通知を受け取ります。

これまでのところ

これまでのところ、イベントを発生させてユーザーデータを取得できます(_Add Product_ページにあるユーザー)

助けが必要

管理者が通知を受け取る方法を理解するのに助けが必要です。

コード

コンポーネントスクリプト

_created() {
  let user = JSON.parse(localStorage.getItem("user"))
  this.listenForBroadcast(user);
},
methods: {
  listenForBroadcast(user) {
    Echo.join('userInAddProduct')
    .here((Loggeduser) => {
      console.log('My user data', Loggeduser);
    });
  }
}
_

上記のコードの結果

_My user data [{…}]
  0:
    id: 1
    name: "Test User"
    photo: "User-1588137335.png"
    __ob__: Observer {value: {…}, dep: Dep, vmCount: 0}
    get id: ƒ reactiveGetter()
    set id: ƒ reactiveSetter(newVal)
    get name: ƒ reactiveGetter()
    set name: ƒ reactiveSetter(newVal)
    get photo: ƒ reactiveGetter()
    set photo: ƒ reactiveSetter(newVal)
    __proto__: Object
    length: 1
    __proto__: Array(0)
_

チャンネルルート

_Broadcast::channel('userInAddProduct', function ($user) {
    return [
        'id' => $user->id,
        'photo' => $user->photo,
        'name' => $user->name
    ];
});
_

MessagePushed(イベントファイル)

_class MessagePushed implements ShouldBroadcast
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

    public $user;

    public function __construct(User $user)
    {
        $this->user = $user;
    }

    public function broadcastOn()
    {
        return new PresenceChannel('userInAddProduct');
    }
}
_

質問

このイベントの火災に関する通知を受け取るにはどうすればよいですか? _user x_がページ_Add Product_にあることを管理者ユーザーに通知しますか?

更新

この質問を公開してから、いくつか変更を加えました。ここに、最新のコードと質問があります。

_bootstrap.js_

_window.io = require('socket.io-client');

window.Echo = new Echo({
    broadcaster: 'socket.io',
    Host: window.location.hostname + ':6001',
    auth: { // added authentication token (because all my events are private)
        headers: {
            Authorization: localStorage.getItem('access_token'),
        },
    },
});
_

Add.vue (add product component where event has to be fired)

_listenForBroadcast(user) {
    let ui = JSON.parse(localStorage.getItem("user"))
    Echo.join('userInAddProduct')
    .here((users) => {
        console.log('My user data', users)
    })
    .joining((user) => {
        this.$notify({
            title: '',
            message: user + 'joining',
            offset: 100,
            type: 'success'
        });
    })
    .leaving((user) => {
        this.$notify({
            title: '',
            message: user + 'is leaving new product',
            offset: 100,
            type: 'warning'
        });
    })
    .whisper('typing', (e) => {
        this.$notify({
            title: '',
            message: ui.username + 'is adding new product',
            offset: 100,
            type: 'success'
        })
    })
    .listenForWhisper('typing', (e) => {
        console.log(e)
        this.$notify({
            title: '',
            message: ui.username + 'is entered add new product page.',
            offset: 100,
            type: 'success'
        });
    })
    .notification((notification) => {
        console.log('noitication listener: ', notification.type);
    });
},
_

次に、イベントを処理するために4つのファイルを作成しました。

  • イベント(_passing data_)
  • イベントリスナー(_process the database storage_および_showing notifications_からオンライン管理者へ)
  • オブザーバー(発砲イベント)
  • 通知(_store data to database_管理者は、イベントが発生したときにオンラインではないため、後で通知を表示できます)

_Event file_

_class MessagePushed extends Event implements ShouldBroadcast
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

    public $user;
    public $product;

    public function __construct(User $user, Product $product)
    {
        $this->user = $user;
        $this->product = $product;
    }

    public function broadcastOn()
    {
        return new PresenceChannel('userInAddProduct');
    }
}
_

_Listener file_

_class ThingToDoAfterEventWasFired implements ShouldQueue
{
    public function handle(MessagePushed $event)
    {
        //Log testing purpose only
        $user = $event->user->username;
        $product = $event->product->name;

        // Real data that should be broadcasts
        $user2 = $event->user;
        $product2 = $event->product;

        // inform all admins and authorized staffs about new product
        $admins = User::role(['admin', 'staff'])->get();
        foreach($admins as $admin) {
            $admin->notify(new UserAddProduct($user2, $product2));
        }

        Log::info("Product $product was Created, by worker: $user");
    }
}
_

Notification

_class UserAddProduct extends Notification implements ShouldQueue
{
    use Queueable;

    protected $product;
    protected $user;

    public function __construct(User $user, Product $product)
    {
        $this->product = $product;
        $this->user = $user;
    }

    public function via($notifiable)
    {
        return ['database', 'broadcast'];
    }

    public function toDatabase($notifiable)
    {
        return [
            'user_id' => $this->user->id,
            'user_username' => $this->user->username,
            'product_id' => $this->product->id,
            'product_name' => $this->product->name,
        ];
    }

    public function toArray($notifiable)
    {
        return [
            'id' => $this->id,
            'read_at' => null,
            'data' => [
                'user_id' => $this->user->id,
                'user_username' => $this->user->username,
                'product_id' => $this->product->id,
                'product_name' => $this->product->name,
            ],
        ];
    }
}
_

Observer

_public function created(Product $product)
{
    $user = Auth::user();
    event(new MessagePushed($user, $product));
}
_

ご質問

  1. イベントが発生したらすぐにライブ通知を返すにはどうすればよいですかアプリ全体?現在、私のコードは_add.vue component admins get notify IF they are in same page only :/_に配置されています
  2. 複数のイベントの通知を受け取るにはどうすればよいですか?アプリ全体で_event, listener, observer_と_product event_の両方が管理者に通知されるようにしたい場合、他のページアクション用に別の_other event_があるとします。

ありがとう

6
mafortis

解決した

これが私のニーズと私の質問に基づいて私がそれをどのようにしたかです(あなたのケースが私のものと異なる場合、それはどういうわけか異なるかもしれません)

アクティビティが発生するコンポーネント(私の場合Add.vue

Echo.join('userInAddProduct')
.here((users) => {
    console.log('here: ', users);
})
.joining((user) => {
    console.log('joining: ', user);
})
.leaving((user) => {
    console.log('leaving: ', user);
})
.whisper('typing', {data: notf}) // this part sends my data
.notification((notification) => {
    console.log('noitication listener1: ', notification.type);
});

管理者のすべてのページで通知を表示する必要があるので、ソケットエミットを追加しました(つまり、Echo.listenForWhisper)をnavbarコンポーネントに追加します。

mounted() {
  this.notifs();
    window.Echo.join('userInAddProduct')
       // listen to broadcast from Add.vue
      .listenForWhisper('typing', (product) => {
        // add it into my navbar notifications list
        this.notifications.unshift(product);
      });
}

これで、ユーザーがサーバー管理者に新製品を追加するたびに通知されます。

この機能を実行するための他の設定を確認するには、更新部分までスクロールして戻り、Event, Listener & Observeファイルコード。 (これらのファイルと上記のすべてのコードを優先コンポーネントに作成すると、リアルタイムの通知が届きます)。

0
mafortis
  1. アプリ全体でイベントが発生したらすぐにライブ通知を返すにはどうすればよいですか?現在、私のコードがadd.vueコンポーネントに配置されているため、管理者は同じページにのみいる場合に通知を受け取ります:/

スクリプトを追加し、そのページでソケットエミット関数を呼び出してオンラインを有効にする必要があります。他のページに移動すると、オンラインで無効にする機能が発生します

  1. 複数のイベントの通知を受け取るにはどうすればよいですか?別のイベント、リスナー、他のページアクションのオブザーバーがあるとします。アプリ全体の製品イベントと他のイベントの両方を管理者に通知してもらいたいとしましょう。

これらすべてのイベントでソケットエミットを呼び出さないのはなぜですか?

こちらをご確認ください: https://github.com/socketio/socket.io

2
iGuru1994

public and privateのようなチャネルタイプを区別します。

公開:Illuminate\Broadcasting\Channel。認証なしで機能するため、匿名ユーザーはこのブロードキャストを聞くことができます。みんなが利用できるサッカーの試合のスコアのように。

Private:Illuminate\Broadcasting\PrivateChannel。認証で動作するため、認証されたユーザーのみがこのブロードキャストを聞くことができます。管理者が特定のユーザーの行動を監視したり、ユーザーが注文状況を監視したりするようなものです。

一方、Illuminate\Broadcasting\PresenceChannelであるanother privateチャネルがあります。認証も必要です。例では、チャットルームのようになります。例:認証されたユーザーのみが相互に通信できます。

したがって、これらのタイプはメソッドを定義します。そして、あなたは異なる道をたどる必要があります。 Laravelのドキュメントhttps://laravel.com/docs/broadcasting )を読むことを強くお勧めします。

routes/channels.phpでは、認証されたユーザーがこの特定のチャンネルをリッスンできるかどうかを決定または確認する必要があります。したがって、ブール値(trueまたはfalse)を返す必要があります。したがって、ここでは、クライアント側に値を返していません。

すべてのパブリックプロパティ MessagePushedブロードキャストイベントのserializedおよびsentclient sideになります。すべての情報データをMessagePushedコンストラクターに渡し、property/propertiesに設定する必要があります。これで、次のようにして受信データを処理できます。

window.Echo = new Echo({
    broadcaster: 'socket.io',
    Host: window.location.hostname + ':6001',
    auth: {
      headers: {
        'X-Auth-Token': "<token>"
      }
    }
});

window.Echo.private('userInAddProduct')
   .listen('MessagePushed ', (e) => {
       console.log(e.auction);
    });

トークンを使用するカスタム認証を作成することをお勧めします。上記では、ユーザーを認証するためにトークンをサーバーに送信しました。 https://laravel.com/docs/authentication#adding-custom-guards

あなたの状況では、これら2つのメカニズムを分離します。

  1. アプリの製品ページに移動するためにユーザーを確認してください
  2. 管理者に通知

2.のポイントは、Illuminate\Broadcasting\PrivateChannelを使用するのに十分です。したがって、管理ページにWebSocketが必要です。 1.ポイントは、要件によって異なるため、注意が必要です。ユーザーが正確なアプリ製品ページに移動したことを管理者に通知するだけで十分ですか?

  • はいの場合、ユーザーがそのページに移動すると、コントローラーでこのブロードキャストイベントがトリガーされます。

  • 十分でない場合は、サーバーを「ポーリング」し、X秒ごとにティックブロードキャストを管理者に送信するために、ユーザーページに別のWebソケットが必要です。

ブロードキャストイベントのトリガー:

broadcast(new App\Events\MessagePushed($user));

私の使い方の好みは:

よろしくお願いいたします。

0
bornemisza

私は最近記事を書きました Laravel NuxtJs通知用のWebSockets の使用方法で、イベント設定を含めて十分詳細に説明しましたLaravel WebSocketsの場合。これが役に立つと思います。

0
AndreyBlog