Real-Time Updates with Laravel 11 Reverb, Livewire 3, and Broadcasting

Real-Time Updates with Laravel 11 Reverb, Livewire 3, and Broadcasting

Real-Time Updates with Laravel 11 Reverb, Livewire 3, and Broadcasting.

In this blog post, we’ll explore how to set up and use broadcasting in Laravel 11 with Livewire 3. We’ll use a real-world project as an example, which includes creating and updating posts.

Step 1: Installation

Event broadcasting is accomplished by a server-side broadcasting driver that broadcasts your Laravel events so that Laravel Echo (a JavaScript library) can receive them within the browser client.

  1. Install broadcasting
  • By default, broadcasting is not enabled in new Laravel applications. You may enable broadcasting using the install:broadcasting Artisan command:

php artisan install:broadcasting

  • The install:broadcasting command will create a routes/channels.php file where you may register your application’s broadcast authorization routes and callbacks.
  • Before broadcasting any events, you should first configure and run a queue worker.
php artisan queue:work 

b) Reverb

  • When running the install:broadcasting command, you will be prompted to install Laravel Reverb. Of course, you may also install Reverb manually using the Composer package manager. Since Reverb is currently in beta, you will need to explicitly install the beta release:
composer require laravel/reverb:@beta
  • Once the package is installed, you may run Reverb’s installation command to publish the configuration, add Reverb’s required environment variables, and enable event broadcasting in your application:
php artisan reverb:install

Laravel Reverb brings blazing-fast and scalable real-time WebSocket communication directly to your Laravel application.

  • If you would like to make any configuration changes, you may do so by updating Reverb’s environment variables or by updating the config/reverb.phpconfiguration file.

Application Credentials

  • In order to establish a connection to Reverb, a set of Reverb “application” credentials must be exchanged between the client and server.
REVERB_APP_ID=my-app-id
REVERB_APP_KEY=my-app-key
REVERB_APP_SECRET=my-app-secret
  1. Running the Server
  • The Reverb server can be started using the reverb:startArtisan command:
php artisan reverb:start
  • By default, the Reverb server will be started at 0.0.0:8080, making it accessible from all network interfaces.
  • If you need to specify a custom host or port, you may do so via the –host and –port options when starting the server:
php artisan reverb:start --host=127.0.0.1 --port=9000
  • Alternatively, you may define REVERB_SERVER_HOSTand REVERB_SERVER_PORT environment variables in your application’s .env configuration file.
  1. Debugging
  • To improve performance, Reverb does not output any debug information by default. If you would like to see the stream of data passing through your Reverb server, you may provide the –debug option to the reverb:start command:
php artisan reverb:start --debug
  1. Restarting
  • Since Reverb is a long-running process, changes to your code will not be reflected without restarting the server via the reverb:restartArtisan command.
  • The reverb:restartcommand ensures all connections are gracefully terminated before stopping the server. If you are running Reverb with a process manager such as Supervisor, the server will be automatically restarted by the process manager after all connections have been terminated:
php artisan reverb:restart
  • Finally, you are ready to install and configure Laravel Echo, which will receive the broadcast events on the client-side.
  1. Laravel Echo is a JavaScript library that makes it painless to subscribe to channels and listen for events broadcast by your server-side broadcasting driver.
npm install --save-dev laravel-echo pusher-js
  • Once Echo is installed, you are ready to create a fresh Echo instance in your application’s JavaScript. A great place to do this is at the bottom of theresources/js/bootstrap.js file that is included with the Laravel framework.
  • By default, an example Echo configuration is already included in this file – you simply need to uncomment it and update the broadcaster configuration option to reverb:
import Echo from 'laravel-echo';

import Pusher from 'pusher-js';
window.Pusher = Pusher;

window.Echo = new Echo({
    broadcaster: 'reverb',
    key: import.meta.env.VITE_REVERB_APP_KEY,
    wsHost: import.meta.env.VITE_REVERB_HOST,
    wsPort: import.meta.env.VITE_REVERB_PORT ?? 80,
    wssPort: import.meta.env.VITE_REVERB_PORT ?? 443,
    forceTLS: (import.meta.env.VITE_REVERB_SCHEME ?? 'https') === 'https',
    enabledTransports: ['ws', 'wss'],
});

Next, you should compile your application’s assets:

npm run build

Step 2: Setting Up Events

In our project, we have two events: PostCreated and PostUpdated. These events are triggered when a post is created or updated, respectively. They are defined in the app/Events directory. Let’s start with the PostCreated event. Run the following command…

