event and listeners

Laravel Events and Listeners

user

Sonu Singh

14 Apr 2024

12 min read

Laravel PHP

Introduction

Laravel's event system implements a simple observer pattern, enabling you to subscribe and respond to different events within your application. Events reside in the app/Events directory, while their corresponding listeners are located in app/Listeners. These directories are automatically generated as you create events and listeners using Artisan commands.

Events provide a clean solution for decoupling different parts of your application, allowing multiple listeners to independently respond to a single event. For instance, you can use events to trigger actions like sending Slack notifications when an order is shipped, keeping your codebase organized and maintainable.

what are events

Events are moments or occurrences that happen during the execution of your code. For instance, when a new user registers on a website, that's an event. When an item is added to a shopping cart, that's another event.

What are listeners

Listeners, on the other hand, are like attentive ears waiting for specific events to occur. When an event happens, listeners jump into action, carrying out predetermined tasks or actions. For example, when a user registers, a listener might send a welcome email or log the registration details, when an item added to your shopping cart, you might need to update your Inventory or logs the updates.

So, events announce what's happening, and listeners respond accordingly. They work together to keep your application organized, responsive, and flexible.

Generating Events and Listeners

To swiftly generate events and listeners, you can use Laravel's Artisan commands: php artisan make:event and php artisan make:listener.

php artisan make:event NewUserRegisteredEvent

php artisan make:listener SendNewUserRegisterNotification --event=NewUserRegisteredEvent

For convenience, you may also invoke the make:event and make:listener Artisan commands without additional arguments. When you do so, Laravel will automatically prompt you for the class name and, when creating a listener, the event it should listen to:

Registering Events and Listeners

Laravel seamlessly registers event listeners by default, scanning the Listeners directory in your application. If a listener class method starts with "handle" or "__invoke", Laravel automatically identifies and registers these methods as event listeners, matching the event type-hinted in the method's signature:

use App\Events\NewUserRegisteredEvent;

class SendNewUserRegisterNotification
{
    /**
     * Handle the given event.
     */
    public function handle(NewUserRegisteredEvent $event): void
    {
        //
    }
}

Utilize the event:list command to display a comprehensive list of all registered listeners within your Laravel application:

php artisan event:list

Manually Registering Events

Employing the Event facade, manually register events and their corresponding listeners within the boot method of your application's AppServiceProvider class:

use App\Orders\Events\NewUserRegisteredEvent;
use App\Orders\Listeners\SendNewUserRegisterNotification;
use Illuminate\Support\Facades\Event;

/**
 * Bootstrap any application services.
 */
public function boot(): void
{
    Event::listen(
        NewUserRegisteredEvent::class,
        SendNewUserRegisterNotification::class,
    );
}

Benefits and Usage Scenarios of Events(Why and When)

Using events in Laravel can greatly enhance the flexibility and maintainability of your application. Let's delve into a real-world scenario to understand why events are beneficial.

Imagine you're developing an e-commerce platform where users can purchase products. After a successful purchase, several actions need to be triggered:

  1. Sending order confirmation emails: You want to notify the user via email about their purchase.
  2. Updating inventory: You need to decrement the quantity of purchased items from your inventory.
  3. Logging purchase activities: You want to keep a record of the user's purchase activities for analytics purposes.
  4. Triggering notifications: Perhaps you want to send a notification to the admin or customer support team about the new order.

Now, let's see how events can streamline this process:

  1. OrderConfirmationEmail event: You can create an event called OrderConfirmationEmail that contains all the necessary data about the purchase, such as the user's email and the purchased items. This event can be listened to by a SendOrderConfirmationEmail listener, which will handle sending the email. First, we'll generate the event using Artisan command:
php artisan make:event OrderConfirmationEmail

This will create a new event file named OrderConfirmationEmail.php in the app/Events directory.

Next, we'll define the event class:

// app/Events/OrderConfirmationEmail.php

namespace App\Events;

use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;

class OrderConfirmationEmail
{
    use Dispatchable, SerializesModels;

    public $userEmail;
    public $purchasedItems;

    /**
     * Create a new event instance.
     *
     * @param  string  $userEmail
     * @param  array  $purchasedItems
     * @return void
     */
    public function __construct($userEmail, $purchasedItems)
    {
        $this->userEmail = $userEmail;
        $this->purchasedItems = $purchasedItems;
    }
}

Now, let's generate the listener using Artisan command:

php artisan make:listener SendOrderConfirmationEmail --event=OrderConfirmationEmail

Next, we'll define the listener class:

// app/Listeners/SendOrderConfirmationEmail.php

namespace App\Listeners;

use App\Events\OrderConfirmationEmail;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;

class SendOrderConfirmationEmail implements ShouldQueue
{
    use InteractsWithQueue;

    /**
     * Handle the event.
     *
     * @param  OrderConfirmationEmail  $event
     * @return void
     */
    public function handle(OrderConfirmationEmail $event)
    {
        $userEmail = $event->userEmail;
        $purchasedItems = $event->purchasedItems;

        // Code to send the order confirmation email
        Mail::to($userEmail)->send(new OrderConfirmationMail($purchasedItems));
    }
}

Dispatching OrderConfirmationEmail Event:

use App\Events\OrderConfirmationEmail;

// Example scenario: After a successful purchase, dispatch the OrderConfirmationEmail event
$order = [
    'user_email' => '[email protected]',
    'purchased_items' => ['item1', 'item2', 'item3'],
];

event(new OrderConfirmationEmail($order['user_email'], $order['purchased_items']));
  1. UpdateInventory event: Another event, UpdateInventory, can be dispatched after a successful purchase. This event can be listened to by an UpdateInventoryQuantity listener, which will decrement the quantity of purchased items from the inventory. First, generate the event using Artisan command:
php artisan make:event UpdateInventory

Next, define the event class:

// app/Events/UpdateInventory.php

namespace App\Events;

use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;

class UpdateInventory
{
    use Dispatchable, SerializesModels;

    public $purchasedItems;

    /**
     * Create a new event instance.
     *
     * @param  array  $purchasedItems
     * @return void
     */
    public function __construct($purchasedItems)
    {
        $this->purchasedItems = $purchasedItems;
    }
}

Now, let's generate the listener using Artisan command:

php artisan make:listener UpdateInventoryQuantity --event=UpdateInventory

Next, define the listener class:

// app/Listeners/UpdateInventoryQuantity.php

namespace App\Listeners;

use App\Events\UpdateInventory;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;

class UpdateInventoryQuantity implements ShouldQueue
{
    use InteractsWithQueue;

    /**
     * Handle the event.
     *
     * @param  UpdateInventory  $event
     * @return void
     */
    public function handle(UpdateInventory $event)
    {
        $purchasedItems = $event->purchasedItems;

        // Code to update inventory quantity based on purchased items
    }
}

Dispatching UpdateInventory Event:

use App\Events\UpdateInventory;

// Example scenario: After a successful purchase, dispatch the UpdateInventory event
$purchasedItems = ['item1', 'item2', 'item3'];

event(new UpdateInventory($purchasedItems));
  1. LogPurchaseActivity event: After a purchase, you can dispatch a LogPurchaseActivity event, which will be handled by a LogPurchaseActivity listener. This listener can log the purchase details to your analytics system or database. Event Class
// app/Events/LogPurchaseActivity.php

namespace App\Events;

use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;

class LogPurchaseActivity
{
    use Dispatchable, SerializesModels;

    public $purchaseDetails;

    /**
     * Create a new event instance.
     *
     * @param  array  $purchaseDetails
     * @return void
     */
    public function __construct($purchaseDetails)
    {
        $this->purchaseDetails = $purchaseDetails;
    }
}

and Listener Class

// app/Listeners/LogPurchaseActivityListener.php

namespace App\Listeners;

use App\Events\LogPurchaseActivity;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;

class LogPurchaseActivityListener implements ShouldQueue
{
    use InteractsWithQueue;

    /**
     * Handle the event.
     *
     * @param  LogPurchaseActivity  $event
     * @return void
     */
    public function handle(LogPurchaseActivity $event)
    {
        $purchaseDetails = $event->purchaseDetails;

        // Code to log purchase activity to analytics system or database
    }
}

Dispatching LogPurchaseActivity Event:

use App\Events\LogPurchaseActivity;

// Example scenario: After a successful purchase, dispatch the LogPurchaseActivity event
$purchaseDetails = [
    'user_id' => 1,
    'order_id' => 123,
    'total_amount' => 100,
    // Add more purchase details as needed
];

event(new LogPurchaseActivity($purchaseDetails));
  1. NewOrderNotification event: Lastly, you can dispatch a NewOrderNotification event to notify the admin or customer support team about the new order. This event can be listened to by a SendNewOrderNotification listener, which will trigger the appropriate notifications. Event Class
// app/Events/NewOrderNotification.php

namespace App\Events;

use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;

class NewOrderNotification
{
    use Dispatchable, SerializesModels;

