0% found this document useful (0 votes)
174 views14 pages

Real Time

This document discusses how to set up real-time notifications with Laravel and React. It provides a 10 step process to: 1. Install Laravel Websockets and configure broadcasting in Laravel. 2. Create a notification class to send data to the frontend. 3. Define authorization routes and channels to securely broadcast notifications. 4. Configure the frontend with Echo and Pusher to listen for notifications. The goal is to allow sending notifications from the backend to be received in real-time by the frontend application using Laravel broadcasting and React. Key pieces include Laravel Websockets, Pusher, notifications, and authorization routes.

Uploaded by

Yu Wa
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
174 views14 pages

Real Time

This document discusses how to set up real-time notifications with Laravel and React. It provides a 10 step process to: 1. Install Laravel Websockets and configure broadcasting in Laravel. 2. Create a notification class to send data to the frontend. 3. Define authorization routes and channels to securely broadcast notifications. 4. Configure the frontend with Echo and Pusher to listen for notifications. The goal is to allow sending notifications from the backend to be received in real-time by the frontend application using Laravel broadcasting and React. Key pieces include Laravel Websockets, Pusher, notifications, and authorization routes.

Uploaded by

Yu Wa
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 14

Real Time Notification With Laravel API & React JS

To make real time notification, we need to separate as two parts: backe-end and front-end part.
Because, in back-end side, we make broadcast notification by using laravel websockets to send real time
notification.

Then, from front-end side, by using laravel-echo and pusher-js(both is javascript library), listen channel
from laravel websockets server and show notifications in front-end application.

So, I will start from back-end side laravel.

Notification Setup In Laravel Side


Laravel Version: 7.x

Package: Laravel Websockets

Ref Link:

https://laravel.com/docs/7.x/notifications

https://laravel.com/docs/7.x/broadcasting

https://laravel.com/docs/7.x/events

https://www.youtube.com/watch?v=7MvN0w5BW48&list=PLzz9vf6075V25O3jAzvBrU-
k4PscUWoLi&index=5

https://medium.com/@mihkelallorg/laravel-react-jwt-tokens-and-laravel-echo-with-pusher-for-
dummies-like-me-cafc5a09a1a1

Note: Before following step, you must already setup API authentication with laravel passport.

Step 1. Install Laravel Websockets with following command.


composer require beyondcode/laravel-websockets

This package comes with a migration to store statistic information while running your WebSocket server.
You can publish the migration file using:
php artisan vendor:publish --provider="BeyondCode\LaravelWebSockets\
WebSocketsServiceProvider" --tag="migrations"

Then, run migrations:


php artisan migrate

Next, you need to publish the WebSocket configuration file:


php artisan vendor:publish --provider="BeyondCode\LaravelWebSockets\
WebSocketsServiceProvider" --tag="config"

You can run websockets server with following command:


php artisan websockets:serve

Step 2. In config/app.php, remove comment from App\Providers\BroadcastServiceProvider::class.

Step 3. Then install pusher with following command.


composer require pusher/pusher-php-server "~4.0"
Step 4. In .env file, change Broadcast driver, pusher id and key as shown in below.

BROADCAST_DRIVER=pusher

PUSHER_APP_ID=841161584

PUSHER_APP_KEY=64498465165

PUSHER_APP_SECRET=asdf4a87f65464

We just use pusher as a broadcast driver. Not really use pusher paid service. So that, we can give any
random number that we want as app_id, app_key and app_secret keys.

Step 5. In config/broadcasting.php, add host, port, schema into pusher array as shown in below.
You can copy these lines from laravel websockets line:
https://beyondco.de/docs/laravel-websockets/basic-usage/pusher#pusher-configuration.

The reason of putting those lines because we tell pusher to use our local laravel websockets server,
instead of pusher server.

If your websockets server is on separate server with specified port, you can change in that place.

Step 6. Defining Authorization Routes

As we use broadcast notifications with private channel, we need to authorize that the currently
authenticated user can actually listen on the channel.

Laravel makes it easy to define the routes to respond to channel authorization requests.

In app/Providers/BroadcastServiceProvider.php, included with our Laravel application, we will see a


