In today’s article, I am going to create a chatroom using Laravel, 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.
Here is a list of components that I will use for this application:
- Laravel Auth
- Laravel Mix
- Laravel Broadcast
- Pusher for Laravel and VueJS
- Bootstrap
Check out the following GIF for server and application launch.
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:
1
|
php artisan migrate
|
Next, create a basic auth by running the following command:
1
|
php artisan make:auth
|
Create a factory for creating a few users. For this, head to database/factoriesand open ModelFactory.php. Paste the following code in it.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
$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:
1
|
php artisan tinker
|
Now. run the following command to create ten users.
1
|
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:
1
2
3
|
php artisan queue:table
php artisan queue:failed–table
|
Now run the following command for the migration:
1
|
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:
1
|
php artisan make:event ChatMessage
|
Go to app/Events folder and open ChatMessage.php.
Start by implementing the class with ShouldBroadcast:
1
|
class ChatMessage implements ShouldBroadcast
|
Next, create a new public variable $user
. Replace the constructor with the following:
1
2
3
4
5
6
7
8
9
|
public function __construct($user)
{
//
$this->user = $user;
}
|
And, replace broadcastOn
with the following:
1
2
3
4
5
6
7
|
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:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
|
<?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:
1
|
composer require pusher/pusher–php–server
|
Now in the .env file, set the values for the following items:
1
2
3
4
5
6
7
|
BROADCAST_DRIVER=
PUSHER_APP_ID=
PUSHER_APP_KEY=
PUSHER_APP_SECRET=
|
Next, I will create the chat controller.
The Chat Controller
Run the following command in the console:
1
|
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.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware(‘auth’);
}
|
Now create a new function which sends the chat message:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
/**
* 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()
:
1
2
3
4
5
6
7
8
9
|
public function chatPage()
{
$users = User::take(10)->get();
return view(‘chat’,[‘users’=> $users]);
}
|
The final version of ChatController.php will look like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
|
<?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:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
|
@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=“http://placehold.it/50/55C1E7/fff&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:
1
2
3
4
5
|
@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.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
|
<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=“http://placehold.it/50/55C1E7/fff&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.
1
2
3
|
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:
1
|
npm install
|
Now run the following command to install VueResource, which I will use for HTTP requests.
1
|
npm install vue–resource
|
Now go to resources/assets/js and open app.js file. Replace the code in it with the following:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
|
/**
* 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.
1
|
npm run dev
|
This is how this code works:
First I imported Pusher and vue-resource components:
1
2
3
4
5
|
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:
1
2
3
4
5
6
7
8
9
|
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:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
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):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
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.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
|
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.
Source: https://www.cloudways.com