php artisan make:event PostCreated
<?php

namespace App\Events;

use App\Models\Post;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;

class PostCreated implements ShouldBroadcast
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

    public $post;

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

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

    // public function broadcastOn()
    // {
    //     return new Channel('posts');
    // }
}

The PostUpdated event is similar, but it’s triggered when a post is updated.

<?php

namespace App\Events;

use App\Models\Post;
use Illuminate\Broadcasting\Channel;
use Illuminate\Queue\SerializesModels;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;

class PostUpdated implements ShouldBroadcast
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

    public $post;

    /**
     * Create a new event instance.
     */
    public function __construct(Post $post)
    {
        $this->post = $post;
    }

    /**
     * Get the channels the event should broadcast on.
     *
     * @return array<int, \Illuminate\Broadcasting\Channel>
     */
    public function broadcastOn()
    {
        return new PrivateChannel('posts.'.$this->post->id);
    }
}

Step 3: Broadcasting Events

When a post is created or updated, we dispatch the corresponding event. This is done in the store and update methods of our blade and livewire components create.blade.php, edit.blade.php and list.blade.php, respectively.

Here’s how we dispatch the PostCreated event when a post is created: create.blade.php

use App\Events\PostCreated;

public function store(): void
    {
        $validated = $this->validate();

        // Create a new post and assign it to $post
        $post = auth()->user()->posts()->create($validated);

        // Dispatch the PostCreated event with the newly created post
        event(new PostCreated($post));

        $this->message = '';

        // Dispatch a Livewire event
        $this->dispatch('post-created');
    }

Listen For the PostCreated event (Public Channel)

Laravel Echo is a JavaScript library that makes it painless to subscribe to channels and listen for events broadcast by your server-side broadcasting driver. So go ahead and update the file echo.js.

window.Echo.channel('posts')
        .listen('.App\\Events\\PostCreated', (e) => {
            alert("A new post has been created: " + e.post.message);
            // Update the UI to show the new post
            // This could be adding the new post to a list, re-rendering a component, etc.
        });

The first line of code is a channel ‘posts’ that we are subscribed to. We listen for the ‘posts’ channel from our event (PostCreated.php) on the backend and post a Javacript alert message. You can update the UI anything you want depending on the type of application you’re creating.

Update the routes/channel.php

<?php

use App\Models\Post;
use App\Models\User;
use Illuminate\Support\Facades\Broadcast;

Broadcast::channel('posts', function ($user) {
    // Allow all authenticated users to listen to the channel
    return true;
});

In our routes/channel.php we have set the channel ‘posts’ to return true to allow anybody to listen on this channel whether authenticated or not.

Refresh the Posts

#[On('echo:posts,PostCreated')]
    #[On('post-created')]
    public function getPosts(): void
    {
        $this->posts = Post::with('user')
            ->latest()
            ->get();
    }

To get an instant update when you create a new post. You will have to listen for the PostCreated event and the posts will be created in real time without any page refresh.

 Listen For the PostCreated event (Private Channel)

window.Echo.private('posts')
    .listen('.App\\Events\\PostCreated', (e) => {
        alert("A new post has been created: " + e.post.message);
        // Update the UI to show the new post
        // This could be adding the new post to a list, re-rendering a component, etc.
    });

 

Dispatching the PostUpdated Event on Update.

We will start by dispatching the event (PostUpdated.php). This file is the edit.blade.php

use App\Events\PostUpdated;

public function update(): void
    {
        $this->authorize('update', $this->post);
 
        $validated = $this->validate();
 
        $this->post->update($validated);
 
        $this->dispatch('post-updated');

        event(new PostUpdated($this->post)); // Dispatch the event after the post has been updated
    }

In our list.blade.php file, we will create a JavaScript array of post IDs:

<script>
    var postIds = @json($posts->pluck('id'));
</script>

$posts->pluck(‘id’): This Laravel collection method is used to retrieve all of the values for a given key from the collection. In this case, it’s getting all of the id values from the $posts collection, which gives us a collection of all post IDs.

@json($posts->pluck(‘id’)): The @json Blade directive is used to convert the collection of post IDs to a JSON array.

var postIds = @json($posts->pluck(‘id’));: This line is setting a JavaScript variable postIds to the JSON array of post IDs. This gives you a JavaScript array of all post IDs.