call to the Broadcast::routes() method. This method will register the /broadcasting/auth route to
handle authorization requests.

The Broadcast::routes() method will place its routes within the web middleware group; however, we
are making API, we can change web middleware to api middleware by passing parameter to
Broadcast::routes() method.

Add Broadcast::routes(['prefix' => 'api', 'middleware' => ['auth:api']]); into boot() method of this file.

<?php

namespace App\Providers;

use Illuminate\Support\Facades\Broadcast;
use Illuminate\Support\ServiceProvider;

class BroadcastServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        Broadcast::routes(['prefix' => 'api', 'middleware' => ['auth:api']]);

        require base_path('routes/channels.php');
    }
}
And we also add api prefix. So, /broadcasting/auth will change into /api/broadcasting/auth. You can
check that route changes with: php artisan route:list.

Step 7. Next, we need to define the logic that will actually perform the channel authorization. There’s
already an example channel defined for us in routes/channels.php file. I only changed the channel name
from App.User.{id} to App.EmployeePersonal.{id}

Broadcast::channel('App.EmployeePersonal.{id}', function ($user, $id) {
    return (int) $user->id === (int) $id;
});
Each user has its own channel and in this example only the user itself can subscribe to its channel.

Step 8. In our app/Models/EmployeePersonal.php, use Notifiable trait and add


receivesBroadcastNotificationsOn method. This is where we define the channel where the users
notifications start going through. Make sure it matches the defined channel in channels.php.

<?php

namespace App\Models;

use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Passport\HasApiTokens;

class EmployeePersonal extends Authenticatable
{
    use HasApiTokens, Notifiable;

    /**
     * The channels the user receives notification broadcasts on.
     *
     * @return string
     */
    public function receivesBroadcastNotificationsOn()
    {
        return 'App.EmployeePersonal.' . $this->id;
    }
}
Step 9. When sending notification, we also store that notification into database. We need to create a
table to store our notifications. Use following command to create a laravel default notifications table.
php artisan notifications:table

php artisan migrate

Now, our setup is complete for creating notifications table, broadcast channel to send notification and
broadcast channel authorization routes.

Step 10. Let assume, when a user is create a product, we will send notification to all users. To do that,
we will start create a notification class with followin command.
php artisan make:notification ProductNotify

This command will place a fresh notification class in your app/Notifications directory
[app/Notifications/ProductNotify.php]. You can give any name you want.

By creating notification class by artisan command, laravel will already place some methods:
__construct(), via(), toMail(), toArray().

Following is the complete code of ProductNotify.php.

<?php

namespace App\Notifications;

use Illuminate\Contracts\Broadcasting\ShouldBroadcastNow;
use Illuminate\Notifications\Messages\BroadcastMessage;
use Illuminate\Notifications\Notification;

class ProductNotify extends Notification implements ShouldBroadcastNow
{
    private $product;

    /**
     * Create a new notification instance.
     *
     * @return void
     */
    public function __construct($product)
    {
        $this->product = $product;
    }
    /**
     * Get the notification's delivery channels.
     *
     * @param  mixed  $notifiable
     * @return array
     */
    public function via($notifiable)
    {
        return ['database', 'broadcast'];
    }

    /**
     * Get the array representation of the notification.
     *
     * @param  mixed  $notifiable
     * @return array
     */
    public function toArray($notifiable)
    {
        return [
            'product_id' => $this->product->id,
            'product_name' => $this->product->product_name,
            'quantity' => $this->product->quantity,
            'page' => 'product',
            'message' => $this->product->message
        ];
    }

    /**
     * Get the broadcastable representation of the notification.
     *
     * @param  mixed  $notifiable
     * @return BroadcastMessage
     */
    public function toBroadcast($notifiable)
    {
        return new BroadcastMessage($this->toArray($notifiable));
    }

    public function broadcastType()
    {
        return 'new-product';
    }

}
__construct(): we will send product information as notification, we pass product object in constructor.

via(): as we will send broadcast notification and save into database, we need to set database and
broadcast.

