Broadcasting is used to send real time message to client. In this article we will learn to use broadcast to send web socket event in laravel. Web sockets are used to communicate with client from server for real time communication.
Broadcasting very useful to send update to client when any update on server and we want to notify the user without reloading the current page.
For example sending real time messaged to user or notifications to users. Another example is queue, We want to perform so long task in background and then want to notify the user after completion of task.
In this example we will use laravel websocket package which gives ability to use pusher without any third party integration or paid service so this example will cover to use web sockets broadcasting free. this is a replacement package of Pusher APIs.
Let’s implement Use Broadcast to Send Web Socket Event in Laravel step by step easily
Step 1: Create a fresh laravel project
Open a terminal window and type below command to create a new project
composer create-project laravel/laravel blog
You can also read this to start with new project
Step 2: Install packages for websocket and configure
After setting up the project we need to install required packages and configuration so install the package using below command
composer require beyondcode/laravel-websockets
Package comes with migration so we need to create migration using follow command in terminal
php artisan vendor:publish --provider="BeyondCode\LaravelWebSockets\WebSocketsServiceProvider" --tag="migrations"
I assume the you have already installed the laravel and basic connection of it like database connection and composer.
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laravel-blog
DB_USERNAME=root
DB_PASSWORD=
And Run the migrations :
php artisan migrate
Next, you need to publish the WebSocket configuration file:
php artisan vendor:publish --provider="BeyondCode\LaravelWebSockets\WebSocketsServiceProvider" --tag="config"
Above command will publish a new configuration file as config/websockets.php
:
return [
/*
* This package comes with multi tenancy out of the box. Here you can
* configure the different apps that can use the webSockets server.
*
* Optionally you can disable client events so clients cannot send
* messages to each other via the webSockets.
*/
'apps' => [
[
'id' => env('PUSHER_APP_ID'),
'name' => env('APP_NAME'),
'key' => env('PUSHER_APP_KEY'),
'secret' => env('PUSHER_APP_SECRET'),
'enable_client_messages' => false,
'enable_statistics' => true,
],
],
/*
* This class is responsible for finding the apps. The default provider
* will use the apps defined in this config file.
*
* You can create a custom provider by implementing the
* `AppProvider` interface.
*/
'app_provider' => BeyondCode\LaravelWebSockets\Apps\ConfigAppProvider::class,
/*
* This array contains the hosts of which you want to allow incoming requests.
* Leave this empty if you want to accept requests from all hosts.
*/
'allowed_origins' => [
//
],
/*
* The maximum request size in kilobytes that is allowed for an incoming WebSocket request.
*/
'max_request_size_in_kb' => 250,
/*
* This path will be used to register the necessary routes for the package.
*/
'path' => 'laravel-websockets',
'statistics' => [
/*
* This model will be used to store the statistics of the WebSocketsServer.
* The only requirement is that the model should extend
* `WebSocketsStatisticsEntry` provided by this package.
*/
'model' => \BeyondCode\LaravelWebSockets\Statistics\Models\WebSocketsStatisticsEntry::class,
/*
* Here you can specify the interval in seconds at which statistics should be logged.
*/
'interval_in_seconds' => 60,
/*
* When the clean-command is executed, all recorded statistics older than
* the number of days specified here will be deleted.
*/
'delete_statistics_older_than_days' => 60,
/*
* Use an DNS resolver to make the requests to the statistics logger
* default is to resolve everything to 127.0.0.1.
*/
'perform_dns_lookup' => false,
],
/*
* Define the optional SSL context for your WebSocket connections.
* You can see all available options at: http://php.net/manual/en/context.ssl.php
*/
'ssl' => [
/*
* Path to local certificate file on filesystem. It must be a PEM encoded file which
* contains your certificate and private key. It can optionally contain the
* certificate chain of issuers. The private key also may be contained
* in a separate file specified by local_pk.
*/
'local_cert' => null,
/*
* Path to local private key file on filesystem in case of separate files for
* certificate (local_cert) and private key.
*/
'local_pk' => null,
/*
* Passphrase for your local_cert file.
*/
'passphrase' => null,
//'verfiy_peer' =>false
],
];
You don’t need to change anything but in future you can change the configuration according to your need like configuration of SSL certificates or port.
Pusher Package Replacement
Next, Install Pusher package to communicate the laravel with websocket
in same manner it connects with pusher
so install the package
composer require pusher/pusher-php-server
//for laravel 5,6,7 and 8
composer require pusher/pusher-php-server "~3.0"
and change broadcast driver in .env
file to pusher
as follow
BROADCAST_DRIVER=pusher
Pusher Configuration
You may be thinking that we are going to use this example without any third party services like pusher but why we are configuring the pusher but When broadcasting events from your Laravel application to your WebSocket server, the default behavior is to send the event information to the official Pusher server. But since the Laravel WebSockets package comes with its own Pusher API implementation, we need to tell Laravel to send the events to our own server
So configure the config/broadcasting.php
to use our laravel websocket as follow
'pusher' => [
'driver' => 'pusher',
'key' => env('PUSHER_APP_KEY'),
'secret' => env('PUSHER_APP_SECRET'),
'app_id' => env('PUSHER_APP_ID'),
'options' => [
'cluster' => env('PUSHER_APP_CLUSTER'),
'encrypted' => true,
'host' => '127.0.0.1',
'port' => 6001,
'scheme' => 'http'
],
],
Configure Pusher Detail in .env
Now, You don’t need to register and get the pusher details from anywhere. You can add any PUSHER_APP_ID ,PUSHER_APP_KEY and PUSHER_APP_SECRET details here as i have added READERSTACKS
PUSHER_APP_ID=READERSTACKS
PUSHER_APP_KEY=READERSTACKS
PUSHER_APP_SECRET=READERSTACKS
PUSHER_APP_CLUSTER=mt1
Step 3: Add Echo and Pusher in client side
Next, in this step we will add echo and pusher configuration in our JavaScript code. you are free to import anywhere in your code but as laravel recommend it to use it in resources/js/bootstrap.js so let’s first install the dependency in our laravel project and open the terminal
Open terminal in /var/www/html/laravel_project_name
npm install --save-dev laravel-echo pusher-js
and add the below code at last of the file in resources/js/bootstrap.js
import Echo from "laravel-echo"
window.Pusher = require('pusher-js');
window.Echo = new Echo({
broadcaster: 'pusher',
key: 'READERSTACKS',
wsHost: window.location.hostname,
wsPort: 6001,
forceTLS: false,
disableStats: true,
});
Laravel WebSockets package works nicely into Laravel Echo and to best fit in any frontend framework like react angular. If you are new to Laravel Echo, be sure to take a look at the official documentation.
Now, compile the change and generate minified public/js/app.js
file by running follow command
npm install
npm run dev
Let’s test our implementation now
Step 4: Generate Event Class
Event class is responsible for sending the event to specific events and in laravel we can easily create event using artisan command as below
php artisan make:event SendNotification
here, we are creating a simple event class to send the notification to client and server so change the code of app/Events/SendNotification.php
to below code
<?php
namespace App\Events;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Contracts\Broadcasting\ShouldBroadcastNow;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
class SendNotification implements ShouldBroadcastNow
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $message;
/**
* Create a new event instance.
*
* @return void
*/
public function __construct($message)
{
//
$this->message=$message;
}
/**
* Get the channels the event should broadcast on.
*
* @return \Illuminate\Broadcasting\Channel|array
*/
public function broadcastOn()
{
return new Channel('my-notifications');
}
}
here we have created a public new Channel('my-notifications');
my-notification which we will listen in javascript code in next step.
Also passed a $message
variable to constructor so we can pass any type of message to notification, then also notice one more thing which is ShouldBroadcastNow
interface so here we are instructing laravel to broadcast the event immediately, by default laravel send it to queue job and then process it to send the event to listeners so make sure you have QUEUE_CONNECTION=sync
in .env
file
QUEUE_CONNECTION=sync
If you want to use queue to process the event then you need to change the interface to ShouldBroadcast
in Event class.
Step 5: Create View
Let’s create a simple view for chat box
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Laravel Real Time Web socket Broadcast Using Events - Readerstacks </title>
<script src="{{asset('js/app.js')}}" crossorigin="anonymous"></script>
<script src="https://code.jquery.com/jquery-3.6.0.min.js" crossorigin="anonymous"></script>
<link href="//netdna.bootstrapcdn.com/bootstrap/4.1.1/css/bootstrap.min.css" rel="stylesheet" />
</head>
<body>
<div class="container">
<div class="panel panel-primary">
<div class="panel-heading">
<h2>Laravel Real Time Web socket Broadcast Using Events - Readerstacks</h2>
</div>
<div class="panel-body">
Logged In as : {{@request()->username}}
<div id="messages"></div>
<form id="chatbox" action="{{url('send-notification')}}" >
<div class="form-group">
<label>Message</label>
<input type="text" id='text' name="message" value="" class="form-control" />
</div>
<div class="form-group">
<button class="btn btn-primary">Send</button>
</div>
</form>
</div>
</div>
</div>
</body>
<script>
$(function() {
Echo.channel('my-notifications')
.listen('SendNotification', (e) => {
$("#messages").append("<br>"+JSON.stringify(e));
});
$("#chatbox").on("submit", function(e) {
e.preventDefault();
var action = $(this).attr("action");
var message = $("#text").val();
$.get(action+"?message="+message, function(data) {
$("#text").val('');
})
return false;
});
});
</script>
</html>
here we simply added jQuery for simple client side operations and bootstrap for UI then app.js
which is most important part of this example so don’t forget to add it
<script src="{{asset('js/app.js')}}" crossorigin="anonymous"></script>
and script to listen laravel echo and send the message using Ajax
<script>
$(function() {
Echo.channel('my-notifications')
.listen('SendNotification', (e) => {
$("#messages").append("<br>"+JSON.stringify(e));
});
$("#chatbox").on("submit", function(e) {
e.preventDefault();
var action = $(this).attr("action");
var message = $("#text").val();
$.get(action+"?message="+message, function(data) {
$("#text").val('');
})
return false;
});
});
</script>
Step 6: Create routes
To test our implementation we will create two routes first for show the view and second for communication between two clients using laravel echo and WebSockets
<?php
use Illuminate\Support\Facades\Route;
use Illuminate\Http\Request;
Route::get('/',function(){
return view("chat");
});
Route::get('/send-notification',function(Request $request){
event(new \App\Events\SendNotification($request->message));
return "Sent Successfully";
});
Step 6: Start the websocket and php server
Now, finally start our both the servers to check our implementation
start websocket server in one terminal
php artisan websockets:serve
and php server
php artisan serve
Open two tabs with same Url http://localhost:8000?username=Bot
, http://localhost:8000?username=Tester
, and start chatting