Home
NexoPOS

Model Dispatchable Fields Event

The dispatchable fields event is a concept that ensures triggering events when a model property changes. Unlike regular Model events that are dispatched when a specific action is made (save, update, delete, etc), here we have a deep implementation that only triggers if a specific attribute of a model has changed.

The reason for this implementation was to avoid dispatching and listening to events when it's not necessary. For example, an order on NexoPOS can be updated in multiple ways. Every time the order is updated, we have default listeners that are ready to perform a specific action. Wouldn't it be better if, when the customer assigned is changed, we compute reports for the previous and recent customers? Wouldn't it be better if we could notify the driver only when the delivery status moves from "pending" to "ready-for-delivery"? That's the whole point of this feature.

Implementation

The implementation of that feature consists only of providing an array $dispatchableFieldsEvents on the model we want to dispatch the event. On that model, we'll provide property and related events like this:

<?php
namespace Modules\YourModule\Models;

use App\Models\NsModel;
use Modules\YourModule\Events\DeliveryChangedEvent;

class Order extends NsModel
{
    public $dispatchableFieldsEvents  = [
      'delivery_status' =>  DeliveryChangedEvent::class
    ];
}

Now we need to define the event as it not only receives the model as a parameter, but also the previous and new value of the property:

<?php
namespace Modules\YourModule\Events;

use App\Models\Order;

class DeliveryChangedEvent
{
    public function __construct( public Order $order, public mixed $previous, public mixed $new )
    {
        // ...
    }
}

From here, you can safely listen to this event from our event listener like this:

<?php 
namespace Modules\YourModule\Listeners;

use Modules\YourModule\Events\DeliveryChangedEvent;
use Moduels\YourModules\Services\DriverService;

class DeliveryChangedEventListener
{
    public function __construct( public DriverService $driverService ){
    {
        // ...
    }
      
    public function handle( DeliveryChangedEvent $event )
    {
          if ( $event->previous === 'pending' && $event->new === 'ready-for-delivery' ) {
              $this->driverService->notifyAssignedDriver( $event->order );
          }
    }
}