Implementing realtime chat and notifications in an Airbnb clone with Laravel and WebSocket
Tags: airbnbclone, airbnbclonephp, airbnbclonelaravel, airbnbclonescript
Published: 2023-10-27 06:16:14

Creating real-time features like chat or notifications between hosts and guests is a crucial part of building a seamless Airbnb clone experience. Laravel, with the help of WebSockets, can be a great choice for implementing this functionality. 

In this blog post, we will walk through the process of setting up a real-time chat and notification system using Laravel, the Laravel Echo package, and the Pusher service. We'll use a simplified example to illustrate the key steps involved.

### Prerequisites
Before getting started, make sure you have the following components set up:

1. **Laravel Project**: Have a Laravel project up and running.

2. **Pusher Account**: Sign up for a free Pusher account (https://pusher.com/) and create a new app. You'll need the app credentials.

3. **Laravel Echo**: Install the Laravel Echo package in your project using `composer require laravel/echo`.

### Step 1: Setting up Laravel Echo and Pusher
First, configure Laravel Echo and Pusher. Open your `.env` file and set the following variables:

```env
BROADCAST_DRIVER=pusher
PUSHER_APP_ID=your-app-id
PUSHER_APP_KEY=your-app-key
PUSHER_APP_SECRET=your-app-secret
PUSHER_APP_CLUSTER=your-app-cluster
```

Next, update the `config/broadcasting.php` file to use the Pusher driver:

```php
'connections' => [
    'pusher' => [
        'driver' => 'pusher',
        'key' => env('PUSHER_APP_KEY'),
        'secret' => env('PUSHER_APP_SECRET'),
        'app_id' => env('PUSHER_APP_ID'),
        'options' => [
            'cluster' => env('PUSHER_APP_CLUSTER'),
            'encrypted' => true,
        ],
    ],
],
```

### Step 2: Create the Chat Model and Migration
Let's create a model and migration for our chat system. Run the following commands:

```shell
php artisan make:model Chat -m
```

In the generated migration file, define the `chats` table schema:

```php
public function up()
{
    Schema::create('chats', function (Blueprint $table) {
        $table->id();
        $table->unsignedBigInteger('sender_id');
        $table->unsignedBigInteger('receiver_id');
        $table->text('message');
        $table->timestamps();
    });
}
```

Run the migration to create the `chats` table:

```shell
php artisan migrate
```

### Step 3: Create ChatController
Generate a controller for handling chat messages:

```shell
php artisan make:controller ChatController
```

In the `ChatController`, create methods for sending and retrieving chat messages. Here's a simplified example:

```php
use Illuminate\Http\Request;
use App\Events\NewChatMessage;
use App\Chat;

class ChatController extends Controller
{
    public function send(Request $request)
    {
        $message = Chat::create([
            'sender_id' => auth()->id(),
            'receiver_id' => $request->receiver_id,
            'message' => $request->message,
        ]);

        broadcast(new NewChatMessage($message))->toOthers();

        return response()->json(['message' => 'Message sent']);
    }

    public function getMessages(Request $request)
    {
        $messages = Chat::where(function ($query) use ($request) {
            $query->where('sender_id', auth()->id())
                ->where('receiver_id', $request->receiver_id);
        })->orWhere(function ($query) use ($request) {
            $query->where('sender_id', $request->receiver_id)
                ->where('receiver_id', auth()->id());
        })->get();

        return response()->json(['messages' => $messages]);
    }
}
```

### Step 4: Create an Event
Generate an event to broadcast new chat messages:

```shell
php artisan make:event NewChatMessage
```

In the `NewChatMessage` event, define the data to be broadcasted:

```php
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
use App\Chat;

class NewChatMessage
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

    public $message;

    public function __construct(Chat $message)
    {
        $this->message = $message;
    }

    public function broadcastOn()
    {
        return new PrivateChannel('chat.' . $this->message->receiver_id);
    }
}
```

### Step 5: Configure Broadcasting Channels
Define the broadcasting channels in `routes/channels.php`. In this case, we're using private channels for one-on-one chats:

```php
use Illuminate\Support\Facades\Broadcast;
use App\User;

Broadcast::channel('chat.{receiver_id}', function ($user, $receiver_id) {
    return $user->id === (int) $receiver_id;
});
```

### Step 6: Set Up the Frontend
On the frontend, you'll need to use Laravel Echo to listen for incoming messages and send messages to the server. Here's an example using JavaScript and Vue.js:

```javascript
// resources/js/bootstrap.js
import Echo from 'laravel-echo'

window.Echo = new Echo({
    broadcaster: 'pusher',
    key: process.env.MIX_PUSHER_APP_KEY,
    cluster: process.env.MIX_PUSHER_APP_CLUSTER,
    encrypted: true,
    authEndpoint: '/broadcasting/auth',
})

// resources/js/components/ChatComponent.vue
<template>
  <div>
    <div v-for="message in messages" :key="message.id">
      {{ message.message }}
    </div>
    <input v-model="newMessage" @keyup.enter="sendMessage" />
  </div>
</template>

<script>
export default {
  data() {
    return {
      messages: [],
      newMessage: '',
    }
  },
  created() {
    this.fetchMessages()
    this.listenForMessages()
  },
  methods: {
    fetchMessages() {
      // Make an API request to get chat messages
    },
    listenForMessages() {
      Echo.private('chat.' + this.receiverId)
        .listen('NewChatMessage', (event) => {
          this.messages.push(event.message)
        })
    },
    sendMessage() {
      // Make an API request to send a chat message
    },
  },
}
</script>
```

### Step 7: Create the API Routes
Create API routes for sending and retrieving chat messages:

```php
// routes/api.php
Route::middleware('auth:api')->group(function () {
    Route::post('/chat/send', 'ChatController@send');
    Route::get('/chat/messages', 'ChatController@getMessages');
});
```

### Step 8: Secure the API Routes
To secure the API routes, you can use Laravel Passport for authentication and authorization. Make sure the routes are protected and only accessible by authenticated users.

### Step 9: Test the Chat System
With everything set up, you can now test your chat system by sending and receiving messages in real-time between hosts and guests.

### Conclusion
Implementing real-time features like chat or notifications using Laravel and WebSockets can significantly enhance the user experience of your **[Airbnb clone](https://cron24.com/airbnb-clone)**.

This blog post provided a simplified example of how to set up a real-time chat system using Laravel, Laravel Echo, and Pusher. You can expand on this foundation to create a full-featured chat and notification system for your application, giving your users a seamless and engaging experience.

Thank you.