Laravel 11 Real-Time Notifications using Echo Socket.IO and Redis
In this tutorial, I will show you how to send real-time notifications using echo, socket io, redis server in the laravel 11 application. we will use a phpredis driver to send real-time notifications using the echo server with socket.io in the laravel 11 project. you can use free and open source with socket.io and redis server.
What is Socket.IO?
Socket.IO is a JavaScript library that enables real-time, bidirectional communication between web clients and servers. It simplifies the process of establishing and maintaining WebSocket connections, allowing for efficient data exchange. Developers use it to create dynamic, real-time applications like chat apps, live notifications, and online gaming. Socket.IO ensures compatibility across various browsers and environments, making real-time interactions more accessible and reliable.
What is Redis Server?
Redis Server is an open-source, in-memory data store used as a database, cache, and message broker. It supports various data structures like strings, lists, sets, and hashes. Redis is known for its speed, enabling quick data access and real-time applications. It's often used to enhance web performance by storing frequently accessed data in memory, reducing the need to access slower disk storage.
Here is what we will do in this example:
1. Create authentication (auth) scaffolding using Laravel UI.
2. Set up two types of users: a super admin and a normal user. We will identify them using an "is_admin" column in the users table.
3. Create a posts table with columns for the title and body.
4. Allow users to create posts with title and body.
5. Once a post is created, the admin will get a realtime notification using socket.io. we will create PostCreate Event for send realtime notification.
6. we will setup echo server with socket.io
7. we will install redis server in our system. then we will install predis/predis composer package to system.
8. setup server.js file to start 6001 port.
Here is a preview of the realtime notification list layout:
Step for How to Send Real-Time Notifications with Laravel 11 SocketIO Redis
- Step 1: Install Laravel 11
- Step 2: Create Auth using Scaffold
- Step 3: Create Migrations
- Step 4: Create and Update Models
- Step 5: Install Redis Server
- Step 6: Setup Echo Server with SocketIO
- Step 7: Create PostCreate Event
- Step 8: Create Routes
- Step 9: Create Controller
- Step 10: Create and Update Blade Files
- Step 11: Create Admin User
- Step 12: Setup Node JS for 6001 Port
- Run Laravel App
Step 1: Install Laravel 11
This step is not required; however, if you have not created the Laravel app, then you may go ahead and execute the below command:
composer create-project laravel/laravel example-app
Step 2: Create Auth using Scaffold
Now, in this step, we will create an auth scaffold command to generate login, register, and dashboard functionalities. So, run the following commands:
Laravel 11 UI Package:
composer require laravel/ui
Generate Auth:
php artisan ui bootstrap --auth
npm install
npm run build
Step 3: Create Migrations
Here, we will create posts and add is_admin column to users table. so, let's run the following command:
php artisan make:migration add_is_admin_column_table
php artisan make:migration create_posts_table
now, let's update the following migrations:
database/migrations/2024_06_18_140624_add_is_admin_column.php
<?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
{
//
}
};
database/migrations/2024_06_18_140906_create_posts_table.php
<?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');
}
};
now, Let's run the migration command:
php artisan migrate
Step 4: Create and Update Models
Here, we will create Post model using the following command. we also need to update User model here. we will write relationship and some model function for like and dislike.
php artisan make:model Post
now, update the model file with hasMany() relationship:
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',
];
}
}
Step 5: Install Redis Server
Here, we will install redis server to the system. so first you need to run the following command to install redis server to your system.
sudo apt-get update
sudo apt-get install redis-server
Now, also install php-redis to your system:
sudo apt-get install php-redis
Next, let's start the redis server to your system:
sudo systemctl start redis
Please check your redis server status using the following command:
sudo systemctl status redis
If, everything fine then you can proceed to the next step:
Step 6: Setup Echo Server with SocketIO
Now, we need to configure laravel broadcast and socket io as driver.
So, first by default laravel has not enabled broadcasting, so you need to run the following command to enable it.
php artisan install:broadcasting
Now, we will install predis/predis to use driver as redis, so let's run the below command:
composer require predis/predis
Now, we will install laravel echo server, so, let's run the below commands:
npm install --save laravel-echo socket.io-client
now, you will see some code on the echo.js file, where you can made a changes:
resources/js/echo.js
import Echo from 'laravel-echo';
import io from 'socket.io-client';
window.io = io;
window.Echo = new Echo({
broadcaster: 'socket.io',
host: window.location.hostname + ':6001'
});
Then, set the BROADCAST_CONNECTION, REDIS_CLIENT environment variable to redis in your application's .env file, also we will add redis env variables:
.env
BROADCAST_CONNECTION=redis
REDIS_CLIENT=phpredis
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
Now again build your JS:
npm run build
Now, you need to check configuration to database.php file:
config/database.php
<?php
use Illuminate\Support\Str;
return [
...
'redis' => [
'client' => env('REDIS_CLIENT', 'redis'),
'options' => [
'cluster' => env('REDIS_CLUSTER', 'redis'),
'prefix' => '',
],
'default' => [
'url' => env('REDIS_URL'),
'host' => env('REDIS_HOST', '127.0.0.1'),
'username' => env('REDIS_USERNAME'),
'password' => env('REDIS_PASSWORD'),
'port' => env('REDIS_PORT', '6379'),
'database' => env('REDIS_DB', '0'),
],
'cache' => [
'url' => env('REDIS_URL'),
'host' => env('REDIS_HOST', '127.0.0.1'),
'username' => env('REDIS_USERNAME'),
'password' => env('REDIS_PASSWORD'),
'port' => env('REDIS_PORT', '6379'),
'database' => env('REDIS_CACHE_DB', '1'),
],
],
];
Next, we need to add driver to the broadcasting.php file, as the below:
config/database.php
<?php
return [
'default' => env('BROADCAST_CONNECTION', 'null'),
'connections' => [
...
'log' => [
'driver' => 'log',
],
'redis' => [
'driver' => 'redis',
'connection' => 'default',
],
],
];
Step 7: Create PostCreate Event
In this step, we need to create "Event" by using the Laravel artisan command, so let's run the command below. We will create the PostCreate event class.
next, run the following command to create event class.
php artisan make:event PostCreate
Now you can see a new folder created as "Events" in the app folder. You need to make the following changes as shown in the class below.
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}'."
];
}
}
Step 8: Create Routes
In this step, we need to create some routes for realtime notification. So open your "routes/web.php" file and add the following route.
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');
Step 9: Create Controller
Here, we require the creation of a new controller, PostController, with an index method to send a notification route. So let's put the code below.
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)
{
$this->validate($request, [
'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.');
}
}
Step 10: Create and Update Blade Files
In this step, we will update app.blade.php file and create posts.blade file. so, let's update it.
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('/') }}">
Laravel Send Realtime Notification using SocketIO Redis Server
</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.connector.socket.on('connect', () => {
console.log('Successfully connected to Socket.IO server');
});
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
Step 11: Create Admin User
In this step, we need to run the command to create the seeder to create admin user.
Let's run the migration command:
php artisan make:seeder CreateAdminUser
noww, we need to update CreateAdminUser seeder.
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' => 'admin@gmail.com',
'password' => bcrypt('123456'),
'is_admin' => 1
]);
}
}
now, the run seeder using the following command:
php artisan db:seed --class=CreateAdminUser
Step 12: Setup Node JS for 6001 Port
Here, we will enable 6001 port for socket io channel. so, you need to install npm packages with the following command:
npm install --save ioredis
npm install --save socket.io
Now, create server.js file in root folder and update the following code:
server.js
import { createServer } from 'http';
import { Redis } from 'ioredis';
import { Server } from 'socket.io';
const server = createServer();
const io = new Server(server, {
cors: {
origin: "*",
}
});
const redis = new Redis();
redis.subscribe('posts', (err, count) => {
if (err) {
console.error('Failed to subscribe: %s', err.message);
} else {
console.log(`Subscribed successfully! This client is currently subscribed to ${count} channels.`);
}
});
redis.on('message', (channel, message) => {
const event = JSON.parse(message);
console.log(`Message received from channel ${event.event}: ${channel}`);
io.emit(event.event, channel, event.data);
});
io.on('connection', (socket) => {
console.log('a user connected');
socket.on('disconnect', () => {
console.log('user disconnected');
});
});
server.listen(6001, () => {
console.log('listening on *:6001');
});
Run Laravel & NodeJS App:
All the required steps have been done, now you have to type the given below command and hit enter to run the Laravel app:
php artisan serve
now, also run the node js for 6001 port:
node server.js
Now, Go to your web browser, type the given URL and view the app output:
http://localhost:8000/
Now, you have one admin user and you can register new normal user from registration form.
You can create post and Admin user will get the notification.
Output:
You can download the code from git:
I hope it can help you...
Hardik Savani
I'm a full-stack developer, entrepreneur and owner of ItSolutionstuff.com. I live in India and I love to write tutorials and tips that can help to other artisan. I am a big fan of PHP, Laravel, Angular, Vue, Node, Javascript, JQuery, Codeigniter and Bootstrap from the early stage. I believe in Hardworking and Consistency.
We are Recommending you
- Laravel 11 Product Add to Cart Functionality Example
- Laravel 11 MongoDB CRUD Application Tutorial
- Laravel 11 Real-Time Notifications using Pusher Example
- Laravel 11 Socialite Login with Gitlab Account Example
- Laravel 11 Notifications With database Driver Example
- Laravel 11 Send Email Via Notification Example
- Laravel 11 Like Dislike System Tutorial Example
- Laravel 11 JSON Web Token(JWT) API Authentication Tutorial
- Laravel 11 PayPal Payment Gateway Integration Example
- How to Install Sweetalert2 in Laravel 11 Vite?
- Laravel 11 Store Backup on Dropbox using Spatie Tutorial
- Laravel 11 Generate PDF and Send Email Tutorial
- Laravel 11 JQuery Load More Data on Scroll Example
- Laravel 11 Notification | Send Notification in Laravel 11