Then, in your echo.js file, we will use this postIds array to subscribe to the PostUpdated event for each post:

  postIds.forEach(postId => {
            window.Echo.private(`posts.${postId}`)
                .listen('PostUpdated', (e) => {
                    alert("A post has been updated: " + e.post.message);
                    // Update the UI to show the updated post
                });
        });
      

postIds.forEach(postId => {…}): This line uses the forEach method to execute a function for each post ID in the postIds array. The postId parameter is the current post ID in the array.

Update the routes/channel.php

<?php

use App\Models\Post;
use App\Models\User;
use Illuminate\Support\Facades\Broadcast;

Broadcast::channel('posts', function ($user) {
    // Allow all authenticated users to listen to the channel
    return true;

Broadcast::channel('posts.{postId}', function (User $user, int $postId) {
    return $user->id === Post::findOrNew($postId)->user_id;
});});

 

The Broadcast::channel(‘posts.{postId}’, function (User $user, int $postId) {…}) line in our channels.php file is defining a private channel for each post.

When a user tries to listen on this channel, the provided callback function is executed to determine if the user is authorized to listen to the channel. The function receives the authenticated user and the post ID as parameters.

The return $user->id === Post::findOrNew($postId)->user_id; line is checking if the authenticated user is the creator of the post. If the user’s ID matches the post’s user_id, the user is authorized to listen to the channel.

Finally listen for the PostUpdated event

  #[On('echo:posts,PostUpdated')]
    public function edit(Post $post): void
    {
        $this->editing = $post;
 
        $this->getPosts();
    } 

In Summary:

Laravel’s event broadcasting allows you to broadcast your server-side Laravel events to your client-side JavaScript application using a driver-based approach to WebSockets.

The events may be easily consumed on the client-side using the Laravel Echo JavaScript package.

Events are broadcast over “channels“, which may be specified as public or private. Any visitor to your application may subscribe to a public channel without any authentication or authorization; however, in order to subscribe to a private channel, a user must be authenticated and authorized to listen on that channel.

Watch the video here:

Sign up for free tutorials in your inbox.

We don’t spam! Read our privacy policy for more info.

2 thoughts on “Real-Time Updates with Laravel 11 Reverb, Livewire 3, and Broadcasting”

    1. Sure, I can help you with that. Here is a step-by-step guide on how to connect from the FE directory to the BE directory using Laravel Reverb and Sanctum:

      Prerequisites:

      You have a Laravel project set up with Reverb and Sanctum installed.
      You have a frontend application (FE) that you want to connect to the backend (BE).
      Steps:

      Configure Reverb in your BE:

      Make sure you have installed Reverb and Sanctum in your Laravel project.
      Configure Reverb in your .env file by setting the BROADCAST_CONNECTION environment variable to reverb.
      Configure Sanctum in your .env file by setting the SANCTUM_STATE_MAX_AGE environment variable to a value that is appropriate for your application.
      Generate a Sanctum API token:

      Create a Sanctum API token for your FE application. You can do this by running the following command in your Laravel project:
      Bash
      php artisan sanctum:token create
      Use code with caution.
      This will generate a Sanctum API token. Save the token for later use.
      Configure the FE to connect to the BE:

      In your FE application, configure it to connect to the BE’s WebSocket endpoint. The WebSocket endpoint is typically ws://localhost:8000/ws.
      When connecting to the WebSocket endpoint, you will need to include the Sanctum API token that you generated in step 2. You can do this by adding the Authorization header to the WebSocket connection request. The value of the Authorization header should be Bearer {token}, where {token} is the Sanctum API token that you generated in step 2.
      Authenticate and authorize requests:

      Once you have connected to the WebSocket endpoint, you can start sending and receiving messages.
      To authenticate and authorize requests, you will need to include the Sanctum API token in the request headers. You can do this by adding the Authorization header to the request headers. The value of the Authorization header should be Bearer {token}, where {token} is the Sanctum API token that you generated in step 2.
      Here is an example of how to connect to the BE from the FE using JavaScript:

      JavaScript
      const socket = new WebSocket(‘ws://localhost:8000/ws’, {
      headers: {
      Authorization: `Bearer ${sanctumToken}`,
      },
      });

      socket.onmessage = (event) => {
      console.log(event.data);
      };

      socket.onopen = () => {
      console.log(‘Connected to WebSocket server’);
      };

      socket.onerror = (error) => {
      console.error(‘WebSocket error:’, error);
      };

      socket.onclose = () => {
      console.log(‘WebSocket connection closed’);
      };

Leave a Comment

Your email address will not be published. Required fields are marked *