    public $orderDetails;

    /**
     * Create a new event instance.
     *
     * @param  array  $orderDetails
     * @return void
     */
    public function __construct($orderDetails)
    {
        $this->orderDetails = $orderDetails;
    }
}

And Listener Class

// app/Listeners/SendNewOrderNotification.php

namespace App\Listeners;

use App\Events\NewOrderNotification;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;

class SendNewOrderNotification implements ShouldQueue
{
    use InteractsWithQueue;

    /**
     * Handle the event.
     *
     * @param  NewOrderNotification  $event
     * @return void
     */
    public function handle(NewOrderNotification $event)
    {
        $orderDetails = $event->orderDetails;

        // Code to send new order notification to admin or customer support team
    }
}

Dispatching NewOrderNotification Event:

use App\Events\NewOrderNotification;

// Example scenario: After a successful purchase, dispatch the NewOrderNotification event
$orderDetails = [
    'order_id' => 123,
    'total_amount' => 100,
    'customer_name' => 'John Doe',
    // Add more order details as needed
];

event(new NewOrderNotification($orderDetails));

Event within event

In Laravel, calling an event within another event is not directly supported. Events are intended to represent single occurrences or actions within your application, and nesting events can lead to complex and potentially unpredictable behavior.

However, you can achieve similar functionality by dispatching multiple events and having listeners respond to those events accordingly. Here's an example to illustrate this:

Let's say you have an event called UserRegistered that is dispatched when a new user registers on your website. After the user is registered, you want to perform additional actions, such as sending a welcome email and logging the registration.

You can achieve this by dispatching separate events for each action:

use App\Events\UserRegistered;
use App\Events\SendWelcomeEmail;
use App\Events\LogUserRegistration;

class UserController extends Controller
{
    public function register(Request $request)
    {
        // Register the user

        // Dispatch the UserRegistered event
        event(new UserRegistered($user));

        return response()->json(['message' => 'User registered successfully']);
    }
}

Then, you can have listeners for each of these events:

class SendWelcomeEmailListener
{
    public function handle(UserRegistered $event)
    {
        // Code to send welcome email to the registered user
    }
}

class LogUserRegistrationListener
{
    public function handle(UserRegistered $event)
    {
        // Code to log the user registration
    }
}

Handling Event Exceptions:

Sometimes, errors or exceptions may occur during event processing. Laravel provides mechanisms to handle these exceptions gracefully:

use App\Events\UserRegistered;
use App\Listeners\SendWelcomeEmail;

try {
    // Dispatch the UserRegistered event
    event(new UserRegistered($user));

    // The event was dispatched successfully
    // Perform additional actions if needed
} catch (\Exception $e) {
    // An exception occurred during event processing
    // Handle the exception gracefully
    \Log::error('Error sending welcome email: ' . $e->getMessage());
    // Display a user-friendly error message
    return redirect()->back()->with('error', 'Failed to send welcome email. Please try again later.');
} 

Conclusion

In conclusion, Laravel's event and listener system offers a powerful mechanism for simplifying application logic. By decoupling components, organizing code modularly, and providing flexibility and extensibility, events and listeners empower developers to build robust and scalable applications with ease.

So, the next time you're faced with a complex workflow or need to streamline your application's logic, consider harnessing the power of Laravel events and listeners to simplify the task at hand.

user

Author: Sonu Singh

With over 7 years of dedicated experience in web development, I've traversed through the dynamic landscape of digital technology, honing my skills and expertise across various frameworks and content management systems. My journey began with the exploration of frameworks like CodeIgniter, CakePHP, Yii, and eventually, I found my passion in Laravel - a framework that resonated deeply with my love for elegant, efficient code. Throughout my career, I've had the privilege to contribute to numerous projects, ranging from small-scale ventures to large, enterprise-level solutions. Each project has been a unique opportunity to push boundaries, solve intricate challenges, and deliver innovative solutions tailored to meet client needs. One of my proudest accomplishments includes the development of a SaaS-based project using Laravel and MySQL. This venture not only showcased my technical prowess but also demonstrated my ability to conceptualize, design, and execute scalable solutions that drive business growth. In addition to my proficiency in development, I've also delved into server deployment and query optimization, ensuring that every aspect of a project - from its codebase to its infrastructure - is optimized for peak performance and reliability.

Leave a reply

dot

Subscribe to Newsletter

Provide your email to get email notification when we launch new products or publish new articles

Newsletter

Subscribe to my newsletter to get updated posts

Don't worry, I don't spam