In this guide, I’ll walk you through setting up real-time event broadcasting in Laravel 11. Event broadcasting lets us update data in real-time on connected clients, making Laravel ideal for interactive applications.
We’ll use Laravel Reverb to broadcast events and listen to them on the frontend. This example will include setting up events, configuring broadcasting, and creating a frontend listener.
Real-Time Event Broadcasting in Laravel 11
In this step, we'll install laravel 11 application using the following command.
composer create-project laravel/laravel example-app
Now, we'll create Laravel Auth using the following command.
composer require laravel/ui
Generate Auth:
php artisan ui bootstrap --auth
npm install
npm run build
Next, we'll create a migration using the following command.
php artisan make:migration add_is_admin_column_table
php artisan make:migration create_posts_table
Migration:
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('users', function (Blueprint $table) {
$table->tinyInteger('is_admin')->default(0);
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
//
}
};
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->foreignId('user_id')->constrained()->onDelete('cascade');
$table->string('title');
$table->text('body');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('posts');
}
};
Then, we'll migrate the table into the database using the following command.
php artisan migrate
Next, we'll create a Model and add the following code.
php artisan make:model Post
app/Models/Post.php
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
use HasFactory;
protected $fillable = ['title', 'body', 'user_id'];
/**
* Write code on Method
*
* @return response()
*/
public function user()
{
return $this->belongsTo(User::class);
}
}
app/Models/User.php
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
class User extends Authenticatable
{
use HasFactory, Notifiable;
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'name',
'email',
'password',
'is_admin'
];
/**
* The attributes that should be hidden for serialization.
*
* @var array
*/
protected $hidden = [
'password',
'remember_token',
];
/**
* Get the attributes that should be cast.
*
* @return array
*/
protected function casts(): array
{
return [
'email_verified_at' => 'datetime',
'password' => 'hashed',
];
}
}
Now, we'll enable broadcasting using the following command.
php artisan install:broadcasting
laravel will ask to install Reverb and you need to select "Yes". then it will automatically install it.
composer require laravel/reverb
php artisan reverb:install
Now, we will install the laravel echo server.
npm install --save-dev laravel-echo
resources/js/echo.js
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'],
});
Then, set the BROADCAST_CONNECTION environment variable to Reverb in your application's .env file, also we will add Reverb env variables.
.env
BROADCAST_CONNECTION=reverb
REVERB_APP_ID=256980
REVERB_APP_KEY=f4l2tmwqf6eg0f6jz0mw
REVERB_APP_SECRET=zioqeto9xrytlnlg7sj6
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}"
Then, build the JS using the following command.
npm run build
Next, we'll create an Event using the following command.
php artisan make:event PostCreate
app/Events/PostCreate.php
<?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\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Contracts\Broadcasting\ShouldBroadcastNow;
class PostCreate implements ShouldBroadcastNow
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $post;
/**
* Create a new event instance.
*/
public function __construct($post)
{
$this->post = $post;
}
/**
* Write code on Method
*
* @return response()
*/
public function broadcastOn()
{
return new Channel('posts');
}
/**
* Write code on Method
*
* @return response()
*/
public function broadcastAs()
{
return 'create';
}
/**
* Get the data to broadcast.
*
* @return array
*/
public function broadcastWith(): array
{
return [
'message' => "[{$this->post->created_at}] New Post Received with title '{$this->post->title}'."
];
}
}
Then, add the following routes into the web.php file.
routes/web.php
<?php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\PostController;
Route::get('/', function () {
return view('welcome');
});
Auth::routes();
Route::get('/home', [App\Http\Controllers\HomeController::class, 'index'])->name('home');
Route::get('/posts', [PostController::class, 'index'])->name('posts.index');
Route::post('/posts', [PostController::class, 'store'])->name('posts.store');
Now, we'll create a controller and add the following code to that file.
app/Http/Controllers/PostController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\Post;
use App\Events\PostCreate;
class PostController extends Controller
{
/**
* Write code on Method
*
* @return response()
*/
public function index(Request $request)
{
$posts = Post::get();
return view('posts', compact('posts'));
}
/**
* Write code on Method
*
* @return response()
*/
public function store(Request $request)
{
$request->validate([
'title' => 'required',
'body' => 'required'
]);
$post = Post::create([
'user_id' => auth()->id(),
'title' => $request->title,
'body' => $request->body
]);
event(new PostCreate($post));
return back()->with('success','Post created successfully.');
}
}
In this step, we will update the app.blade.php file and create the posts.blade.php file.
resources/views/layouts/app.blade.php
<!doctype html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- CSRF Token -->
<meta name="csrf-token" content="{{ csrf_token() }}">
<title>{{ config('app.name', 'Laravel') }}</title>
<!-- Fonts -->
<link rel="dns-prefetch" href="//fonts.bunny.net">
<link href="https://fonts.bunny.net/css?family=Nunito" rel="stylesheet">
<!-- Scripts -->
@vite(['resources/sass/app.scss', 'resources/js/app.js'])
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css" />
@yield('script')
</head>
<body>
<div id="app">
<nav class="navbar navbar-expand-md navbar-light bg-white shadow-sm">
<div class="container">
<a class="navbar-brand" href="{{ url('/') }}">
Real-Time Event Broadcasting in Laravel 11 using Reverb
</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="{{ __('Toggle navigation') }}">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<!-- Left Side Of Navbar -->
<ul class="navbar-nav me-auto">
</ul>
<!-- Right Side Of Navbar -->
<ul class="navbar-nav ms-auto">
<!-- Authentication Links -->
@guest
@if (Route::has('login'))
<li class="nav-item">
<a class="nav-link" href="{{ route('login') }}">{{ __('Login') }}</a>
</li>
@endif
@if (Route::has('register'))
<li class="nav-item">
<a class="nav-link" href="{{ route('register') }}">{{ __('Register') }}</a>
</li>
@endif
@else
<li class="nav-item">
<a class="nav-link" href="{{ route('posts.index') }}">{{ __('Posts') }}</a>
</li>
<li class="nav-item dropdown">
<a id="navbarDropdown" class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false" v-pre>
{{ Auth::user()->name }}
</a>
<div class="dropdown-menu dropdown-menu-end" aria-labelledby="navbarDropdown">
<a class="dropdown-item" href="{{ route('logout') }}"
onclick="event.preventDefault();
document.getElementById('logout-form').submit();">
{{ __('Logout') }}
</a>
<form id="logout-form" action="{{ route('logout') }}" method="POST" class="d-none">
@csrf
</form>
</div>
</li>
@endguest
</ul>
</div>
</div>
</nav>
<main class="py-4">
@yield('content')
</main>
</div>
</body>
</html>
resources/views/posts.blade.php
@extends('layouts.app')
@section('content')
<div class="container">
<div class="row justify-content-center">
<div class="col-md-12">
<div class="card">
<div class="card-header"><i class="fa fa-list"></i> {{ __('Posts List') }}</div>
<div class="card-body">
@session('success')
<div class="alert alert-success" role="alert">
{{ $value }}
</div>
@endsession
<div id="notification">
</div>
@if(!auth()->user()->is_admin)
<p><strong>Create New Post</strong></p>
<form method="post" action="{{ route('posts.store') }}" enctype="multipart/form-data">
@csrf
<div class="form-group">
<label>Title:</label>
<input type="text" name="title" class="form-control" />
@error('title')
<div class="text-danger">{{ $message }}</div>
@enderror
</div>
<div class="form-group">
<label>Body:</label>
<textarea class="form-control" name="body"></textarea>
@error('body')
<div class="text-danger">{{ $message }}</div>
@enderror
</div>
<div class="form-group mt-2">
<button type="submit" class="btn btn-success btn-block"><i class="fa fa-save"></i> Submit</button>
</div>
</form>
@endif
<p class="mt-4"><strong>Post List:</strong></p>
<table class="table table-bordered data-table">
<thead>
<tr>
<th width="70px">ID</th>
<th>Title</th>
<th>Body</th>
</tr>
</thead>
<tbody>
@forelse($posts as $post)
<tr>
<td>{{ $post->id }}</td>
<td>{{ $post->title }}</td>
<td>{{ $post->body }}</td>
</tr>
@empty
<tr>
<td colspan="5">There are no posts.</td>
</tr>
@endforelse
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
@endsection
@section('script')
@if(auth()->user()->is_admin)
<script type="module">
window.Echo.channel('posts')
.listen('.create', (data) => {
console.log('Order status updated: ', data);
var d1 = document.getElementById('notification');
d1.insertAdjacentHTML('beforeend', '<div class="alert alert-success alert-dismissible fade show"><span><i class="fa fa-circle-check"></i> '+data.message+'</span></div>');
});
</script>
@endif
@endsection
Next, we'll create a seeder using the following command.
php artisan make:seeder CreateAdminUser
database/seeders/CreateAdminUser.php
<?php
namespace Database\Seeders;
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
use App\Models\User;
class CreateAdminUser extends Seeder
{
/**
* Run the database seeds.
*/
public function run(): void
{
User::create([
'name' => 'Admin',
'email' => '[email protected]',
'password' => bcrypt('123456'),
'is_admin' => 1
]);
}
}
Now, run the seeder using the following command:
php artisan db:seed --class=CreateAdminUser
Now, run the laravel 11 application using the following command.
php artisan serve
Also, start the reverb server using the following command.
php artisan reverb:start
You might also like:
In this example, we will see how to convert an image into a base64 string using jquery. Base64 encoding schemes are...
Jan-03-2022
In this tutorial we will learn about laravel 8 inner join query example. Also see how to join two tables in laravel 8. I...
Nov-24-2021
In this example we will see laravel 8 one to many relationship example. Also you can use one to many relationship in lar...
Nov-03-2021
In this article, we will see how to create a dynamic line chart in laravel 9. A dynamic line chart or line plot or...
Mar-22-2022