How to create a Real-Time Chat using Laravel and Firebase
A comprehensive guide to make a real-time chat using Laravel 6 with firebase cloud messaging and laravel-fcm library.
Getting Started — Configuring Environment
Step : 1
Install composer
Step : 2
Create a Laravel 6 project named Chatsi
composer create-project — prefer-dist laravel/laravel Tweety “6.*”
Step : 3
Require laravel-ui for authentication
composer require laravel/ui=”1.*” — dev
Generate authentication with vue
php artisan ui vue — auth
Install dependancies and build
npm install && npm run dev
Step : 4
Start Development Server
php artisan serve
Step : 5
Create a database and and add it to the .env file. Then, migrate authentication tables
php artisan migrate
Make sure that authentications work properly
Installing FCM
Step : 6
Login to your google account and go to ‘console.firbase.google.com’
Create a project and give it a name. Here it is chatsi-realtime-laravel-chat
No need to tic google analytics option (not checked recommended)
Step : 7
Navigate to project settings and create a new web app from the icon below. Give it a name.
Step : 8
Copy the firebase link script tag in the line 2 and paste it inside resources>views>layouts> app.blade.php header tag.
Step : 9
Copy the remaining part of the script of firebase to the app.blade.php script section.
Step : 10
Navigate to Project Overview>Project Settings, register your app there and copy the generated code as publicVapidKey
Step : 11
Inside home.blade.php add below lines as a new script section.
@section('scripts')
<script>
// Retrieve Firebase Messaging object.
const messaging = firebase.messaging();
// Add the public key generated from the console here.
messaging.usePublicVapidKey("your publicVapidKey");
</script>
@endsection
Add FCM token to user table
Step : 12
Create a new controller called FCMController
php artisan make:controller FCMController
Step : 13
Make the FCMController looks like below
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\User;
class FCMController extends Controller
{
//
public function index(Request $req){
return "testing";
}
}
?>
Step : 14
Change the user table migration to add a fcm_token as below
Schema::create('users', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('name');
$table->string('email')->unique();
$table->timestamp('email_verified_at')->nullable();
$table->string('password');
$table->longText('fcm_token')->nullable();
$table->rememberToken();
$table->timestamps();
});
Migrate the changes using below command
php artisan migrate:fresh
Don’t forget to add the new filed to fillable variable inside User model.
Try to create a test user. It should be created with a null fcm_token.
Send FCM token to the server
Step : 15
Change your FCMController as below
public function index(Request $req){
$input = $req->all();
return response()->json($input);
}
Return a dummy response again.
Don’t forget to create a route in Api.php as below.
Route::post('/save-token', 'FCMController@index');
We will try to hit the end point with axios library.
Step : 16
Just add CDN script(jsDeliver CDN) inside out head tag in app.blade.php.
Step : 17
Add following lines to the home.blade.php.
@section('scripts')
<script>
// Retrieve Firebase Messaging object.
const messaging = firebase.messaging();
// Add the public key generated from the console here.
messaging.usePublicVapidKey("BNi8WFY0HVBE2YvPXCfj7wDGbURGAh6rD57klttmetVL-PDYCnPNOgvUfC_RZquDF6uXjS5f78PXAcnFI9KuNTE");
function sendTokenToServer(fcm_token) {
const user_id = '{{auth()->user()->id}}';
//console.log($user_id);
axios.post('/api/save-token', {
fcm_token, user_id
})
.then(res => {
console.log(res);
})
}
function retreiveToken(){
messaging.getToken().then((currentToken) => {
if (currentToken) {
sendTokenToServer(currentToken);
// updateUIForPushEnabled(currentToken);
} else {
// Show permission request.
//console.log('No Instance ID token available. Request permission to generate one.');
// Show permission UI.
//updateUIForPushPermissionRequired();
//etTokenSentToServer(false);
alert('You should allow notification!');
}
}).catch((err) => {
console.log(err.message);
// showToken('Error retrieving Instance ID token. ', err);
// setTokenSentToServer(false);
});
}
retreiveToken();
messaging.onTokenRefresh(()=>{
retreiveToken();
});
messaging.onMessage((payload)=>{
console.log('Message received');
console.log(payload);
location.reload();
});
</script>
@endsection
Step : 18
Change FCMController as below.
public function index(Request $req){
$input = $req->all();
$fcm_token = $input['fcm_token'];
$user_id = $input['user_id'];
$user = User::findOrFail($user_id);
$user->fcm_token = $fcm_token;
$user->save();
return response()->json([
'success'=>true,
'message'=>'User token updated successfully.'
]);
}
Try to go to homepage and see whether you can see the token in console. if not check your firebase keys and script links.
Installing Laravel FCM Library
Step : 19
Install laravel fcm library
composer require brozot/laravel-fcm
Step : 20
Register the Laravel-FCM provider to your app configuration
congif/app.php
'providers' => [
// ...
LaravelFCM\FCMServiceProvider::class,
]'aliases' => [
// ...
'FCM' => LaravelFCM\Facades\FCM::class,
'FCMGroup' => LaravelFCM\Facades\FCMGroup::class, // Optional
]
Creating the chat UI
Step : 21
I will use on document css for this. Let’s modify our home.blade.php file.
@section('content')
<style>
.chat-container {
display: flex;
flex-direction: column;
}
.chat {
border: 1px solid gray;
border-radius: 3px;
width: 50%;
padding: 0.5em;
}
.chat-left {
background-color: white;
align-self: flex-start;
}
.chat-right {
background-color: #3f9ae5;
align-self: flex-end;
}
.message-input-container {
position: fixed;
left: 0;
right: 0;
bottom: 0;
background-color: white;
border: 1px solid gray;
padding: 1em;
}
</style>
<div class="container" style="margin-bottom: 480px" >
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header">Dashboard</div>
<div class="card-body">
<div class="chat-container">
<p class="chat chat-right">
<b>A :</b><br>
message1 </p>
<p class="chat chat-left">
<b>B :</b><br>
message 2
</p>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="message-input-container">
<form action="" method="POST">
@csrf
<div class="form-group">
<label>Message</label>
<input type="text" name="message" class="form-control">
</div>
<div class="form-group">
<button type="submit" class="btn btn-primary">SEND MESSAGE</button>
</div>
</form>
</div>
@endsection
Chat migration and creation
Step : 22
Create a table named Chats and Chats model
php artisan make:migration create_chats_table
php artisan make:model Chat
Step : 23
Change your migration file as below.
Schema::create('chats', function (Blueprint $table) {
$table->bigIncrements('id');
$table->integer('sender_id');
$table->string('sender_name');
$table->longText('message');
$table->timestamps();
});
php artisan migrate:fresh
Step : 24
Add fillable fields to Chat model.
protected $fillable=[
'sender_id',
'sender_name',
'message'
];
Step : 25
Add following lines to the HomeController to display the chats.
public function createChat(Request $request)
{
$input = $request->all();
$message = $input['message'];
$chat = new Chat([
'sender_id' => auth()->user()->id,
'sender_name' => auth()->user()->name,
'message' => $message
]);
$chat->save();
return redirect()->back();
}
Step : 26
Add these lines to display the chat in home.blade.php.
<div class="chat-container">
@if(count($chats)==0)
<p>There is no chat yet.</p>
@endif
@foreach($chats as $chat )
@if($chat->sender_id === auth()->user()->id)
<p class="chat chat-right">
<b>{{$chat->sender_name}} :</b><br>
{{$chat->message}} </p>
@else
<p class="chat chat-left">
<b>{{$chat->sender_name}} :</b><br>
{{$chat->message}}
</p>
@endif
@endforeach
</div>
Step : 27
Make following routes in web.php
Route::get('/home', 'HomeController@index')->name('home');
Route::post('/home','HomeController@createChat')->name('home.createChat');
Step : 28
Make users and check whether messages are displaying.
Using Laravel FCM
Step : 29
Update the HomeController with the new methods below.
private function broadcastMessage($senderName, $message)
{
$optionBuilder = new OptionsBuilder();
$optionBuilder->setTimeToLive(60 * 20);
$notificationBuilder = new PayloadNotificationBuilder('New message from : ' . $senderName);
$notificationBuilder->setBody($message)
->setSound('default')
->setClickAction('http://localhost:8000/home');
$dataBuilder = new PayloadDataBuilder();
$dataBuilder->addData([
'sender_name' => $senderName,
'mesage' => $message
]);
$option = $optionBuilder->build();
$notification = $notificationBuilder->build();
$data = $dataBuilder->build();
$tokens = User::all()->pluck('fcm_token')->toArray();
$downstreamResponse = FCM::sendTo($tokens, $option, $notification, $data);
return $downstreamResponse->numberSuccess();
}
Update the createChat function as below.
public function createChat(Request $request)
{
$input = $request->all();
$message = $input['message'];
$chat = new Chat([
'sender_id' => auth()->user()->id,
'sender_name' => auth()->user()->name,
'message' => $message
]);
$this->broadcastMessage(auth()->user()->name,$message);
$chat->save();
return redirect()->back();
}
Don’t forget to Check the imports.
Step : 30
Go to cloud messaging section in the firebase console of google and add those keys to the .env file with your keys
FCM_SERVER_KEY = your key
FCM_SENDER_ID = your id
Check by logging with two users and messages will update now.
Send and Receive Messages with notification
Step : 31
Create a file named firbase-messaging-sw.js in public>js folder and add these codes and update it with your credentials.
// Give the service worker access to Firebase Messaging.
// Note that you can only use Firebase Messaging here, other Firebase libraries
// are not available in the service worker.
importScripts('https://www.gstatic.com/firebasejs/7.23.0/firebase-app.js');
importScripts('https://www.gstatic.com/firebasejs/7.23.0/firebase-messaging.js');
// Initialize the Firebase app in the service worker by passing in
// your app's Firebase config object.
// https://firebase.google.com/docs/web/setup#config-object
var firebaseConfig = {
apiKey: "your key",
authDomain: "your app url",
databaseURL: "your app db url",
projectId: "your project id",
storageBucket: "your storage bucket",
messagingSenderId: "your message senderid",
appId: "your app id"
};
// Initialize Firebase
firebase.initializeApp(firebaseConfig);
// Retrieve an instance of Firebase Messaging so that it can handle background
// messages.
const messaging = firebase.messaging();
messaging.setBackgroundMessageHandler(function(payload) {
console.log('[firebase-messaging-sw.js] Received background message ', payload);
// Customize notification here
const {title, body} = payload.notification;
const notificationOptions = {
body,
};
return self.registration.showNotification(title,
notificationOptions);
});
Try to send messages and you will see json objects of messages in console and receive notifications as well.
Thanks.
WHMLowe