Creating Real Time Notifications in Laravel with Laravel Web Sockets
In this post we will be looking at how to build a realtime notification Laravel App with Laravel Websockets and Echo.
This could be used to send realtime notifications to a user about an order dispatched, new post, comments or many other reasons.
Code here is you need. Repo
Create an App
laravel new realtime-notifications-app && cd realtime-notifications-app
Run the App
php -S localhost:8000 -t public
Install the Packages
composer require beyondcode/laravel-websockets
composer require pusher/pusher-php-server
Edit .ENV file
Used by the package we don't use Pusher but needs configuring, don't forget to make these more secure in production.
BROADCAST_DRIVER=pusher
PUSHER_APP_ID=98765
PUSHER_APP_KEY=98765
PUSHER_APP_SECRET=98765
PUSHER_APP_CLUSTER=mt1
Publish the package migrations
php artisan vendor:publish --provider="BeyondCode\LaravelWebSockets\WebSocketsServiceProvider" --tag="migrations"
Database
Get your DB set up in .env
and then run the migrations
php artisan migrate
Publish the Package Config
php artisan vendor:publish --provider="BeyondCode\LaravelWebSockets\WebSocketsServiceProvider" --tag="config"
Launch the Stats Page
Go to http://localhost:8000/laravel-websockets and you should now see:
Click the connect button and you should get the following:
Create an Event
php artisan make:event RealTimePost
Edit the Event to match the following:
use Illuminate\Broadcasting\Channel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Queue\SerializesModels;
class RealTimePost implements ShouldBroadcast
{
use SerializesModels;
public string $message;
public function __construct(string $message)
{
$this->message = $message;
}
public function broadcastOn(): Channel
{
return new Channel('events');
}
}
Broadcasting
Change the broadcasting.php
config file to match:
'options' => [
'cluster' => env('PUSHER_APP_CLUSTER'),
'encrypted' => false,
'host' => '127.0.0.1',
'port' => 6001,
'scheme' => 'http'
],
Open tinker. php artisan tinker
and run the following:
event(new App\Events\RealTimePost('Hello World'));
In your web sockets dashboard you should now see this:
Front End
npm install
npm install --save-dev laravel-echo pusher-js
Go to resources/js/bootstrap.js
and add the following:
import Echo from 'laravel-echo';
window.Pusher = require('pusher-js');
window.Echo = new Echo({
broadcaster: 'pusher',
key: process.env.MIX_PUSHER_APP_KEY,
cluster: process.env.MIX_PUSHER_APP_CLUSTER,
forceTLS: false,
wsHost: window.location.hostname,
wsPort: 6001,
disabledStats: true,
enabledTransport: [‘ws’, ‘wss’]
})
For simplicity lets just edit our welcome.php blade. Add this to just before the <body>
tags and also import the app.js into your welcome page:
<script> Echo.channel('events') .listen('RealTimePost', (e) => console.log('RealTimePost: ' + e.message)); </script>
Finally run npm run dev
Go to http://localhost:8000/ and you will now see the following in your websockets dashboard:
Congrats you are now connected to the websocket.
Now in tinker. Run the event(new App\Events\RealTimePost('Hello World'));
and you will see it in your browser console.
Private Messaging
So the notifications above are broadcast to everyone. Lets make a private channel between the server and the logged in user.
In your RealTimePost Event. Change to the following:
use Illuminate\Broadcasting\PrivateChannel;
public function broadcastOn(): Channel {
return new PrivateChannel('events');
}
Restart Tinker and resend the Event.
Now in your welcome.blade. Change the Echo to:
Echo.private('events') .listen('RealTimePost', (e) => console.log('Private RealTimePost: ' + e.message));
When you refresh you will get an error in the console this is normal. In your app config file uncomment the app config file. Uncomment the line App\Providers\BroadcastServiceProvider::class
and then run php artisan config:cache.
At the top of your welcome.blade
file add the Laravel CSRF tags in the meta data:
Go to routes/channels.php
and paste the following:
Broadcast::channel('events', function ($user)
{
return true;
});
Now in Tinker run the following to create a new user:
User::create([
'name' => 'Test Person',
'email' => 'test@example.com',
'password' => bcrypt('password'),
]);
In your routes/web.php file change the welcome route to this:
Route::get('/', function () {
auth()->login(User::first());
return view('welcome');
});
Remember to add use App\Models\User;
to the top of the page.
Reload the browser and run the Tinker command and you should now receive the private notification in the console.
Notifications
Lets change the event to a notification.
php artisan make:notification RealTimeNotification
Open up the Notification and paste the following:
namespace App\Notifications;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Notifications\Messages\BroadcastMessage;
use Illuminate\Notifications\Notification;
class RealTimeNotification extends Notification implements ShouldBroadcast
{
public string $message;
public function __construct(string $message)
{
$this->message = $message;
}
public function via($notifiable): array
{
return ['broadcast'];
}
public function toBroadcast($notifiable): BroadcastMessage
{
return new BroadcastMessage([
'message' => "$this->message (User $notifiable->id)"
]);
}
}
Go back to Tinker and run the following:
$user = User::first();
Then:
$user->notify(new App\Notifications\RealTimeNotification('Hello World'));
In your websocket dashboard you should now see this:
Open the welcome.blade
and change the Echo
to look like this:
Echo.private('App.Models.User.1') .notification((notification) => { console.log(notification.message); });
Refresh your browser with the welcome page. And run your tinker notification again and you should see an output.
The validation for the user is in the channels.php
file using this line, this allows you to only show the message to the correct user:
Broadcast::channel('App.Models.User.{id}', function ($user, $id) {
return (int) $user->id === (int) $id;
});
Code here is you need. Repo
Categories: Posts