How to Add Real-Time Comments in Laravel 11 with Laravel Reverb

How to Add Real-Time Comments in Laravel 11 with Laravel Reverb

In this guide, we will create a real-time commenting system for a Laravel 11 application. This system will enable users to see and post comments instantly, without needing to refresh the page. By integrating Laravel Echo, Laravel Reverb, and Pusher, we will ensure that comment updates are broadcasted in real time.

What is Laravel Reverb?

Laravel Reverb is a broadcasting driver designed for real-time communication in Laravel applications. It allows users to receive updates instantly as they occur. With Reverb, you can handle real-time notifications, chat messages, and other dynamic interactions. This tutorial will show you how to set up and configure Laravel Reverb to enable real-time commenting functionality in your Laravel application.

What We Will Do

  • Install Laravel 11: set up a new Laravel project.
  • Set Up Authentication: Use Laravel UI to scaffold authentication.
  • Create the Comment System: Implement controllers, routes, and the necessary logic for handling comments.
  • Install and Configure Laravel Reverb: Set up Laravel Reverb for real-time broadcasting.
  • Set up Broadcasting: Configure broadcasting with events and channels.
  • Install and Configure laravel-echo pusher-js: Set up Pusher as an alternative or additional broadcasting driver.
  • Create Blade Templates: Design the front-end to display and submit comments.
  • Configure JavaScript for Echo: Handle real-time updates on the client side.

1. Installing Laravel 11

To start, we need to install Laravel 11. Use Composer to create a new Laravel project by using the following code:

composer create-project --prefer-dist laravel/laravel laravel-realtime-comments

Navigate to the project directory by using the following code:

cd laravel-realtime-comments

2. Setting Up Authentication with Laravel UI

Authentication is animportant part of any application, and Laravel UI makes it easy to set up. We'll use Laravel UI to generate the necessary views and routes for user authentication.

Install Laravel UI by using the following code:

composer require laravel/ui

Generate the authentication scaffolding using Bootstrap:

php artisan ui bootstrap --auth

Lastly install the npm dependencies and compile the assets:

npm install && npm run dev

With authentication set up, users can now register, log in, and log out, which is necessary for identifying who is posting the comments.

3. Creating the Comment System

Comment Controller

We need to create a controller to handle the storage and retrieval of comments. This controller will manage the logic for saving comments to the database and broadcasting them in real-time. To create the comment controller use the following code.

php artisan make:controller CommentController

Edit  app/Http/Controllers/CommentController.php  to include:

Edit  app/Http/Controllers/CommentController.php  to include the following methods:

namespace App\Http\Controllers; use App\Events\CommentPosted; use App\Models\Post; use Illuminate\Http\Request; class CommentController extends Controller { public function store(Request $request, Post $post) { $validated = $request->validate([ 'comment' => 'required|string|max:255', ]); $validated['user_id'] = auth()->user()->id; $comment = $post->comments()->create($validated); broadcast(new CommentPosted($comment))->toOthers(); return response()->json([ 'status' => 'success', 'message' => 'Comment posted successfully.', 'comment' => $comment, ], 200); } public function index(Post $post) { $comments = $post->comments()->latest()->get(); return response()->json($comments); } }

This comment controllerallows us to handle all aspects of comment management, from storing new comments to retrieving existing ones.

3. Routes

We need to define routes to handle comment-related actions. These routes will connect our controller methods to specific URLs in the application.

Add the following routes in routes/web.php:

Route::get('/home', [App\Http\Controllers\HomeController::class, 'index'])->name('home'); Route::get('/posts/{post}/comments', [CommentController::class, 'index'])->name('comments.index'); Route::post('/posts/{post}/comments', [CommentController::class, 'store'])->name('comments.store'); Auth::routes();

These routes allow users to fetch and post comments on specific posts, which is the basis for our real-time commenting system.

4. Installing and Configuring Laravel Reverb

Laravel Reverb is a broadcasting driver designed for real-time communication in Laravel applications. It allows users to receive updates instantly as they occur. We’ll install Reverb along with Laravel Echo, which will be used on the client side to listen for broadcasted events.

Install Laravel Echo and Reverb by using the following code:

php artisan install:broadcasting

.env Configuration

we need to configure the .env file to include Reverb settings. This configuration will tell Laravel to use Reverb for broadcasting events.

Adjust the following code to your .env file:

BROADCAST_CONNECTION=reverb REVERB_APP_ID=151212 REVERB_APP_KEY=1rcztnsuiavyzgsomsms REVERB_APP_SECRET=uezrgv668uyajdrlq69x REVERB_HOST="localhost" REVERB_PORT=8080 REVERB_SCHEME=http VITE_REVERB_APP_KEY="${REVERB_APP_KEY}" VITE_REVERB_HOST="${REVERB_HOST}" VITE_REVERB_PORT="${REVERB_PORT}" VITE_REVERB_SCHEME="${REVERB_SCHEME}"

5. Setting Up Broadcasting

Broadcasting events is at the core of any real-time system. We’ll create an event that will be broadcasted whenever a comment is posted.

Generate the CommentPosted event by using the following code:

php artisan make:event CommentPosted

Inside the generated event class, include the necessary properties and the  broadcastOn  method to define the channel the event will broadcast on. Here’s an example:

