Lesson 39 of 50
Laravel Events and Listeners help you organize actions that should happen when something occurs in your application.
Example: Student Registration
When a student registers:
StudentRegistered event is dispatched.This separates registration logic from email logic, making the application easier to maintain.
Use Artisan to create an event:
php artisan make:event StudentRegistered
Laravel creates the event in:
app/Events/StudentRegistered.php
Example event class:
<?php
namespace App\Events;
use App\Models\Student;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
class StudentRegistered
{
use Dispatchable, SerializesModels;
public function __construct(
public Student $student
) {}
}
The event carries the student model so that listeners can access the newly registered student's information.
This example assumes your project has an
App\Models\Student model.
Create a listener using Artisan:
php artisan make:listener SendStudentWelcomeEmail --event=StudentRegistered
Laravel creates:
app/Listeners/SendStudentWelcomeEmail.php
Example listener:
<?php
namespace App\Listeners;
use App\Events\StudentRegistered;
use App\Mail\WelcomeMail;
use Illuminate\Support\Facades\Mail;
class SendStudentWelcomeEmail
{
public function handle(StudentRegistered $event): void
{
$student = $event->student;
Mail::to($student->email)->send(
new WelcomeMail($student->name)
);
}
}
The handle() method runs when the listener
receives the event.
This example assumes the Student model has
name and email fields and
that the WelcomeMail Mailable exists.
In modern Laravel applications, event discovery can
automatically detect listeners in the standard
app/Listeners directory when they follow
the supported conventions.
If you need to register the mapping manually, open
app/Providers/AppServiceProvider.php
and use an event listener registration method.
For example, in the boot() method:
use App\Events\StudentRegistered;
use App\Listeners\SendStudentWelcomeEmail;
use Illuminate\Support\Facades\Event;
public function boot(): void
{
Event::listen(
StudentRegistered::class,
SendStudentWelcomeEmail::class
);
}
Keep the existing imports and methods in your AppServiceProvider. Add the imports at the top of the file and place this code inside its class.
If your project already discovers this listener automatically, you do not need to register it a second time.
Check registered event mappings where supported:
php artisan event:list
Dispatch the event after successfully saving the student record.
Example controller method:
<?php
namespace App\Http\Controllers;
use App\Events\StudentRegistered;
use App\Models\Student;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
class StudentController extends Controller
{
public function store(Request $request)
{
$validated = $request->validate([
'name' => ['required', 'string', 'max:255'],
'email' => ['required', 'email', 'max:255', 'unique:students,email'],
'password' => ['required', 'string', 'min:8'],
]);
$student = Student::create([
'name' => $validated['name'],
'email' => $validated['email'],
'password' => Hash::make($validated['password']),
]);
StudentRegistered::dispatch($student);
return response()->json([
'message' => 'Student registered successfully.',
'student' => [
'id' => $student->id,
'name' => $student->name,
'email' => $student->email,
],
], 201);
}
}
This example assumes the Student model allows these fields to be mass-assigned and the database has the corresponding columns.
Never return the student's password in the response. Store passwords using secure hashing.
One event can trigger multiple listeners. For example, student registration can send an email and create an administrative notification.
Create another listener:
php artisan make:listener NotifyAdminOfRegistration --event=StudentRegistered
Example listener:
<?php
namespace App\Listeners;
use App\Events\StudentRegistered;
use Illuminate\Support\Facades\Log;
class NotifyAdminOfRegistration
{
public function handle(StudentRegistered $event): void
{
Log::info('A student registered.', [
'student_id' => $event->student->id,
'student_name' => $event->student->name,
]);
}
}
Register or discover this listener in the same way as the welcome-email listener.
When StudentRegistered is dispatched,
both registered listeners can handle the event.
Some listener actions, such as sending emails or calling external services, may take time. Laravel allows listeners to be queued.
Add the ShouldQueue interface to the
listener class:
use Illuminate\Contracts\Queue\ShouldQueue;
class SendStudentWelcomeEmail implements ShouldQueue
{
// Keep the existing handle() method here.
}
Keep the listener's constructor and
handle() method from the earlier example.
Configure the queue connection in .env:
QUEUE_CONNECTION=database
Create the required queue table if it does not already exist, then run the migrations and start a worker:
php artisan make:queue-table
php artisan migrate
php artisan queue:work
The migration command depends on your Laravel version and existing project setup. Do not create a duplicate jobs table.
With a queued listener, dispatching the event can return before the email is actually sent. A working queue worker is needed to process it.
StudentRegistered.Important:
If a listener must run only after a database transaction commits, configure it to handle events after commit using Laravel's supported event or queue configuration for your version. This helps prevent listeners from acting on records that were later rolled back.
Create a student registration event system.
StudentRegistered event.SendStudentWelcomeEmail listener.Bonus Task:
Create a FeePaymentCompleted event with
listeners for sending a receipt email and recording
an administrative log entry.
1. What does a Laravel event represent?
2. Which method commonly handles an event in a listener?
3. Which interface allows a listener to be queued?