How to Build a Chat Application with Laravel Echo and Pusher

How to Build a Chat Application with Laravel Echo and Pusher

In this tutorial, we will learn how to build a real-time chat application using Laravel Echo and Pusher. Laravel Echo is a JavaScript library that makes it easy to handle real-time events in Laravel applications. Pusher is a hosted service that allows us to send and receive real-time messages.

By the end of this tutorial, you will have a fully functional chat application where users can send and receive messages in real-time.

Prerequisites

To follow along with this tutorial, you will need the following:

  • Basic knowledge of Laravel framework
  • PHP installed on your system
  • Composer installed on your system
  • Node.js installed on your system
  • Laravel project setup with database configuration

Step 1: Setup Laravel Project

First, let’s setup a new Laravel project by running the following command in your terminal:

composer create-project --prefer-dist laravel/laravel chatapp

This will create a new Laravel project named chatapp. Once the project is created, navigate to the project directory:

cd chatapp

Step 2: Install Laravel Echo

To install Laravel Echo, we need to install the laravel-echo package via npm:

npm install --save laravel-echo pusher-js

This will install the required packages for Laravel Echo and Pusher. Next, we need to configure Laravel Echo to work with our application.

Step 3: Configure Laravel Echo

Open the bootstrap.js file located in the resources/js directory and add the following lines of code at the top of the file:

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
});

This will configure Laravel Echo with the required settings. Next, open the .env file located in the root directory of your Laravel project and add the following lines of code:

PUSHER_APP_ID=your_app_id
PUSHER_APP_KEY=your_app_key
PUSHER_APP_SECRET=your_app_secret
PUSHER_APP_CLUSTER=your_app_cluster

Replace your_app_id, your_app_key, your_app_secret, and your_app_cluster with your actual Pusher credentials. Save the file once done.

Step 4: Create Chatroom Model and Migration

Next, let’s create a Chatroom model and a migration to store the chatroom details. Run the following command in your terminal:

php artisan make:model Chatroom -m

This will create a new Chatroom model and a migration file. Open the newly created migration file located in the database/migrations directory and update the up method as follows:

public function up()
{
    Schema::create('chatrooms', function (Blueprint $table) {
        $table->id();
        $table->string('name');
        $table->timestamps();
    });
}

This will create an id, name, and timestamps columns in the chatrooms table. Save the file once done.

Step 5: Create User Model and Migration

Next, let’s create a User model and a migration file to store user details. Run the following command in your terminal:

php artisan make:model User -m

This will create a new User model and a migration file. Open the newly created migration file located in the database/migrations directory and update the up method as follows:

public function up()
{
    Schema::create('users', function (Blueprint $table) {
        $table->id();
        $table->string('name');
        $table->string('email')->unique();
        $table->timestamp('email_verified_at')->nullable();
        $table->string('password');
        $table->rememberToken();
        $table->timestamps();
    });
}

This will create the required columns in the users table. Save the file once done.

Step 6: Create Chat Messages Model and Migration

Next, let’s create a ChatMessage model and a migration file to store chat messages. Run the following command in your terminal:

php artisan make:model ChatMessage -m

This will create a new ChatMessage model and a migration file. Open the newly created migration file located in the database/migrations directory and update the up method as follows:

public function up()
{
    Schema::create('chat_messages', function (Blueprint $table) {
        $table->id();
        $table->unsignedBigInteger('chatroom_id');
        $table->unsignedBigInteger('user_id');
        $table->text('message');
        $table->timestamps();
    });
}

This will create the required columns in the chat_messages table. Save the file once done.

Step 7: Run Migrations

Next, let’s run the migrations to create the required tables in the database. Run the following command in your terminal:

php artisan migrate

This will create the chatrooms, users, and chat_messages tables in your database.

Step 8: Create Routes

Now, let’s create some routes to handle the chat application functionality. Open the routes/web.php file located in the root directory of your Laravel project and update the file as follows:

use AppHttpControllersChatController;

Route::get('/', [ChatController::class, 'index'])->name('chat.index');
Route::post('/message', [ChatController::class, 'sendMessage'])->name('chat.sendMessage');
Route::get('/messages', [ChatController::class, 'getMessages'])->name('chat.getMessages');

This will define three routes for the chat application: / to display the chat interface, /message to send a message, and /messages to fetch the chat messages.

Step 9: Create Chat Controller

Next, let’s create a ChatController to handle the chat application functionality. Run the following command in your terminal:

php artisan make:controller ChatController

This will create a new ChatController in the app/Http/Controllers directory. Open the newly created ChatController file and update the file as follows:

namespace AppHttpControllers;

use AppModelsChatMessage;
use AppModelsChatroom;
use IlluminateHttpRequest;

class ChatController extends Controller
{
    public function index()
    {
        $chatrooms = Chatroom::all();

        return view('chat.index', compact('chatrooms'));
    }

    public function sendMessage(Request $request)
    {
        $user = auth()->user();

        $message = $user->messages()->create([
            'chatroom_id' => $request->input('chatroom_id'),
            'message' => $request->input('message')
        ]);

        return response()->json($message);
    }

    public function getMessages()
    {
        $messages = ChatMessage::with('user')->latest()->limit(50)->get();

        return response()->json($messages);
    }
}

This will define three methods in the ChatController. The index method returns the chat view, the sendMessage method saves a new chat message to the database, and the getMessages method returns the 50 latest chat messages.

Step 10: Create Chat Index View

Next, let’s create a chat index view. Run the following command in your terminal:

mkdir resources/views/chat
touch resources/views/chat/index.blade.php

This will create a new directory chat in the resources/views directory and a new index.blade.php file inside it. Open the index.blade.php file and update the file as follows:

@extends('layouts.app')

@section('content')
    <div class="container">
        <div class="row">
            <div class="col-md-3">
                <h3>Chatrooms</h3>

                <ul>
                    @foreach($chatrooms as $chatroom)
                        <li>{{ $chatroom->name }}</li>
                    @endforeach
                </ul>
            </div>
            <div class="col-md-9">
                <h3>Chat</h3>

                <div id="chat-messages"></div>

                <form>
                    <div class="form-group">
                        <input type="text" id="message-input" class="form-control" placeholder="Message">
                    </div>
                    <button type="submit" id="send-message" class="btn btn-primary">Send</button>
                </form>
            </div>
        </div>
    </div>
@endsection

@section('scripts')
    <script>
        var chatroomId = null;

        // Fetch chat messages
        function fetchMessages() {
            axios.get('/messages')
                .then(function (response) {
                    var chatMessages = '';

                    response.data.forEach(function (message) {
                        chatMessages += '<p><strong>' + message.user.name + '</strong>: ' + message.message + '</p>';
                    });

                    document.getElementById('chat-messages').innerHTML = chatMessages;
                })
                .catch(function (error) {
                    console.log(error);
                });
        }

        // Send chat message
        function sendMessage(event) {
            event.preventDefault();

            var message = document.getElementById('message-input').value;

            if (chatroomId && message) {
                axios.post('/message', { chatroom_id: chatroomId, message: message })
                    .then(function (response) {
                        // Clear input field
                        document.getElementById('message-input').value = '';

                        // Fetch messages again
                        fetchMessages();
                    })
                    .catch(function (error) {
                        console.log(error);
                    });
            }
        }

        // Event Listeners
        document.getElementById('send-message').addEventListener('click', sendMessage);

        // Fetch messages on page load
        window.addEventListener('DOMContentLoaded', function () {
            fetchMessages();
        });
    </script>
@endsection

This will create the chat index view with a list of chatrooms, a chat window, and a form to send messages. The JavaScript code handles fetching and displaying chat messages, sending messages, and updating the chat window in real-time.

Step 11: Update Layout

Open the resources/views/layouts/app.blade.php file and update the file as follows:

<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <title>{{ config('app.name', 'Laravel') }}</title>

    <link href="{{ asset('css/app.css') }}" rel="stylesheet">
</head>
<body>
    <div id="app">
        <nav class="navbar navbar-expand-md navbar-light bg-white shadow-sm">
            <div class="container">
                <a class="navbar-brand" href="{{ url('/') }}">
                    {{ config('app.name', 'Laravel') }}
                </a>
                <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="{{ __('Toggle navigation') }}">
                    <span class="navbar-toggler-icon"></span>
                </button>

                <div class="collapse navbar-collapse" id="navbarSupportedContent">
                    <!-- Left Side Of Navbar -->
                    <ul class="navbar-nav mr-auto">

                    </ul>

                    <!-- Right Side Of Navbar -->
                    <ul class="navbar-nav ml-auto">
                        <!-- Authentication Links -->
                        @guest
                            @if (Route::has('login'))
                                <li class="nav-item">
                                    <a class="nav-link" href="{{ route('login') }}">{{ __('Login') }}</a>
                                </li>
                            @endif

                            @if (Route::has('register'))
                                <li class="nav-item">
                                    <a class="nav-link" href="{{ route('register') }}">{{ __('Register') }}</a>
                                </li>
                            @endif
                        @else
                            <li class="nav-item dropdown">
                                <a id="navbarDropdown" class="nav-link dropdown-toggle" href="#" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" v-pre>
                                    {{ Auth::user()->name }}
                                </a>

                                <div class="dropdown-menu dropdown-menu-right" aria-labelledby="navbarDropdown">
                                    <a class="dropdown-item" href="{{ route('logout') }}"
                                       onclick="event.preventDefault();
                                                     document.getElementById('logout-form').submit();">
                                        {{ __('Logout') }}
                                    </a>

                                    <form id="logout-form" action="{{ route('logout') }}" method="POST" class="d-none">
                                        @csrf
                                    </form>
                                </div>
                            </li>
                        @endguest
                    </ul>
                </div>
            </div>
        </nav>

        <main class="py-4">
            @yield('content')
        </main>
    </div>

    <script src="{{ asset('js/app.js') }}"></script>
    @yield('scripts')
</body>
</html>

This will update the layout file to include the required JavaScript and CSS assets.

Step 12: Run Laravel Development Server

Finally, let’s run the Laravel development server to see our chat application in action. Run the following command in your terminal:

php artisan serve

This will start the Laravel development server on `http://localhost:8000`. Visit this URL in your browser to see the chat application.

Congratulations! You have successfully built a chat application with Laravel Echo and Pusher. Users can now send and receive messages in real-time.

Conclusion

In this tutorial, we learned how to build a real-time chat application using Laravel Echo and Pusher. We covered the following steps:

  • Setting up a new Laravel project
  • Installing Laravel Echo and Pusher
  • Configuring Laravel Echo
  • Creating models and migrations for chatrooms, users, and chat messages
  • Running migrations
  • Creating routes and a controller
  • Creating chat views and updating the layout
  • Running the Laravel development server

Now, you can further enhance your chat application with features like private messaging, online/offline status, and message notifications.

Related Post