Events and Listeners

An event is a plain object recording a fact; a listener reacts to it in handle(). The dispatcher never learns who listens, so a new reaction is a new class, not an edit to the checkout. make:event OrderPlaced and make:listener SendOrderConfirmation --event=OrderPlaced create both. The event holds public Order $order and uses Dispatchable (for OrderPlaced::dispatch()); the listener logs through a LoggerInterface injected into its constructor.

The event implements ShouldDispatchAfterCommit, so it waits for the open transaction to commit and vanishes on a rollback; Checkout::place() dispatches it inside DB::transaction(). Eloquent meanwhile fires model events for every row (Inserting and Updating Records). Wildcard listeners show both:

Model events versus the domain event during one checkoutSQL
use App\Events\OrderPlaced;
use App\Services\Checkout;
$lv = fn () => ' (transaction level ' . DB::transactionLevel() . ')';
Event::listen('eloquent.created: *', fn (string $name) => print("model:  {$name}{$lv()}\n"));
Event::listen(fn (OrderPlaced $e) => print("domain: OrderPlaced #{$e->order->id}{$lv()}\n"));
$order = app(Checkout::class)->place('ann@example.com', ['BK-102' => 1, 'BK-104' => 2]);
echo "payment: {$order->payment_ref}\n";
Output
model:  eloquent.created: App\Models\Order (transaction level 1)
model:  eloquent.created: App\Models\OrderItem (transaction level 1)
model:  eloquent.created: App\Models\OrderItem (transaction level 1)
domain: OrderPlaced #1 (transaction level 0)
payment: fake_0001

The model events fired mid-transaction, so a created listener on Order would see no items; the domain event fired once, after the commit, and the listeners logged Stock reserved for order #1 and Confirmation to ann@example.com, total 142.50. Use model events for one row's concerns and domain events for business facts.