toArray(): The toArray() method is also used by the broadcast channel to determine which data to
broadcast to your JavaScript client. If you would like to have two different array representations for the
database and broadcast channels, you should define a toDatabase method instead of a toArray
method. But, now, I will only use toArray() because we will send and save same notification data.

toMail(): We will remove toMail() method because we don’t need to send email, just send notification.

toBroadcast(): The broadcast channel broadcasts notifications using Laravel's event broadcasting
services, allowing your JavaScript client to catch notifications in realtime. If a notification supports
broadcasting, you can define a toBroadcast method on the notification class. This method will receive a
$notifiable entity and should return a BroadcastMessage instance.

broadcastType(): In addition to the data you specify, all broadcast notifications also have a type field
containing the full class name of the notification. If you would like to customize the notification type that
is provided to your JavaScript client, you may define a broadcastType method on the notification class.

Step 11. Create a ProductController[app/Http/Controllers/API/Product/ProductController.php]


php artisan make:controller API\Product\ProductController

Following is my sample code.

<?php

namespace App\Http\Controllers\API\Product;

use App\Http\Controllers\Controller;
use App\Models\EmployeePersonal;
use App\Models\Product;
use App\Notifications\ProductNotify;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Notification as FacadesNotification;

class ProductController extends Controller
{
    public function create(Request $req) {
        DB::beginTransaction();
        try {
            $product = new Product;
            $product->product_name = $req->product_name;
            $product->quantity = $req->quantity;
            $product->save();
            // sent notification to all users
            $users = EmployeePersonal::all();
            // add new custom message to show as notification in front-end
            $product->message = 'New product '.$product->product_name.' is creat
ed!';
            FacadesNotification::send($users, new ProductNotify($product));
            DB::commit();
            return response()->json(['message':'New Product Created!'], 200);
        } catch (\Throwable $th) {
            DB::rollBack();
            return response()->json((['message':$th->getMessage()], 400);
        }
    }
}

Inside of this class, when we create a new product, we will send notification to all users by using
notification facades FacadesNotification::send($users, new ProductNotify($product));. We also pass
our product object when calling notification class.

Step 12. This step is optional. If you want to show all notifications as a page in your web applications and
you want to set features like: Mark All As Read for all notifications or Mark As Read for a user clicked
notification, you can use following sample code.

Before start accessing notifications table, we need to create model for that table with following
commands. It will create a model in this path: app/Models/Notification.php
php artisan make:model Models\Notification

Then, create a controller that can work with notifications.


php artisan make:controller API\Notification\NotificationController

It will create controller in path: app/Http/Controllers/API/Notification/NotificationController.


Following is just sample code to show you concept.

<?php

namespace App\Http\Controllers\API\Notification;

use App\Http\Controllers\Controller;
use App\Models\EmployeePersonal;
use App\Models\Notification;
use Illuminate\Http\Request;

class NotificationController extends Controller
{
    /**
     * Show all unread notification for requested user
     * 
     * @param   userId
     */
    public function show(Request $req) {
        $result = [];
        $users = EmployeePersonal::find($req->user_id);
        foreach($users->unreadNotifications as $noti) {
            $tmp['id'] = $noti['id'];
            $tmp['notifiable_id'] = $noti['notifiable_id'];
            $tmp['message'] = $noti['data']['message'];
            $result[] = $tmp;
        }
        
        return response()->json(['data' => $result], 200);
    }

