Build a Real-Time Chat Application With Pusher and Laravel 5.1

To build a real-time chat application on laravel, we decided to use Pusher. Unfortunately Pusher isn’t open source but it does have a reasonable free package. We will implement a real-time chat application with Laravel, Mysql and Pusher.

The Scenario
1. A user will open the chat application in a browser and provides a nickname to continue the chat.
2. The user will enter some text and clicks the Send button.
3. The message will be handled by a service written using Laravel 5.1.
4. The message will be sent to Pusher in order to trigger a new message event to broadcast that message to connected clients.
5. The new message will be acquired by the clients, and the chat message list will be sent to all connected clients.

Laravel Project Setup

Of course, first we will need a fresh installation of the Laravel framework. You may install the Laravel framework using Composer:

composer create-project laravel/laravel laravel-pusher 5.1

Database
Our application will interact with a database, and it will be Mysql. Create a database with any name here we have created with name laravel_pusher. And create a table for users to store nickname of users and handle authentication.
Edit the users migration file and add some additional fields for our channel :

$table->increments('id');
$table->string('name');
$table->integer('chat_room_id')->unsigned();
$table->foreign('chat_room_id')->references('id')->on('chat_rooms')- >onDelete('CASCADE');
$table->timestamps();

Create another table ‘chat_rooms’ to handle channels from our database. Let’s use the make:migration command to generate a new database migration for our ‘chat_rooms’ table:

php artisan make:migration create_chat_rooms_table --create=chat_rooms

Now edit this file and add an additional string column for the name of our channels :

$table->increments('id');
$table->string('name');
$table->timestamps();

Model
We have to create models to access tables in our database. We will create two models User.php and ChatRoom.php in App/Http folder.
Edit User model with following code :

protected $table = 'users';
protected $fillable = array('name','chat_room_id');
public function chat_rooms()
{
return $this->belongsTo('App\ChatRoom', 'chat_room_id');
}

And ChatRoom model with following code:

protected $table = 'chat_rooms';
protected $fillable = array('name');

Pusher

Pusher provides a service to trigger events for real-time communication. You can go the Pusher Website to get one.

After successful account and application creation, you will be able to get some credentials like App ID, App Secret, and App Key. For this application we’ll use package vinkla/pusher. In order to install this package and use Pusher class in your Laravel project, you have to do the following:

1. Run following  command in your terminal to install vinkla/pusher pakage :

composer require vinkla/pusher

2. Add the following Pusher package to the config/app.php :

Vinkla\Pusher\PusherServiceProvider::class,

3. Add the reference in config/app.php to your aliases array as

'LaravelPusher' => Vinkla\Pusher\Facades\Pusher::class

Note that we have aliased facades as LaravelPusher instead of Pusher.
4. In your terminal publish the Pusher configuration file with this command

 php artisan vendor:publish

This command will create a config file config/pusher.php, and you need to provide the required credentials that you can find in your Pusher dashboard. The config file will be like below:

