Spread the love

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

websocket server
websocket server

Leave a Reply