This website uses cookies

Our website, platform and/or any sub domains use cookies to understand how you use our services, and to improve both your experience and our marketing relevance.

📣 Try the fastest hosting platform with pay-as-you-go pricing & 24/7 expert support! MIGRATE NOW →

Create a Realtime Chatroom with Laravel, VueJS and Pusher

Updated on June 23, 2022

9 Min Read

chatroom in laravel and vuejs

In today’s article, I am going to create a chatroom using Laravel 5.4, Pusher and VueJs. Since these tools are popular and almost every developer has heard of them, I will skip the theoretical introductions and discussions and go straight to the fun part.

Laravel Pusher sits as a real-time layer between your servers and your users. Laravel Pusher is a hosted service that makes it super-easy to include real-time information and functionality to web and versatile applications.  It maintains diligent connections at the client utilizing WebSockets, as and when unused information is included to your server.

Stop Wasting Time on Servers

Cloudways handle server management for you so you can focus on creating great apps and keeping your clients happy.

Laravel Pusher enables users to experience real-time encounters for portable and web applications. It has two features that are real-time API and Push-Notifications.

Here is a list of components that I will use for this application:

  • Laravel Auth
  • Laravel Mix
  • Laravel Broadcast
  • Laravel Pusher for Laravel and VueJS
  • Bootstrap

I recommend that you launch a Cloudways hosted Laravel application for testing the code. If you do not have an account, sign up for a trial account.

(Note: You may use promo code: PHP15 to get FREE Cloudways hosting credit of $15 on signup.)

Check out the following GIF for server and application launch.

DO installation

The complete for this application code can be found in the github repo and the live demo can be found here.

Setup User Authentication

The first step is the migration of the existing user table through the following command:

php artisan migrate

Next, create a basic auth by running the following command:

php artisan make:auth

Create a factory for creating a few users. For this, head to database/factories and open ModelFactory.php. Paste the following code in it.

$factory->define(App\User::class, function (Faker\Generator $faker) {

   static $password = "ahmedkhan";

   return [

       'name' => $faker->name,

       'email' => $faker->unique()->safeEmail,

       'password' => bcrypt($password) ?: $password = bcrypt('secret'),

       'remember_token' => str_random(10),

   ];

});

I will now create several users through the following command that will start up Tinker:

php artisan tinker

Now. run the following command to create ten users.

factory('App\User',10)->create();

Next up is the broadcaster which will broadcast the chat message(s).

Broadcaster For Chat Messages

I will use a database for queues in broadcast. I will first create migration table and then execute the actual migration.

Run the following commands in the terminal for creating the migration tables for queues:

php artisan queue:table

php artisan queue:failed-table

Now run the following command for the migration:

php artisan migrate

I will now create a Broadcast event for chat message. This event will broadcast the chat message when a user sends a new message to another user.

Run the following command to create the event:

php artisan make:event ChatMessage

Go to app/Events folder and open ChatMessage.php.

Start by implementing the class with ShouldBroadcast:

class ChatMessage implements ShouldBroadcast

Next, create a new public variable `$user`. Replace the constructor with the following:

public function __construct($user)

   {

       //

       $this->user = $user;

   }

And, replace `broadcastOn` with the following:

   

public function broadcastOn()

   {

       return ['chat-message'.$this->user['id']];

   }

What I am doing here is broadcasting the user message on ‘chat-message’.$this->user[‘id’] where $this->user[‘id’] is the id of the user to whom the message is being sent.

The final ChatMessage will look like this:

<?php

namespace App\Events;

use Illuminate\Broadcasting\Channel;

use Illuminate\Queue\SerializesModels;

use Illuminate\Broadcasting\PrivateChannel;

use Illuminate\Broadcasting\PresenceChannel;

use Illuminate\Foundation\Events\Dispatchable;

use Illuminate\Broadcasting\InteractsWithSockets;

use Illuminate\Contracts\Broadcasting\ShouldBroadcast;



class ChatMessage implements ShouldBroadcast

{

   use Dispatchable, InteractsWithSockets, SerializesModels;

   public $user;

   /**

    * Create a new event instance.

    *

    * @return void

    */

   public function __construct($user)

   {

       //

       $this->user = $user;

   }

   /**

    * Get the channels the event should broadcast on.

    *

    * @return Channel|array

    */

   public function broadcastOn()

   {
       return ['chat-message'.$this->user['id']];
   }

}

The broadcaster is now ready. I will now setup Pusher, that I will use for broadcasting messages.

Run the following command to install Pusher for PHP:

composer require pusher/pusher-php-server

Now in the .env file, set the values for the following items:

BROADCAST_DRIVER=

PUSHER_APP_ID=

PUSHER_APP_KEY=

PUSHER_APP_SECRET=

Next, I will create the chat controller.

You Might Also Like: Create Simple Laravel Pagination With Vue

