Beboost

Customization

Hook into the status change lifecycle

Customization

The Status Management plugin lets you react to status changes through a dispatched event and through per-model lifecycle handlers.

AfterStatusChangeEvent

AfterStatusChangeEvent is dispatched after a record's status value is updated. It carries the affected model:

namespace Beboost\StatusManagement\Events;

class AfterStatusChangeEvent
{
    public function __construct(public Model $model) {}
}

Listen for it like any Laravel event:

use Beboost\StatusManagement\Events\AfterStatusChangeEvent;
use Illuminate\Support\Facades\Event;

Event::listen(AfterStatusChangeEvent::class, function (AfterStatusChangeEvent $event) {
    $model = $event->model;          // the record whose status changed
    $status = $model->status;        // current Status model (or null)

    if ($status?->code === 'COMPLETED') {
        // send notifications, update related records, etc.
    }
});

The current and previous status are not passed on the event payload. Read the current status from $event->model->status, and use the activity log if you need the previous status (it is recorded with every transition).

Listener class

namespace App\Listeners;

use Beboost\StatusManagement\Events\AfterStatusChangeEvent;

class SendOrderStatusNotification
{
    public function handle(AfterStatusChangeEvent $event): void
    {
        $order = $event->model;

        $order->user->notify(
            new OrderStatusChanged($order, $order->status)
        );
    }
}

Register it in your EventServiceProvider:

protected $listen = [
    AfterStatusChangeEvent::class => [
        SendOrderStatusNotification::class,
    ],
];

Lifecycle Handlers (before / after hooks)

To run logic before a status value is created, updated or deleted — and to be able to block the change — register a handler for a specific model. Handlers implement one or more of these contracts:

ContractMethods
EntityStatusCreateHandlerbeforeCreate(StatusValue $value): bool / afterCreate(StatusValue $value): void
EntityStatusUpdateHandlerbeforeUpdate(StatusValue $value): bool / afterUpdate(StatusValue $value): void
EntityStatusDeleteHandlerbeforeDelete(StatusValue $value): bool / afterDelete(StatusValue $value): void

A before* method returning false (or throwing StatusInterruptProcessException) cancels the operation and shows a danger notification to the user.

namespace App\Status;

use Beboost\StatusManagement\Models\StatusValue;
use Beboost\StatusManagement\Services\Contracts\EntityStatusUpdateHandler;

class OrderStatusHandler implements EntityStatusUpdateHandler
{
    public function beforeUpdate(StatusValue $value): bool
    {
        // Block shipping when the order has pending payments
        $order = $value->entity;

        return ! ($value->status->code === 'SHIPPED' && $order->hasPendingPayments());
    }

    public function afterUpdate(StatusValue $value): void
    {
        // side effects after a successful status update
    }
}

Register the handler for a model — typically in a service provider's boot():

use App\Models\Order;
use App\Status\OrderStatusHandler;
use Beboost\StatusManagement\Facades\StatusManagement;
use Beboost\StatusManagement\Services\Contracts\EntityStatusUpdateHandler;

StatusManagement::register(Order::class, [
    EntityStatusUpdateHandler::class => OrderStatusHandler::class,
]);

Interrupt a status change

Throw StatusInterruptProcessException from a handler to stop the change with a message shown to the user:

use Beboost\StatusManagement\Exceptions\StatusInterruptProcessException;

public function beforeUpdate(StatusValue $value): bool
{
    if ($value->status->code === 'SHIPPED' && ! $value->entity->hasAddress()) {
        throw new StatusInterruptProcessException('Cannot ship an order without an address.');
    }

    return true;
}

Status Customization

Statuses can be customized through the database fields documented in Architecture and the configuration file. Key customization points:

  • Visual appearancecolor and icon fields on the statuses table control how statuses render in badges, select fields, and charts
  • Behavioral flagsis_default, initial, is_final, and require_comment control how statuses behave during transitions
  • Global settingsconfig('status-management.global_settings') controls icons, colors, badges, and sorting across all components. See Configuration
  • Lifecycle handlers — use the contracts above to inject custom logic before and after status changes
  • Custom transition rules — register your own rules via TransitionCheckerManager::register(). See Architecture

Next Steps

How is this guide?

On this page