Laravel 11.5 has just been released, and it added anonymous broadcasting
. What is it? Let's take a look.
This message is triggered by a private anonymous event, so let's see how it's done.
We want to start by re-creating our first example from the previous lesson—a global event that will inform all users about system maintenance. We will use the same event and channel, but this time, we will make it anonymous.
To create a channel for this, we will modify the routes/channels.php
file:
// ... Broadcast::channel('system-maintenance', function () { // Public Channel});
Then, we want to create a new command to trigger this event:
php artisan make:command SystemNotifyMaintenanceCommand
And modify the command file:
app/Console/Commands/SystemNotifyMaintenanceCommand.php
use Illuminate\Console\Command;use Illuminate\Support\Facades\Broadcast; class SystemNotifyMaintenanceCommand extends Command{ protected $signature = 'system:notify-maintenance'; protected $description = 'Command description'; public function handle(): void { $time = $this->ask('When should it happen?'); Broadcast::on('system-maintenance') ->as('App\\Events\\SystemMaintenanceEvent') ->with([ 'time' => $time ]) ->via('reverb') ->send(); }}
Next, we will add a Listener:
resources/views/layouts/app.blade.php
{{-- ... --}} window.Echo.channel('system-maintenance') .listen('SystemMaintenanceEvent', (event) => { let location = document.getElementsByTagName('main')[0]; let div = document.createElement('div'); div.style.width = '100%'; div.style.height = '32px'; div.style.textAlign = 'center'; div.style.lineHeight = '32px'; div.style.background = '#ffab44'; div.innerHTML = 'WARNING: The system will go down for maintenance at ' + event.time + '.'; location.insertBefore(div, location.firstChild); }); {{-- ... ---}}
Now, start the Reverb server:
php artisan reverb:start
And trigger the command:
That's it! The anonymous event is working! And we did not have to create an event class! All we have to do is "pretend" that we triggered the event by specifying the ->as()
with the event class name (including namespace!).
The same can be done with private events. Let's re-create another example using private events.
php artisan make:controller StartExportController
app/Http/Controllers/StartExportController.php
use App\Jobs\ExportPdfDataJob; class StartExportController extends Controller{ public function __invoke() { dispatch(new ExportPdfDataJob(auth()->id())); return redirect()->back(); }}
Then, we have to create a job:
php artisan make:job ExportPdfDataJob
app/Jobs/ExportPdfDataJob.php
use App\Events\ExportFinishedEvent;use Illuminate\Bus\Queueable;use Illuminate\Contracts\Queue\ShouldQueue;use Illuminate\Foundation\Bus\Dispatchable;use Illuminate\Queue\InteractsWithQueue;use Illuminate\Queue\SerializesModels; class ExportPdfDataJob implements ShouldQueue{ use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; public function __construct(public int $userId) { } public function handle(): void { sleep(5); Broadcast::private('App.Models.User.' . $this->userId) ->as('App\\Events\\ExportFinishedEvent') ->with([ 'user_id' => $this->userId, 'file_path' => 'file.pdf', ]) ->via('reverb') ->send(); }}
Note: In this example, we use private()
instead of on()
- this is the only difference between global and private events (besides the channel name).
Once this is done, we can listen for this event on our front end:
resources/views/layouts/app.blade.php
{{-- ... --}} window.Echo.private('App.Models.User.' + {{ auth()->id() }}) .listen('ExportFinishedEvent', (event) => { let location = document.getElementsByTagName('main')[0]; let div = document.createElement('div'); div.style.width = '100%'; div.style.height = '32px'; div.style.textAlign = 'center'; div.style.lineHeight = '32px'; div.style.background = '#44ff44'; div.innerHTML = 'SUCCESS: Your export is finished. You can download it <a href="' + event.file_path + '">here</a>.'; location.insertBefore(div, location.firstChild); }); {{-- ... ---}}
Now, if we trigger this event in our job, we should see the banner at the top of our dashboard:
This works just as in our previous example using actual Event classes.
The full repository with source is here on GitHub.