The Chat Controller

Run the following command in the console:

php artisan make:controller ChatController

Now in the controller class, first create a constructor which contains auth middleware. This will let only the authenticated users access the chat.

   

/**

    * Create a new controller instance.

    *

    * @return void

    */

   public function __construct()

   {

       $this->middleware('auth');

   }

Now create a new function which sends the chat message:

/**

    * Send chat message

    * @param $request

    * @return void

    */

   public function sendMessage(Request $request)

   {

       $message = [

           "id" => $request->userid,

           "sourceuserid" => Auth::user()->id,

           "name" => Auth::user()->name,

           "message" => $request->message

       ];

       event(new ChatMessage($message));

       return "true";

   }

This function is simple. The `id` is the id of the user to whom the message is being sent. `sourceid` is the user id who is sending the message and `name` is the username. `message` is the chat message. Next, comes the actual broadcasting that returns true.

I will now create a function which will open a chatroom.

Start by creating a new function `chatPage()`:

public function chatPage()

   {

       $users = User::take(10)->get();

       return view('chat',['users'=> $users]);

   }

The final version of ChatController.php will look like this:

<?php

namespace App\Http\Controllers;


use Illuminate\Http\Request;

use App\User;

use Auth;

use App\Events\ChatMessage;


class ChatController extends Controller

{

   /**

    * Create a new controller instance.

    *

    * @return void

    */

   public function __construct()

   {

       $this->middleware('auth');

   }

   /**

    * Send chat message

    * @param $request

    * @return void

    */

   public function sendMessage(Request $request)

   {

       $message = [

           "id" => $request->userid,

           "sourceuserid" => Auth::user()->id,

           "name" => Auth::user()->name,

           "message" => $request->message

       ];

       event(new ChatMessage($message));

       return "true";

   }

   public function chatPage()

   {

       $users = User::take(10)->get();

       return view('chat',['users'=> $users]);

   }

}

The controller is ready for use.

Creating the Chatroom

Go to resources/views and create a new file called chat.blade.php. Paste the following code in it. This code is a mixture of VueJS and blade:

 

@extends('layouts.app')

@section('content')

<div class="row">

   <div class="col-md-2">

       <ul class="list-group">

       @foreach($users as $chatuser)

           <li v-on:click="getUserId" class="list-group-item" id="{{ $chatuser->id }}" value="{{ $chatuser->name }}">{{ $chatuser->name }}</li>

       @endforeach

           

       </ul>

   </div>

<div class="col-md-10">

<div class="row">

   <div class="col-md-4" v-for="(chatWindow,index) in chatWindows" v-bind:sendid="index.senderid" v-bind:name="index.name">

       <div class="panel panel-primary">

           <div class="panel-heading" id="accordion">

               <span class="glyphicon glyphicon-comment"></span> @{{chatWindow.name}}

           </div>

           <div class="panel-collapse" id="collapseOne">

               <div class="panel-body">

                   <ul class="chat" id="chat">

                       <li class="left clearfix" v-for="chat in chats[chatWindow.senderid]" v-bind:message="chat.message" v-bind:username="chat.username">

                       <span class="chat-img pull-left">

                       <img src="https://placehold.it/50/55C1E7/fff&amp;text=U" alt="User Avatar" class="img-circle">

                       </span>

                       <div class="chat-body clearfix">

                       <div class="header">

                       <strong class="primary-font"> @{{chat.name}}</strong>

                       </div>

                       <p>@{{chat.message}}</p>

                       </div>

                       </li>                                

                   </ul>

           </div>

               <div class="panel-footer">

                   <div class="input-group">

                       <input :id="chatWindow.senderid" v-model="chatMessage[chatWindow.senderid]" v-on:keyup.enter="sendMessage2" type="text" class="form-control input-md" placeholder="Type your message here..." />

                       <span class="input-group-btn"><button :id="chatWindow.senderid" class="btn btn-warning btn-md" v-on:click="sendMessage2">

                               Send</button></span>

                   </div>

               </div>

           </div>

       </div>

   </div>

</div>

</div>

</div>

@endsection

Here is how this code works:

I started with adding the list of users to whom you can send messages:

@foreach($users as $chatuser)

           <li v-on:click="getUserId" class="list-group-item" id="{{ $chatuser->id }}" value="{{ $chatuser->name }}">{{ $chatuser->name }}</li>

       @endforeach

Notice that I have binded `getUserId` function using VueJS. I will write this function in the app.js file.  

Next, the chat window is binded using VueJS variable `chatWindows`. It handles all the chat windows that the user is using. It will only be opened when you click a user for sending a message  or some other user send a message to you. Next is the `chats` variable which handles the chat for that window.

