Implement Broadcasting systems on Private Channels with Laravel & Ably

Harshana Serasinghe
8 min readFeb 27, 2023
Image Credits — Freepik

In the modern world of the web and mobile, We have seen a huge amount of applications which send real-time notifications. Real-time notifications enhance the User Experience to a greater extent because of the easiness of receiving notifications on the user’s end.

Laravel provides the layout to support message broadcasting or web sockets out of the box. It currently supports a few libraries such as “Socketi”, and “Laravel-Websockets” and 3rd party solutions such as Pusher & Ably. In this article, let’s talk about how to design and implement a broadcasting system with Laravel & Ably.

There are 3 types of channels that can be created in Laravel.

  1. Public Channels which don’t require any authentication
  2. Private Channels which require authentication
  3. Presence Channels — They also require authentication and have the ability to register client presence on the channel.

In this article, let’s talk about implementing Private channel communication in Laravel with Ably. You can find an article on how to implement the communication with Public channels from Ably’s blog.

The Tech Stack

For this implementation, We are going to use the following:

  1. Laravel as the application back-end
  2. Vue as the application front-end
  3. Ably as the message sender

The Design

In Laravel, We can create events to trigger various things. This helps the developers to decouple their main execution code and any other code that needs to be executed after the main process. In our application, we base an event trigger to send messages to the Private channel via Ably. Once Ably receives the message, it will broadcast the message to all the users who have authenticated and listened to that private channel.

The Implementation

1 — Initiating the Laravel Project & Installing the required dependencies

You can use the following command in the terminal to create the Laravel Project

composer create-project laravel/laravel laravel-ably-app

Once the project is created, We’ll have to install Ably’s libraries required for both Frontend & Backend.

To install the libraries required for the backend, run the following command:

composer require ably/laravel-broadcaster

To install the frontend libraries, run the following command:

npm install @ably/laravel-echo ably

2 — Setup Ably API Key with Laravel

Follow the below steps to get an API Key from Ably and setup inside your Laravel Project.

  1. Create an account in Ably
  2. Visit the Ably Dashboard and create a new app

3. After the app is created, you will be redirected to the app’s settings page.

4. Navigate to the “API Keys” section and click the “Show” button in the first API Key section. Then it will allow you to copy the code into the clipboard.

Also, you can create a new API key with custom capabilities by clicking the “Create a new API Key” button.

Once the key is copied, Open up your Laravel project and navigate into the “.env” file and paste the API Key as the value for the environment variable “ABLY_KEY”

ABLY_KEY="0JUg2w.xxxxxxxxxxxxxxxxxxxxxxxxxxx"

3 — Configure Ably with Laravel

In order to use Ably with Laravel, we need to specify the Broadcast Driver of the Laravel application as “Ably”. Navigate into the “.env” file and edit the “BROADCAST_DRIVER” key with the value “Ably”.

BROADCAST_DRIVER=ably

After that, we need to enable the Broadcast Service Provider. Navigate to the “app.php” file in the config directory and uncomment the line “ App\Providers\BroadcastServiceProvider::class”

/*
* Application Service Providers...
*/
App\Providers\AppServiceProvider::class,
App\Providers\AuthServiceProvider::class,
App\Providers\BroadcastServiceProvider::class,
App\Providers\EventServiceProvider::class,
App\Providers\RouteServiceProvider::class,

If you’re using Laravel 8 or older, you need to define the Ably driver in the broadcasting.php file as well. Navigate into the “broadcasting.php” file in the config directory and add the following lines inside the “connections” array.

'ably' => [
'driver' => 'ably',
'key' => env('ABLY_KEY')
],

After adding the lines, it should look like the below:

'connections' => [
'pusher' => [
// Pusher configuration here...
],

'ably' => [
'driver' => 'ably',
'key' => env('ABLY_KEY'),
],

'redis' => [
'driver' => 'redis',
'connection' => 'default',
],
]

4 — Create an Event in the Laravel application

To send messages to the front end, we’ll use an event. In order to create the event, use the following command:

php artisan make:event NewMessageEvent

Once it is created, navigate to the file. You can find the created file inside the “Events” directory.

The event does not broadcast messages by default. Therefore, we’ll have to add the “ShouldBroadcast” interface into the Event class to enable the broadcast functionality.

class NewMessageEvent implements ShouldBroadcast
{
// Code
}

Our Event class will use two parameters to initiate the class. The parameters will be “$channelName” and “$message”

class NewMessageEvent implements ShouldBroadcast
{
private $channelName;
private $message;

/**
* Create a new event instance.
*
* @return void
*/
public function __construct($channelName, $message)
{
$this->channelName = $channelName;
$this->message = $message;
}
}

After that, we need to define to which channel we should broadcast the message to. For that, you can use the “broadcastOn” method. Since we’re implementing broadcasting on Private channels, we’ll use the “PrivateChannel” class in Laravel.


class NewMessageEvent implements ShouldBroadcast
{
private $channelName;
private $message;

/**
* Create a new event instance.
*
* @return void
*/
public function __construct($channelName, $message)
{
$this->channelName = $channelName;
$this->message = $message;
}
}

