Laravel8 + Vueでのチャット機能を簡単にご紹介します。
開発環境
Laravel v8.73.2
npm v8.1.0
本記事ではPusherというサービスを使って構築していきます。
Laravel環境構築や、Pusherへの会員登録については他記事などを参考にしてみてください。
パッケージなどのインストール
Laravel UIをインストール。
スカフォールドを各フレームワークから選択。(今回はVue.jsを使用)
パッケージのインストール。
コンパイルの自動化。
マイグレーション実行。
Pusher連携部分の実装
ブロードキャストを有効にするため、 config/app.php の上記コメントアウトを外す。
Pusher用のパッケージのインストール。
Laravel Echo用のパッケージをインストール。
broadcaster: 'pusher',
key: process.env.MIX_PUSHER_APP_KEY,
cluster: process.env.MIX_PUSHER_APP_CLUSTER,
forceTLS: true
});
resources/js/bootstrap.js の上記コメントアウトを外し、Laravel Echoを有効にします。
モデルの作成
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateMessagesTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('messages', function (Blueprint $table) {
$table->char('id', 36)->primary()->comment('ID');
$table->char('user_id', 36);
$table->text('message');
$table->dateTime('deleted_at')->nullable()->comment('削除日時');
$table->dateTime('created_at')->nullable()->comment('作成日時');
$table->dateTime('updated_at')->nullable()->comment('更新日時');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('messages');
}
}
作成されたマイグレーションファイルを上記のように修正。
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Message extends Model
{
use HasFactory;
protected $primaryKey = 'id';
protected $keyType = 'string';
public $incrementing = false;
protected $fillable = ['user_id', 'message'];
protected static function boot()
{
parent::boot();
static::creating(function ($model) {
$model->{$model->getKeyName()} = (string) \Str::uuid();
});
}
}
作成された app/Models/Message.php を上記のように修正。
{
return $this->hasMany('App\Model\Message');
}
UserモデルにhasManyを追加。
マイグレーション実行。
Routeを追加
...
Route::group(['middleware' => ['auth']], function () {
Route::get('chat', [MessageController::class, 'index']);
Route::get('messages', [MessageController::class, 'get']);
Route::post('messages', [MessageController::class, 'send']);
});
routes/web.php に上記を追加。
Controllerを追加
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Events\MessageSentEvent;
use App\Models\Message;
class MessageController extends Controller
{
public function index()
{
return view('chat');
}
public function get()
{
return Message::with('user')->get();
}
public function send(Request $request)
{
$user = Auth::user();
$message = $user->messages()->create([
'message' => $request->input('message')
]);
event(new MessageSent($user, $message));
return ['status' => 'Message Success!'];
}
}
Eventの作成
namespace App\Events;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
use App\Models\Message;
class MessageSentEvent implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $message;
/**
* Create a new event instance.
*
* @return void
*/
public function __construct(User $user, Message $message)
{
$this->user = $user;
$this->message = $message;
}
/**
* Get the channels the event should broadcast on.
*
* @return \Illuminate\Broadcasting\Channel|array
*/
public function broadcastOn()
{
return new PrivateChannel('test');
}
}
公開チャンネルにしたい場合、上記を Channelに変更することで対応可能。
また、 ‘test’ 部分を書き換えることで複数チャンネルにも対応可能。
return Auth::check();
});
今回はプライベートチャンネルを実装したため、 routes/channels.php にて認証チェックを行う。
Viewの作成
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="UTF-8">
<title>テストチャット</title>
<link href="{{ mix('css/app.css') }}" rel="stylesheet" type="text/css">
<meta name="csrf-token" content="{{ csrf_token() }}">
</head>
<body>
<div id="app">
<chat-component></chat-component>
</div>
<script src="{{ mix('js/app.js') }}"></script>
</body>
</html>
resources/views/chat.blade.php
<div>
<ul>
<li v-for="(message, key) in messages" :key="key">
<strong>{{ message.user.name }}</strong>
{{ message.message }}
</li>
</ul>
<input v-model="text" />
<button @click="postMessage" :disabled="!textExists">Submit</button>
</div>
</template>
<script>
export default {
data() {
return {
text: '',
messages: []
};
},
computed: {
textExists() {
return this.text.length > 0;
}
},
created() {
this.getMessages();
Echo.private('test').listen('MessageSentEvent', e => {
this.messages.push({
message: e.message.message,
user: e.user
});
});
},
methods: {
getMessages() {
axios.get('/messages').then(response => {
this.messages = response.data;
});
},
postMessage(message) {
axios.post('/messages', { message: this.text }).then(response => {
this.text = '';
});
}
}
};
</script>
resources/js/components/ChatComponent.vue
Pusherの設定
Select a cluster : 日本で使用する場合、そのままでOK
Front end : Vue.js
Back end : PHP
Pusherにログイン後、「Create my app」画面から各種情報を入力して登録。
PUSHER_APP_KEY=
PUSHER_APP_SECRET=
PUSHER_APP_CLUSTER=mt1
登録が完了したら「App Keys」メニューから必要情報をコピーし、 .env ファイルに追記。
ログイン後、 /chat にアクセスすることでチャットが行えます。