<div class="col-md-4" v-for="(chatWindow,index) in chatWindows" v-bind:sendid="index.senderid" v-bind:name="index.name">

       <div class="panel panel-primary">

           <div class="panel-heading" id="accordion">

               <span class="glyphicon glyphicon-comment"></span> @{{chatWindow.name}}

           </div>

           <div class="panel-collapse" id="collapseOne">

               <div class="panel-body">

                   <ul class="chat" id="chat">

                       <li class="left clearfix" v-for="chat in chats[chatWindow.senderid]" v-bind:message="chat.message" v-bind:username="chat.username">

                       <span class="chat-img pull-left">

                       <img src="https://placehold.it/50/55C1E7/fff&amp;text=U" alt="User Avatar" class="img-circle">

                       </span>

                       <div class="chat-body clearfix">

                       <div class="header">

                       <strong class="primary-font"> @{{chat.name}}</strong>

                       </div>

                       <p>@{{chat.message}}</p>

                       </div>

                       </li>                                

                   </ul>

           </div>

               <div class="panel-footer">

                   <div class="input-group">

                       <input :id="chatWindow.senderid" v-model="chatMessage[chatWindow.senderid]" v-on:keyup.enter="sendMessage" type="text" class="form-control input-md" placeholder="Type your message here..." />

                       <span class="input-group-btn"><button :id="chatWindow.senderid" class="btn btn-warning btn-md" v-on:click="sendMessage">

                               Send</button></span>

                   </div>

               </div>

           </div>

       </div>

   </div>

I have also binded `chatMessage` function.

I will now create routes .Go to the routes folder and open web.php file. Paste the following routes in it.

Route::post('/chat','ChatController@sendMessage');

Route::get('/chat','ChatController@chatPage');

The frontend is done. I will now create function in VueJS that will handle the chats. .

Write Functions to Handle Chat in VueJS

Before getting started with VueJS. make sure you have npm. Run the following command to install all the packages:

npm install

Now run the following command to install VueResource, which I will use for HTTP requests.

npm install vue-resource

Now go to resources/assets/js and open app.js file. Replace the code in it with the following:

/**

* First we will load all of this project's JavaScript dependencies which

* includes Vue and other libraries. It is a great starting point when

* building robust, powerful web applications using Vue and Laravel.

*/

require('./bootstrap');

/**

* Next, we will create a fresh Vue application instance and attach it to

* the page. Then, you may begin adding components to this application

* or customize the JavaScript scaffolding to fit your unique needs.

*/

import VueResource from "vue-resource"

import Echo from "laravel-echo"

import Pusher from "pusher-js"


Vue.use(VueResource);


window.Echo = new Echo({

   broadcaster: 'pusher',

   key: 'adba74bea688557ca' //Add your pusher key here

});


const app = new Vue({

   el: '#app',

   data: {

       chatMessage : [],

       userId : null,

       chats : [],

       chatWindows : [],

       chatStatus : 0,

       chatWindowStatus : [],

       chatCount : []

   },

   created(){

       window.Echo.channel('chat-message'+window.userid)

           .listen('ChatMessage', (e) => {

               console.log(e.user);

               this.userId = e.user.sourceuserid;

               if(this.chats[this.userId]){

                   this.show = 1;

                   this.$set(app.chats[this.userId], this.chatCount[this.userId] ,e.user);

                   this.chatCount[this.userId]++;

                   console.log("pusher");

                   console.log(this.chats[this.userId]);                   

               }else{

                   this.createChatWindow(e.user.sourceuserid,e.user.name)

                   this.$set(app.chats[this.userId], this.chatCount[this.userId] ,e.user);

                   this.chatCount[this.userId]++;

               }            

       });

   },

   http: {

       headers: {

           'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')

       }

   },

   methods: {

   sendMessage(event){

           this.userId = event.target.id;

           var message = this.chatMessage[this.userId];

           

           this.$http.post('chat',{

               'userid' : this.userId,

               'message' : message

           }).then(response => {

               this.chatMessage[this.userId] = '';

               this.$set(app.chats[this.userId], this.chatCount[this.userId] , {

                   "message": message,

                   "name" : window.username

           });

           this.chatCount[this.userId]++;

               console.log("send");

           }, response => {

               this.error = 1;

               console.log("error");

               console.log(response);

           });

       },

   getUserId(event){

       this.userId = event.target.id;

       this.createChatWindow(this.userId,event.target.innerHTML);

       console.log(this.userId);

   },

   createChatWindow(userid,username){

       if(!this.chatWindowStatus[userid]){  

           this.chatWindowStatus[userid] = 1;

           this.chatMessage[userid] = '';

           this.$set(app.chats, userid , {});

           this.$set(app.chatCount, userid , 0);

           this.chatWindows.push({"senderid" : userid , "name" : username});

       }    

   }

}});

Next, run the following command to compile it.

npm run dev

This is how this code works:

First I imported Pusher and vue-resource components:

import VueResource from "vue-resource"

import Echo from "laravel-echo"

import Pusher from "pusher-js"

Next, I added vue-resource to VueJS and initialized Laravel Echo:

Vue.use(VueResource);

window.Echo = new Echo({

   broadcaster: 'pusher',

   key: 'adba74bea68819d557ca' //Add your pusher key here

});

I then created VueJS instance in which first I defined the id of the div in which the app would load.

Next, I defined the variables which I will use in this app:

const app = new Vue({

   el: '#app',

   data: {

       chatMessage : [],

       userId : null,

       chats : [],

       chatWindows : [],

       chatStatus : 0,

       chatWindowStatus : [],

       chatCount : []

   },

Then, I added Laravel Echo to listen for broadcast events in `created()` method (which will work when the Vue app is fully created):

   

created(){

       window.Echo.channel('chat-message'+window.userid)

           .listen('ChatMessage', (e) => {

               console.log(e.user);

               this.userId = e.user.sourceuserid;

               if(this.chats[this.userId]){

                   this.show = 1;

                   this.$set(app.chats[this.userId], this.chatCount[this.userId] ,e.user);

                   this.chatCount[this.userId]++;

                   console.log("pusher");

                   console.log(this.chats[this.userId]);                   

               }else{

                   this.createChatWindow(e.user.sourceuserid,e.user.name)

                   this.$set(app.chats[this.userId], this.chatCount[this.userId] ,e.user);

                   this.chatCount[this.userId]++;

               }       

       });

   },


This function gets the message, and first checks whether an existing chat window is already open for that user. If yes, it sends the message to that chat window. If the chat window does not exists, it will create a new chat window, open it and display the message. Next, I defined ‘X-CSRF-TOKEN’ header for the HTTP requests.

I also created the methods which will handle sending of the message and creation of new chat window for the users.

methods: {

   sendMessage(event){

           this.userId = event.target.id;

           var message = this.chatMessage[this.userId];

           this.$http.post('chat',{

               'userid' : this.userId,

               'message' : message

           }).then(response => {

               this.chatMessage[this.userId] = '';

               this.$set(app.chats[this.userId], this.chatCount[this.userId] , {

                   "message": message,

                   "name" : window.username

           });

           this.chatCount[this.userId]++;

               console.log("send");

           }, response => {

               this.error = 1;

               console.log("error");

               console.log(response);

           });

       },

   getUserId(event){

       this.userId = event.target.id;

       this.createChatWindow(this.userId,event.target.innerHTML);

       console.log(this.userId);

   },

   createChatWindow(userid,username){

       if(!this.chatWindowStatus[userid]){

           

           this.chatWindowStatus[userid] = 1;

           this.chatMessage[userid] = '';

           this.$set(app.chats, userid , {});

           this.$set(app.chatCount, userid , 0);

           this.chatWindows.push({"senderid" : userid , "name" : username});

       } 

   }

}

The application code is finished. I will now test it.  

Testing the Chat Room

Open the login page in three separate browser instances and sign in with any user that you created by the faker.

Now click on any (logged in) user and send a message. In this case, I sent a message to myself from another user. Currently, all browser windows look like this:

I will now send a message to an online user.

Message will be received by that user and a chat window will open.

Now send a message to another user:

And keep sending message to the users.  

Final Words

In this article, I discussed how you could easily setup a realtime private chatroom using, VueJS and Laravel Pusher. This application is very basic and could use several improvements such as saving the messages and filtering users on the basis of their online status.

If you need further help with the code or the application setup, do leave a comment and I will get back to you ASAP.

 

Share your opinion in the comment section. COMMENT NOW

Share This Article

Inshal Ali

Inshal is a Content Marketer at Cloudways. With background in computer science, skill of content and a whole lot of creativity, he helps business reach the sky and go beyond through content that speaks the language of their customers. Apart from work, you will see him mostly in some online games or on a football field.

×

Get Our Newsletter
Be the first to get the latest updates and tutorials.

Thankyou for Subscribing Us!

×

Webinar: How to Get 100% Scores on Core Web Vitals

Join Joe Williams & Aleksandar Savkovic on 29th of March, 2021.

Do you like what you read?

Get the Latest Updates

Share Your Feedback

Please insert Content

Thank you for your feedback!

Do you like what you read?

Get the Latest Updates

Share Your Feedback

Please insert Content

Thank you for your feedback!

Want to Experience the Cloudways Platform in Its Full Glory?

Take a FREE guided tour of Cloudways and see for yourself how easily you can manage your server & apps on the leading cloud-hosting platform.

Start my tour

CYBER WEEK SAVINGS

  • 0

    Days

  • 0

    Hours

  • 0

    Mints

  • 0

    Sec

GET OFFER

For 4 Months &
40 Free Migrations

For 4 Months &
40 Free Migrations

Upgrade Now