Laravelとvue.jsでリアルタイムチャットを実装してみた

2021.01.18

見出し画像

今回はリアルタイムチャット機能を作っていきます。

続き(編集と削除)

pusherとlaravel echoを使います。laravel7.xです。

目次

  1. 大まかな流れ
  2. 必要なモデル、コントローラーの作成
  3. routeの設定
  4. メッセージ保存
  5. メッセージの表示
  6. pusher登録
  7. 環境変数設定
  8. laravel-echoとpusherのインストール
  9. 通知イベントを作成
  10. vue、controllerに記述追加

すべて表示

大まかな流れ

1, 必要なモデル、コントローラーの作成

2, メッセージ保存

3, メッセージの表示

4, pusher登録

5, 環境変数設定

6, laravel-echoとpusherのインストール

7, 通知イベントを作成

8, vueに記述追加

9, 確認

って感じで実装しています。

必要なモデル、コントローラーの作成

まずはモデルとマイグレーションファイルの作成から入ります。コマンドはターミナルで以下のような感じでしょう。

php artisan make:model Message -m

マイグレーション ファイルには、以下のような形で。今回はそこまで長い文章を送らない想定なのでstringで型指定してしてますが、textとかでも良いかと。

外部キーはlaravel7から新しい書き方もできるようになっています。

$table->string('text');
$table->foreignId('user_id')->constrained(); 外部キーつけるなら。

laravel7から上記の1行で下記の2行を表すことが出来る。

// $table->unsignedBigInteger('user_id');
// $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');

上記が済んだらターミナルでphp artisan migrate実行です。

次はモデルファイルにfillableの記述を書きます。アソシエーションも。

Messageモデル
  protected $fillable = ['text', 'user_id'];

   public function user() 
   {
       return $this->belongsTo('App\User');
   }
   
Userモデル
   public function messages() 
   {
       return $this->hasMany('App\Message');
   }

上記のように書ければアソシエーションもおっけいです。

routeの設定

Route::resource('room.message', 'MessageController');

メッセージ保存

まずはvue側から

            <div v-for="message in array" :key="message.id">
                 <div class="media-body ml-3">
                   <div class="bg-light rounded py-2 px-3 mb-2">
                     <p class="text-small mb-0 text-dark">{{message.text}}</p>
                 </div>
               </div>
             
        <form enctype="multipart/form-data" @submit.prevent="send" class="bg-light">
          <div class="input-group">
             <input type="text" placeholder="Type a message" aria-describedby="button-addon2" class="form-control rounded-0 border-0 py-4 bg-light" v-model="text">
             <div class="input-group-append">
               <button id="button-addon2" type="submit" class="btn btn-link"><font-awesome-icon icon="coffee" /></button>
             </div>
           </div>
         </form>       
         
         省略。。
         
 data() {
   return {
     text: '',
     array: [],
   }
 },
 
 省略。。。
 getMessages() {
     axios.get(任意のpath_link).then(res => {
       // propsで渡されたmessagesをarrayに入れている
      this.array = res.data
     })
   },
 
 send() {
     let obj = {
       text: this.text
     }
     
     axios.post(任意のpath, obj).then(res => {
       this.getMessages()
     }).catch(function(error){
       console.log(error)
     })
   },

axiosで入力された文字を飛ばしています。

public function store(Request $request)
   {
       $user = Auth::user();

       $message = new Message();
       $message->text = $request->text;
       $message->user_id = $user->id;
       
       $message->save();
       return $message;
   }

ここまででデータベースにメッセージ保存されることが確認できればオーケー!

メッセージの表示

メッセージの表示についてはgetMesagesメソッドを呼び出して値をarrayに入れて、v-forで表示させているイメージです。axios.getはindexに飛ばしてます。

public function index()
   {
       $messages = Message::get();
       return $messages;
   }

pusher登録

pusherにログイン(新規登録)をしてapi keyを使います。

この記事を参考に進めています。pusherについても同様です。

環境変数設定

.envの環境変数のところにpusherで取得した値を設定していきます。

BROADCAST_DRIVER=pusher pusherに変更する。元々はlogのはず

以下それぞれpusherのものを設定していく。
PUSHER_APP_ID=******
PUSHER_APP_KEY=********************
PUSHER_APP_SECRET=********************
PUSHER_APP_CLUSTER=***

環境変数の設定後は下記コマンドを忘れずに。

php artisan config:cache

config/app.php内のBroadcastServiceProviderをコメントアウトを外す。

// App\Providers\BroadcastServiceProvider::class, 
変更後​
App\Providers\BroadcastServiceProvider::class, ​

laravel-echoとpusherのインストール

をインストール。ターミナルでの作業です。2回ある。

composer require pusher/pusher-php-server "~3.0"

npm install --save laravel-echo pusher-js​

インストールが完了したら、resources/js/bootstrap.jsの記述で以下をコメントインする。

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,
   encrypted: true
});

通知イベントを作成

php artisan make:event MessageCreated でイベント作成

作成されたファイルを少し書き換えます。

#1, ShouldBroadcastの追加

#2, public宣言

#3, broadcastOn()でchatチャンネルを作成。

class MessageCreated implements ShouldBroadcast #1
{
   use Dispatchable, InteractsWithSockets, SerializesModels;

   public $message; #2

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

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

vue、controllerに記述追加

メッセージが保存された際にMessageCreatedが発火するように。pusherにいきます。pusherのdebug consoleでみれます。

$message->save();
event(new MessageCreated($message));

vue側はライフサイクルメソッドのmountedに記載を追加。コントローラーで設定したMessageCreatedが動くのをlistenで検知して動いたらthis.getMessages()を実行するようにしている。

mounted() {
   this.getMessages() メッセージ全取得

    pusherからのデータを受け取る
   Echo.channel('chat').listen('MessageCreated', (e) => {
     this.getMessages()
   })
 },

確認

ここまで行けたらメッセージの送信はリアルタイムで出来ます。pusherでもdebug consoleで中身の送信が確認できます。

もしうまくいっていない場合はconsole.logなどを使って処理がどこまで動いているか確認していきましょう。

ポイント

正しくメッセージが保存できる。

コントローラーで保存が完了した時にMessageCreatedが発火するか。pusherに渡ってたらおっけい。

mounted()からechoで処理の呼び出しに成功するか。console.logで確認できる。

まとめ

初めてlaravel echoとpusherを使ったけどそこまで難しくないので、このまま次はmessageの編集と削除についての記事も書いていきたい。

そんな感じで今回は

以上!