/**
* Get the channels the event should broadcast on.
*
* @return \Illuminate\Broadcasting\Channel|array
*/
public function broadcastOn()
{
return new PrivateChannel($this->channelName);
}

The final file will look similar to the below one:

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\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;

class NewMessageEvent implements ShouldBroadcast
{
private $channelName;
private $message;

use Dispatchable, InteractsWithSockets, SerializesModels;

/**
* Create a new event instance.
*
* @return void
*/
public function __construct($channelName, $message)
{
$this->channelName = $channelName;
$this->message = $message;
}
}

/**
* Get the channels the event should broadcast on.
*
* @return \Illuminate\Broadcasting\Channel|array
*/
public function broadcastOn()
{
return new PrivateChannel($this->channelName);
}

5 — Create a Channel in Laravel & Set Security Logic

This is similar to a route in Laravel. You can define which channel name should go to which Channel class. In order to create a channel, you can use the following command:

php artisan make:channel Message

Once the channel is created, We can add the security logic. Since we’re creating the broadcasting system for authenticated users, we can use Laravel’s Authentication functions. Navigate into the newly created event which is located in the “Broadcasting” directory and add the following code inside the “join” method:

namespace App\Broadcasting;

use App\Models\User;

class Message
{
/**
* Create a new channel instance.
*/
public function __construct()
{
//
}

/**
* Authenticate the user's access to the channel.
*/
public function join(User $user): array|bool
{
return Auth::check() && (int) $user->id == Auth::id();
}
}

This will check whether the user is logged in and whether the requesting user’s user ID is equal to the Logged in user’s User ID.

After that, We have to define the channel name in the “channels.php” file which is located in the “routes” directory.

Broadcast::channel('message', 'App\Broadcasting\Message');

The first argument defines the channel name and the second argument defines the Channel Class.

6 — Add Frontend code

To initialize Ably & Laravel Echo, You need to add the following code to the “bootstrap.js” file which is located in the “resources/js” directory.

import Echo from '@ably/laravel-echo';

window.Ably = require('ably');

// Create new echo client instance using ably-js client driver.
window.Echo = new Echo({
broadcaster: 'ably',
});

// Register a callback for listing to connection state change
window.Echo.connector.ably.connection.on((stateChange) => {
console.log("LOGGER:: Connection event :: ", stateChange);
if (stateChange.current === 'disconnected' && stateChange.reason?.code === 40142) { // key/token status expired
console.log("LOGGER:: Connection token expired https://help.ably.io/error/40142");
}
});

The above code will initialize Laravel Echo with Ably Integrated and pass it as a “window” variable in JavaScript. Then it will try to connect with the Web Socket.

— — — — —

Tip on How to implement this if you’re using Vanilla JS

If you’re using Vanilla JS, first you have to compile the above code by running the following command:

npm run build

This will create a compiled version of the code in the “public/build/assets” directory. You can directly link them as an asset in your Frontend code.

— — — — —

Once the above code is added, you can add the below code which will listen to the private channel and log the messages.

window.Echo.private('message')
.subscribed(function(){
console.log('subscribed To Channel')
})
.listenToAll(function(){
console.log('listening to channel')
})
.listen('NewMessageEvent', (data) => {
console.log(data);

});

The above code will subscribe to the “message” channel that we created in the backend. Then it will listen for “NewMessageEvent”. Once there is a new message, it will console log the message.

7 — Sending Messages to the Frontend by Triggering the event

You can send messages to the WebSocket whenever you need. In this project, Let’s implement the triggering logic when another user visits the same page that all the other users are currently viewing.

First, You need to create a new controller called “HomeController”

php artisan make:controller HomeController

Then, You can navigate to the HomeController by visiting the “app/Http/Controllers” directory.

Then, You need to create a new method called “index” which we’ll use as the home page method.

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class HomeController extends Controller
{
public function index(){

return 'Hello World!';
}
}

After that, you need to add the event trigger with the Event Import.

<?php

namespace App\Http\Controllers;

use App\Events\NewMessageEvent;
use Illuminate\Http\Request;

class HomeController extends Controller
{
public function index(){

event(new NewMessageEvent('message', 'New user Visited'));

return 'Hello World!';
}
}

This will return a page with the text “Hello World!” which listens to the web socket.

Then, You need to add a route which triggers the method. Navigate to the “web.php” file which is located in the “routes” directory and add the following code:

use App\Http\Controllers\HomeController;

Route::get('/user', [HomeController::class, 'index']);

The final “web.php” file will look like the below:

<?php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\HomeController;

Route::get('/user', [HomeController::class, 'index']);

8 — Adding Authentication & Testing

You can install the Laravel Breeze starter kit with your application to add authentication by using this guide by official Laravel Documentation.

Once it is installed, the route that you created earlier might have disappeared. You can add it by following the 7th step again.

After that, You can navigate from your browser to the “register” route created by Laravel Breeze and create a new user. Then, Log in to the user and navigate to the home page that (route “/”) we created earlier.

Then, you can open the console and a duplicate of the same tab. After that, you will see a console log added by the Web Socket.

Now you’re all set to broadcast and receive messages in your Laravel application!

--

--

Harshana Serasinghe

In love with tech ever since I got to know what a computer is :)