namespace App\Events; use App\Models\Comment; use Illuminate\Broadcasting\InteractsWithSockets; use Illuminate\Broadcasting\PrivateChannel; use Illuminate\Contracts\Broadcasting\ShouldBroadcastNow; use Illuminate\Foundation\Events\Dispatchable; use Illuminate\Queue\SerializesModels; class CommentPosted implements ShouldBroadcastNow { use Dispatchable, InteractsWithSockets, SerializesModels; public $comment; public function __construct(Comment $comment) { $this->comment = $comment; } public function broadcastOn(): array { return [ new PrivateChannel("posts.{$this->comment->post_id}"), ]; } public function broadcastAs() { return 'CommentPosted'; } /** * The data to broadcast with the event. * * @return array */ public function broadcastWith() { return [ 'id' => $this->comment->id, 'user_id' => $this->comment->user_id, 'comment' => $this->comment->comment, 'created_at' => $this->comment->created_at, ]; } }

Channels Configuration

To make sure that events are only broadcast to the right users, we’ll configure the broadcast channels in routes/channels.php.

Add the following channel configuration:

Broadcast::channel('posts.{id}', function ($user) { return true; });

6. Installing and Configuring Pusher

Pusher is a popular service for managing broadcasting events. While Reverb handles broadcasting within your Laravel application, Pusher can be used as an alternative or additional broadcasting driver.

Install Pusher using npm:

npm install --save laravel-echo pusher-js

7. Blade Template for Comments

We will create a Blade template that displays comments and includes a form for submitting new comments. This template will be responsible for rendering the front-end of our real-time commenting system.

Create a  comments.blade.php  file in the resources/views directory and add the following content:

This simple template lists all comments and provides a form for adding new ones. When a user submits the form, the comment will be posted in real-time, thanks to the broadcasting we’ve set up.

<extends>('layouts.app') @section('content') <div class="container"> <div class="row justify-content-center"> <div class="col-md-8"> <div class="container"> <h1>Title: {{ $post->title }}</h1> <p>Body: {{ $post->body }}</p> <div id="comments-section" data-comment-section data-post-id="{{ $post->id }}" data-comment-list="comments-list" data-comment-form="comment-form"> <div class="card mb-4"> <div class="card-header"> <h5>Comments</h5> </div> <div class="card-body" class="mb-5"> <ul class="list-group" id="comments-list"> <!-- Comment 1 --> </ul> </div> </div> <div> <!-- Comments will be dynamically loaded here --> </div> <form id="comment-form" method="POST" action="{{ route('comments.store', $post) }}"> @csrf <div class="mb-3"> <label for="comment-body" class="form-label">Your Comment</label> <textarea class="form-control" name="comment" id="comment-body" rows="3" placeholder="Enter your comment"></textarea> </div> <button type="submit" class="btn btn-primary">Submit Comment</button> </form> </div> </div> </div> </div> </div> @endsection

8. JavaScript Configuration for Echo

We will configure the JavaScript to listen for new comments using Laravel Echo. This will make sure that whenever a comment is posted, it appears in real-time for all users viewing the post.

Add the following JavaScript to your  resources/js/app.js  file:

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'], }); class CommentSection { constructor(postId, commentListId, commentFormId) { this.postId = postId; this.commentList = document.getElementById(commentListId); this.commentForm = document.getElementById(commentFormId); this.commentInput = this.commentForm.querySelector('textarea'); this.setupEventListeners(); this.fetchComments(); this.listenForNewComments(); } setupEventListeners() { this.commentForm.addEventListener('submit', (e) => { e.preventDefault(); this.addComment(); }); } async fetchComments() { try { // console.log("Fetching comments for post:", this.postId); const response = await fetch(`/posts/${this.postId}/comments`); if (!response.ok) { throw new Error('Network response was not ok'); } const comments = await response.json(); this.renderComments(comments); // console.log("Comments fetched and rendered"); } catch (error) { console.error("Error fetching comments:", error); } } renderComments(comments) { this.commentList.innerHTML = comments.map(comment => this.createCommentHTML(comment)).join(''); } createCommentHTML(comment) { return `
  • Posted by User ${comment.user_id} - ${new Date(comment.created_at).toLocaleString()}

    ${comment.comment}

  • `; } async addComment() { const content = this.commentInput.value.trim(); if (!content) return; try { // console.log("Adding comment:", content); const response = await fetch(`/posts/${this.postId}/comments`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').getAttribute('content'), }, body: JSON.stringify({ comment: content }), }); if (response.ok) { this.commentInput.value = ''; // console.log("Comment added successfully"); } else { throw new Error('Network response was not ok'); } } catch (error) { console.error("Error adding comment:", error); } } listenForNewComments() { window.Echo.private(`posts.${this.postId}`) .listen('.CommentPosted', (e) => { console.log("New comment received:", e); const commentHTML = this.createCommentHTML(e); this.commentList.insertAdjacentHTML('beforeend', commentHTML); }); } } // Initialize comment sections when the DOM is loaded document.addEventListener('DOMContentLoaded', () => { const commentSections = document.querySelectorAll('[data-comment-section]'); commentSections.forEach(section => { const postId = section.dataset.postId; const listId = section.dataset.commentList; const formId = section.dataset.commentForm; new CommentSection(postId, listId, formId); }); });

    Steps:

    • Configure Laravel Echo: Set up Laravel Echo with a broadcasting service like Reverb or Pusher to handle real-time events.
    • Initialize DOM: On page load, identify all comment sections and initialize the CommentSection class for each.
    • Create CommentSection Class:
    • Constructor: Initializes the class with the necessary IDs and sets up event listeners.
    • addComment: Handles adding a new comment via AJAX, posting it to the server.
    • fetchComments: Retrieves existing comments from the server and displays them.
    • listenForNewComments: Uses Echo to listen for new comment events in real-time and updates the UI accordingly.
    Tags
    Laravel Reverb Laravel 11 Reverb Laravel 11 Laravel 11 Tutorial Laravel Reverb Tutorial Aravel 11 Laravel Reverb Laravel Reverb Comments Laravel Echo Comment Sytem Realtime Communication