Adding Real-Time Chat to Laravel App with Reverb and Vue.js 3
Tags: webdev, laravel, php, vue
Published: 2024-07-04 12:31:57

In today's digital age, users crave real-time interaction. Whether it's for a customer support channel, a collaborative platform, or a social networking app, real-time chat functionality can significantly enhance the user experience. Laravel, the popular PHP framework known for its elegant syntax and robust features, offers a powerful tool for building such features: Laravel Reverb.

This article will guide you through creating a real-time chat system using Laravel Reverb and Vue.js 3. We'll cover setting up Laravel Reverb, building the backend logic with Laravel, and implementing the frontend with Vue.js.

## What is Laravel Reverb?
Laravel Reverb is a first-party WebSocket server specifically designed for Laravel applications. It facilitates seamless, two-way communication between your server and client, allowing for instant data updates without requiring constant page refreshes.

## Why Choose Laravel Reverb for Real-Time Chat?

- **Seamless Integration**: As an official Laravel package, Reverb integrates effortlessly with the Laravel ecosystem.
- **Performance**: Built for speed and scalability, Reverb can handle a high volume of concurrent users and messages.
- **Security**:  Reverb leverages Laravel's built-in security mechanisms for secure communication.

Let's Get Started!

## 1. Project Setup
Make sure you have a fresh Laravel installation. If not, create one:

```
composer create-project laravel/laravel your-chat-app
cd your-chat-app 
```
## 2. Install and Configure Laravel Reverb
Install Reverb using Composer:

```
composer require laravel/reverb
php artisan install:broadcasting
```

This command will also generate the necessary configuration files for broadcasting and create `echo.js` in your `resources/js` directory.

Update your `.env `file with the necessary Reverb configurations. You can generate application credentials from your dashboard on the service you are using.

```
BROADCAST_DRIVER=reverb
REVERB_APP_ID=your-app-id
REVERB_APP_KEY=your-app-key
REVERB_APP_SECRET=your-app-secret
```
## 3. Database Setup
We'll use a simple database structure for this example. Create a migration for a `messages` table:

```
php artisan make:migration create_messages_table

```
Add the following code to the `up` method of the generated migration file:

```
public function up()
{
    Schema::create('messages', function (Blueprint $table) {
        $table->id();
        $table->foreignId('user_id')->constrained()->cascadeOnDelete();
        $table->text('message');
        $table->timestamps();
    });
}
```
Run the migrations:

```
php artisan migrate
```
## 4. Create the Message Model

Generate a Message model:

```
php artisan make:model Message

```
And define the relationship with the User model:

```
// app/Models/Message.php

use Illuminate\Database\Eloquent\Model;

class Message extends Model
{
    protected $fillable = ['user_id', 'message'];

    public function user()
    {
        return $this->belongsTo(User::class);
    }
}
```
## 5. Create the Broadcasting Event
Generate an event that will be broadcast whenever a new message is sent:

```
php artisan make:event MessageSent

```
Update the `MessageSent` event with the following:

```
// app/Events/MessageSent.php

namespace App\Events;

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;
use App\Models\Message;

class MessageSent implements ShouldBroadcast
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

    public $message;

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

    /**
     * Get the channels the event should broadcast on.
     *
     * @return array<int, \Illuminate\Broadcasting\Channel>
     */
    public function broadcastOn(): array
    {
        return [
            new PresenceChannel('chat'),
        ];
    }
}

```
## 6. Define the Broadcast Route

In your `routes/channels.php` file, define the authorization logic for the `chat` channel:

```
Broadcast::channel('chat', function ($user) {
    return ['id' => $user->id, 'name' => $user->name];
});
```
This ensures that only authenticated users can join the chat channel. 

## 7. Create the Chat Controller
Create a controller to handle chat-related logic:

```
php artisan make:controller ChatController

```
Define the methods for retrieving messages and sending new messages:

```
// app/Http/Controllers/ChatController.php

namespace App\Http\Controllers;

use App\Models\Message;
use Illuminate\Http\Request;
use App\Events\MessageSent;

class ChatController extends Controller
{
    public function __construct()
    {
        $this->middleware('auth');
    }

    public function index()
    {
        return view('chat');
    }

    public function messages()
    {
        return Message::with('user')->latest()->take(10)->get();
    }

    public function sendMessage(Request $request)
    {
        $message = auth()->user()->messages()->create([
            'message' => $request->message,
        ]);

        broadcast(new MessageSent($message->load('user')))->toOthers();

        return $message;
    }
}

```
## 8. Set up Routes
Define the routes for your chat application in your `routes/web.php` file:

```
// routes/web.php

use App\Http\Controllers\ChatController;

Route::get('/chat', [ChatController::class, 'index']);
Route::get('/messages', [ChatController::class, 'messages']);
Route::post('/messages', [ChatController::class, 'sendMessage']);
```

## 9. Create the Vue.js Component
Now, let's build the frontend using Vue.js. Create a new component file:

```
touch resources/js/components/Chat.vue

```
Add the following code to Chat.vue:
```
<template>
  <div class="container">
    <div class="row">
      <div class="col-md-8 offset-md-2">
        <div class="card">
          <div class="card-header">Chat Room</div>
          <div class="card-body" style="height: 400px; overflow-y: scroll;">
            <ul class="list-unstyled">
              <li v-for="message in messages" :key="message.id">
                <strong>{{ message.user.name }}:</strong> {{ message.message }}
              </li>
            </ul>
          </div>
          <div class="card-footer">
            <input type="text" class="form-control" v-model="newMessage" @keyup.enter="sendMessage">
            <button class="btn btn-primary mt-2" @click="sendMessage">Send</button>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      messages: [],
      newMessage: ''
    };
  },
  mounted() {
    this.fetchMessages();
    Echo.join('chat')
      .here((users) => {
        console.log('Users online:', users);
      })
      .joining((user) => {
        console.log(user.name + ' joined.');
      })
      .leaving((user) => {
        console.log(user.name + ' left.');
      })
      .listen('MessageSent', (e) => {
        this.messages.push(e.message);
      });
  },
  methods: {
    fetchMessages() {
      axios.get('/messages').then(response => {
        this.messages = response.data;
      });
    },
    sendMessage() {
      if (this.newMessage === '') {
        return;
      }
      axios.post('/messages', { message: this.newMessage }).then(response => {
        this.newMessage = '';
      });
    }
  }
};
</script>
```

This component sets up a basic chat interface, retrieves messages, and sends new messages using Axios. It also utilizes Laravel Echo to listen for the MessageSent event and update the messages in real-time.

## 10. Compile Assets and Run
Finally, compile your assets and start the [Laravel development](https://digimonksolutions.com/services/laravel-development) server:

```
npm run dev
php artisan serve
```

That's it! You should now have a functional real-time chat application built with Laravel Reverb and Vue.js. 

## Conclusion
Laravel Reverb provides a straightforward yet powerful way to add real-time features to your Laravel applications. Paired with the flexibility of Vue.js, you can create engaging and interactive user experiences. This guide covered the fundamental steps to get your real-time chat application up and running. Explore the documentation further to discover more advanced features and customization options offered by Laravel Reverb and Vue.js.