Batch Grouping

When a single user action triggers multiple model changes, you want to see them as one logical operation. AuditChain::batch() groups all audit logs created within its callback under a shared UUID.

Usage

use GrayMatter\AuditChain\Facades\AuditChain;

AuditChain::batch(function () {
    $order->audit('shipped');
    $order->update(['status' => 'shipped']);
    $inventory->update(['quantity' => $inventory->quantity - 1]);
});
// All 3 audit logs share the same batch_uuid

Every audit log created inside the callback — whether from automatic CRUD events or custom events — receives the same batch_uuid.

Custom Batch ID

By default, batch() generates a UUID. You can provide your own:

AuditChain::batch(function () {
    $order->update(['status' => 'processing']);
}, batchId: 'order-42-fulfillment');

Nesting

Batches can be nested. The inner batch gets its own UUID, and the outer batch resumes when the inner one completes:

AuditChain::batch(function () {
    $order->update(['status' => 'shipped']); // outer batch UUID

    AuditChain::batch(function () {
        $shipment->audit('created');         // inner batch UUID
        $tracking->audit('assigned');        // inner batch UUID
    });

    $order->audit('notification_sent');      // outer batch UUID
});

Return Values

batch() returns whatever the callback returns:

$result = AuditChain::batch(function () {
    return Order::create(['status' => 'pending']);
});

// $result is the new Order instance

Querying by Batch

Find all audit logs from a specific operation:

use GrayMatter\AuditChain\Models\AuditLog;

AuditLog::where('batch_uuid', $batchUuid)->get();

Hash Chain Note

The batch_uuid is intentionally excluded from hash computation. It is operational metadata — changing how you group operations does not affect chain integrity.