    /**
     * Make notification mark as read
     * 
     * @param   notifications id -> f3187479-ab6c-4ce2-8ddc-5103f28f7155
     */
    public function readNotification(Request $req) 
    {
        $read = Notification::where('id', $req->id)->update(['read_at'=>now()]);
        if ($read) {
            return response()->json(['message'=>'Mark as read'], 200);
        } else {
            return response()->json(['message'=>'Something wrong!'], 200);
        }
    }
    /**
     * Mark all notification as read
     * 
     * @param   userId
     */
    public function readAllNotifications(Request $req)
    {
        $user = EmployeePersonal::find($req->user_id);
        $user->unreadNotifications->markAsRead();
        return response()->json(['message'=>'mark all as read'], 200);
    }
}

show(): to show all user unread notifications. ‘unread’ means read_at column is NULL inside
notifications table for requested user.

readNotification(): make specific requested notification data to mark as read. ‘mark as read’ means
updating read_at column with current time inside notifications table for specific notification id.

readAllNotifications(): mark all as read for all notifications of requested user. It means updating read_at
column with current time inside notifications table for all of specific user id.

Step 13. Prepare your api route in routes/api.php to test.

Route::post('login', 'API\User\EmployeePersonalController@login');
Route::post('register', 'API\User\EmployeePersonalController@register');
Route::middleware(['auth:api'])->group(function() {
    Route::post('product-register', 'API\Product\ProductController@create');
    Route::get('notifications', 'API\Notification\NotificationController@show');
    Route::post('read', 'API\Notification\
NotificationController@readNotification');
    Route::post('read-all', 'API\Notification\
NotificationController@readAllNotifications');
});

Now, we are finised at back-end side. Let’s move to front-end side.


Acessing Real Time Notification In Front-end React JS
In React JS, please make following steps to listen broadcast channel from laravel and get message from
laravel websockets server.

Step 1. Installing Laravel Echo

Laravel Echo is a JavaScript library that makes it painless to subscribe to channels and listen for events
broadcast by Laravel. You may install Echo via the NPM package manager. In this example, we will also
install the pusher-js package since we will be using the Pusher Channels broadcaster:
npm install --save laravel-echo pusher-js

Step 2. Once Echo is installed, you are ready to create a fresh Echo instance in your application's
JavaScript. A good place to do this is inside of componentDidMount() method because we can update
state immediately if we got a new notification.

Following is just piece of code for how to instantiate Echo.

import Echo from "laravel-echo"

window.Pusher = require('pusher-js');
window.Echo = new Echo({
    broadcaster: 'pusher',
    key: 'your-pusher-channels-key'
});
Inside of Echo instance you can also make authentication. I will show later.

Step 3. Once you have installed and instantiated Echo, you are ready to start listening for broadcast
notifications. You may listen for the broadcast events using Echo's notification method. Remember, the
channel name should match the class name of the entity receiving the notifications:

window.Echo.private(`App.EmployeePersonal.${userId}`)
    .notification((notification) => {
        console.log(notification.type);
    });
In this example, all notifications sent to App\EmployeePersonal instances via the broadcast
channel would be received by the callback. A channel authorization callback for the
App.EmployeePersonal.{id} channel is included in the default BroadcastServiceProvider that
ships with the Laravel framework.

Note: Channel name that listen in Echo is the channel that we already made in laravel. See Step
7 of laravel side.
Following is the complete sample code of instainting laravel Echo and listen broadcast notification from
App.EmployeePersonal.{id} broadcast channel with channel authentication.

componentDidMount() {
    const token = 'xxxxxx-xxx-xxx';
    window.Pusher = require('pusher-js');
    window.Echo = new Echo({
      broadcaster: 'pusher',
      key: '64498465165',
      cluster: 'mt1',
      wsHost: window.location.hostname,
      wsPort: 6001,
      forceTLS: false,
      disableStats: true,
      //authEndpoint is your apiUrl + /broadcasting/auth
      authEndpoint: 'http://localhost/RealTimeNotiTest/public/api/broadcasting/
auth', 
      // As I'm using JWT tokens, I need to manually set up the headers.
      auth: {
        headers: {
          Authorization: 'Bearer '+token,
          Accept: 'application/json',
        },
      }
    });
    
    window.Echo.private('App.EmployeePersonal.5')
      .notification((notify) => {
        console.log(notify);
    });
}
key and cluster must be same that we already set in .env file inside laravel project. See Step 4 of laravel
side.

authEnpoint is the api url for broadcast authentication. This is related to Step 6 of laravel side.

In auth, we can set Authorization header for access token key and other necessary header.

Note: There is one important thing to notice that, token key that we set as authorization headers must
be user id’s token key that we listen in App.EmployeePersonal.id.

Now, in your front-end, you are ready to get notifications from laravel websockets server.
Following is the sample result to show you how it works.

Run websockets server.

Run front-end project.


Then, when create a new product in postman app, you will get new notification immediately.

You might also like