Conditionally Run Event Listeners – Laravel 11

Laravel has a method called shouldQueue for event listeners. You can use this method to should queue or not queue event listener. Make sure to implement shouldQueue interface on the event listener class to use shouldQueue() method. ShouldQueue() method should return true to queue and false to not queue.

  1. If return true event listener will be added to queue and execute the handle().
  2. If return false event listener will not be queued and handle() method is skipped.

Why use ShouldQueue() method in event listeners?

This method has many use cases. Below describe one use case it was used massively in Laravel projects.

Imagine you have a Laravel project to handle shipping goods. You want to run a certain event (ex: ItemShipped) only when the item count is more than 500. You can do that by adding a if statement like below.

if($item->count > 500)
{
   ItemShipped::dispatch($item);
}

What if you have to use this event on several controllers, services, etc. You have to modify all those places to have this condition. This is not a good practice to have a clean code. You can add this condition within the event listener class like below.

First make sure event listener class implements ShouldQueue interface. Next add shouldQueue() method. The handle() of Event listener only run if this method return true.

public function shouldQueue(ItemShipped $event){
        return $event->item->count >= 500;
    }

Example of using shouldQueue method

Create sample event and event listener

First create a sample event class.

php artisan make:event ItemShipped

Next create a event listener for above event class

php artisan make:listener NotifyShippingCompany

Add condition to event listener class

Lets modify event class to accept item object to construct our condition on the event listener class.

  1. Open ItemShipped.php event class
  2. Modify construct to accept item object.
<?php

namespace App\Events;

use Illuminate\Broadcasting\InteractsWithSockets;

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

class ItemShipped implements ShouldDispatchAfterCommit
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

    /**
     * Create a new event instance.
     */
    public function __construct(public object $item)
    {
        //
    }
}

Next modify event listener class

  1. Open NotifyShippingCompany.php
  2. Implement ShouldQueue interface class.
  3. Bind above created event class to the event listener class using handle() method by type hinting.
  4. Next add shouldQueue() method to event listener class and write your condition.
<?php

namespace App\Listeners;

use App\Events\ItemShipped;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Support\Facades\Log;

class NotifyShippingManager implements shouldQueue
{
    /**
     * Handle the event.
     */
    public function handle(ItemShipped $event): void
    {
        Log::info("Event Listener running..");
    }

    /**
     * Return true if item count is
     * greater than or equal to 500
     */
    public function shouldQueue(ItemShipped $event){
        Log::info($event->item->count." is greater than 500 ?");
        return $event->item->count >= 500;
    }
}

Run example

Lets dispatch created event in web.php.

<?php

use App\Events\ItemShipped;
use Illuminate\Support\Facades\Log;

Route::get('/', function () {
    Log::info('Dipatch item shipped event');
    $item = new stdClass();
    $item->count = 600;
    ItemShipped::dispatch($item);
});

Result

You can change the item count value in web.php file to check whether event listener is running or not. Below shows log file information based on above example.

[2024-11-29 11:20:12] local.INFO: Dipatch item shipped event  
[2024-11-29 11:20:12] local.INFO: 600 is greater than 500 ?  
[2024-11-29 11:20:14] local.INFO: Event Listener running..