Laravel 12 Events Explained: Real-World Examples & Best Practices
Laravel's event system is a powerful tool that helps you build decoupled, maintainable applications. In this deep dive, we'll explore Laravel 12's event handling capabilities through practical examples you can apply directly to your projects.
Why Use Events? The Power of Loose Coupling
Imagine building an e-commerce platform. When an order is placed, you need to:
- Update inventory
- Send confirmation emails
- Generate an invoice
- Notify the logistics team
Without events, your order processing code would quickly become a tangled mess. Events let you handle these actions cleanly:
OrderPlaced::dispatch($order);
Getting Started: Creating Events and Listeners
Example 1: User Registration Flow
Generate the event:
php artisan make:event UserRegistered
Create a listener:
php artisan make:listener SendWelcomeEmail --event=UserRegistered
Event Class:
namespace App\Events;
use App\Models\User;
use Illuminate\Foundation\Events\Dispatchable;
class UserRegistered
{
use Dispatchable;
public function __construct(public User $user) {}
}
Listener Class:
namespace App\Listeners;
use App\Events\UserRegistered;
use App\Mail\WelcomeEmail;
use Illuminate\Support\Facades\Mail;
class SendWelcomeEmail
{
public function handle(UserRegistered $event)
{
Mail::to($event->user->email)->send(new WelcomeEmail($event->user));
}
}
Advanced Registration Techniques
Automatic Discovery vs Manual Registration
Laravel 12 automatically discovers listeners in app/Listeners, but you might need manual registration for:
- Third-party package listeners
- Conditional listener registration
// In AppServiceProvider
public function boot()
{
Event::listen(
UserRegistered::class,
[SendWelcomeEmail::class, 'handle']
);
// Conditional listener registration
if (config('app.send_welcome_emails')) {
Event::listen(/* ... */);
}
}
Queued Listeners: Power Up Performance
Example: Video Processing
namespace App\Listeners;
use App\Events\VideoUploaded;
use Illuminate\Contracts\Queue\ShouldQueue;
class ProcessVideo implements ShouldQueue
{
public $queue = 'videos';
public $delay = 60; // Wait 1 minute before processing
public function handle(VideoUploaded $event)
{
// Intensive video processing logic
$event->video->process();
}
public function failed(VideoUploaded $event, Throwable $exception)
{
// Notify admin of failed processing
Notification::sendAdmin("Video processing failed: " . $exception->getMessage());
}
}
Database Transactions and Event Dispatching
Ensure events only fire after successful transactions:
class OrderController extends Controller
{
public function store()
{
DB::transaction(function () {
$order = Order::create(/* ... */);
// This event will only dispatch if the transaction commits
OrderCreated::dispatchAfterCommit($order);
});
}
}
Event Subscribers: Group Related Logic
User Activity Tracker:
namespace App\Subscribers;
class UserActivitySubscriber
{
public function handleLogin($event) {/* ... */}
public function handleLogout($event) {/* ... */}
public function handleProfileUpdate($event) {/* ... */}
public function subscribe()
{
return [
Login::class => 'handleLogin',
Logout::class => 'handleLogout',
ProfileUpdated::class => 'handleProfileUpdate',
];
}
}
Registration:
Event::subscribe(UserActivitySubscriber::class);
Testing Events Like a Pro
Feature Test Example:
public function test_order_confirmation_email_sent()
{
Event::fake();
$user = User::factory()->create();
$response = $this->post('/place-order', [
// Order details
]);
Event::assertDispatched(OrderPlaced::class, function ($event) use ($user) {
return $event->order->user_id === $user->id;
});
Event::assertNotDispatched(PaymentFailed::class);
}
Testing Queued Listeners:
public function test_video_processing_queued()
{
Bus::fake();
$video = Video::factory()->create();
VideoUploaded::dispatch($video);
Bus::assertDispatched(ProcessVideo::class);
}
Real-World Use Cases
- Audit Logging:
class LogUserActivity
{
public function handle($event)
{
ActivityLog::create([
'user_id' => $event->user->id,
'event' => get_class($event),
'data' => $event->getLogData()
]);
}
}
- Cache Busting:
class ClearProductCache
{
public function handle(ProductUpdated $event)
{
Cache::forget("product_{$event->product->id}");
Cache::forget('featured_products');
}
}
- Cross-Service Communication:
class SyncWithCRM implements ShouldQueue
{
public function handle(CustomerUpdated $event)
{
Http::post('crm-api.com/customers', [
'id' => $event->customer->crm_id,
'data' => $event->customer->toArray()
]);
}
}
Best Practices and Pro Tips
Naming Conventions:
- Events: Past tense (UserRegistered, OrderShipped)
- Listeners: Action-oriented (SendNotification, UpdateInventory)
When to Use Events:
- Multiple unrelated actions needed
- Third-party integrations
- Optional application features
- Background processing
Performance Considerations:
- Use queued listeners for slow operations
- Limit synchronous listeners
- Monitor listener execution times
Debugging:
- Use
event:listArtisan command - Log event dispatching:
Event::listen('*', function ($eventName, $payload) { Log::debug("Event fired: $eventName", $payload); });
- Use
Conclusion
Laravel's event system is your gateway to building scalable, maintainable applications. By implementing events and listeners effectively, you can:
- Reduce code complexity
- Improve application performance
- Create more testable code
- Easily add new features
- Integrate with external services seamlessly
Remember: While powerful, events shouldn't replace all direct method calls. Use them judiciously where they provide clear architectural benefits.
Ready to supercharge your Laravel applications? Start by identifying one complex process in your current project that could benefit from event-driven architecture, and refactor it using these techniques!
Projects related to this guide
Use the concepts from this article in practical source-code projects.
Flask Authentication System (Free Version) - Kritim Yantra
🛠 Features✔ Google & GitHub Authentication✔ User Registration & Login✔ Profile/Dashboard Access✔ Secure...
Python Flask Blog Project with Admin Panel
Are you ready to launch a powerful, modern, and fully customizable blog? Look no further! Introducing the Flask-...
Laravel 12 + ReactJS Starter Kit: Add Multi-Language Support (Arabic, English, Spanish) with Blog CRUD
🚀 Installation & Setup Download & Extract Get the ZIP from kritimyantra.com and extract it. Includes pr...
Comments
No comments yet. Be the first to comment.
Sign in to join the discussion.