'connections' => [

'main' => [
'auth_key' => env('PUSHER_KEY'),
'secret' => env('PUSHER_SECRET'),
'app_id' => env('PUSHER_APP_ID'),
'options' => [],
'host' => null, %MCEPASTEBIN%
'port' => null,
'timeout' => null,
],

'alternative' => [
'auth_key' => 'your-auth-key',
'secret' => 'your-secret',
'app_id' => 'your-app-id',
'options' => [],
'host' => null,
'port' => null,
'timeout' => null,
],

Route

You can add your route configurations to the file app/Http/Route.php as below :

Route::get('/', 'ChatController@index');
Route::get('chat', 'ChatController@index');
Route::get('chat/chat', 'ChatController@chat');
Route::post('/chat/subscribe', 'ChatController@store');
Route::post('chat/getMessage', 'ChatController@getMessage');
Route::get('auth/logout', 'Auth\AuthController@getLogout');

Controller

In order to create a controller, simply create a file ChatController.php in App/Controllers folder and make that class extend a Laravel-specific class Controller which exists in App\Http\Controllers.

When you request the /chat endpoint, they will render their own templates under resources/views. You can do that by using the following actions:

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

public function chat(){
$user = Auth::user();
return view('chat.chat',compact('user'));
}

This methods will render specific pages.

Now we need to save the nickname by entered by user and authenticate. If the nickname exists we will authenticate by using that nickname for chat perticular channel.

public function store(Request $request)
{
$pusher_user['name'] = $request->name;
$pusher_user['chat_room_id'] = $request->chat_room_id;
$user = User::firstOrCreate($pusher_user);
Auth::loginUsingId($user->id);
return redirect('/chat/chat');
}

This method will authenticate user’s based on thier nickname and channel name.

When we authenticate user and redirect user to the chat view. User will enter message and send to the user. For this we need to send message to the pusher first by triggering the event.

public function getMessage(Request $request)
{
$user = Auth::user();
$channel = $user->chat_rooms['name'];

LaravelPusher::trigger($channel, 'message', array('message'=>$request->msj,'sender_name'=>$user->name),$request->socket_id);
echo json_encode(array('message'=>$request->msj));
}

This method method will trigger the event with the message by the user and we are also sending user name to display in application and socket_id. Note that this method will be called by an ajax call.

View

we have used the Blade template engine provided by Laravel. We have two view pages: index.blade.php and chat.blade.php in resources/views/chat folder.

First we create simple login page using html form in index.blade.php asking for user’s nickname and select channel like this :

Screenshot from 2016-03-16 16:52:02

Assign action as action=”{{url(‘/chat/subscribe’)}}” and method as method=”POST”.

Now create a view for real-time chatting with users logged in with specific channel in chat.blade.php like this:

Screenshot from 2016-03-16 17:10:49

In this page to send messages create a html form with action as action=”” and method method=”POST” and we will submit this form with ajax.
Now, We have a chat form to send messages, and Laravel puts a meta description in the page:

<meta name="csrf-token" content="{{ csrf_token() }}">

However, we are sending a chat message via AJAX, and there are no tokens in the AJAX request headers. We provide a solution by using the following code snippet:

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

Whenever you send an AJAX request, this token will be put inside the header.

To submit this form we will make ajax call as follows :

$('form').submit(function(){
$.post('getMessage', { msj: $('#enter_message').val(),soket_id: pusher.connection.socket_id}, function(response){

$("#comments").animate({ scrollTop: $(document).height() }, 0);
}, 'json');
document.getElementById('enter_message').value = "";

return false;
});

This will make an ajax call to getMessage method in ChatController.

In order to listen to the message channel in real time, we have used the following:

$(function(){
Pusher.log = function(message) {
if (window.console && window.console.log) {
window.console.log(message);
}
};
var pusher = new Pusher('54333db710da73106b7c', {
encrypted: true
});

var channel = pusher.subscribe();

channel.bind('message', function(response) {

$('#comments').append('

'+response.message+'
');

var sender_name = response;

if ( == sender_name.sender_name)
{
$('#comments').append('

-'+response.sender_name+'
');
}
else
$('#comments').append('

-'+response.sender_name+'
');

$("#comments").animate({ scrollTop: $(document).height() }, 0);

});

Here, we have pusher object with appId. And then, a client is subscribed to the channel. Whenever a new event with the name message and specific channel name arrives, a callback function will be executed inside the bind() function. The message list area will be appended with the new messages and the sender name also be appended below it as we are sending sender name from controller by triggering pusher event.

Why we used Pusher

Pusher has a nice channel/event model where you can subscribe to a channel, and then bind callbacks to specific events over that channel. This is a pretty natural way to implement message events.
Pusher supports SSL and SSL provides client to server encryption.
Overall, We’ve found that Pusher has better documentation/examples, a better API, and better backend/debug tools.

Limitations

  • Pusher has no server-side caching. This means that missed messages remained missed, there is a much higher chance of messages not getting through.
  • Pusher’s limits are 10kb per message as part of their normal offering. They offer larger message sizes for enterprise plans.

Conclusion

In this tutorial we have shown you how to setup Pusher with Laravel 5.1. We have used pusher to send realtime notifications.
We have focused on the real-time chat application in Laravel and saw that the Pusher libraries are very easy to handle thanks to Pusher.