Workflow Hooks
Alpha notice: Hook invocation order is tied to runtime transactions today. Do not rely on hooks for graph routing — use transitions and
DBFlow::reject()strategies instead.
Workflow hooks let your Laravel application react when an instance starts, completes approval, is rejected, or is cancelled. They are host callbacks — not Laravel Event classes and not WorkflowLogEvent rows.
Registration
Register one hook class per workflow key during application boot:
use DbflowLabs\Core\DBFlow;
use DbflowLabs\Core\Services\WorkflowHooksRegistry;
DBFlow::registerWorkflowHooks(
app(WorkflowHooksRegistry::class),
'procurement_request_approval',
ProcurementRequestWorkflowHooks::class,
);
Refund demo equivalent:
DBFlow::registerWorkflowHooks(
app(WorkflowHooksRegistry::class),
'refund_dispute_approval',
RefundDisputeWorkflowHooks::class,
);
WorkflowHooks contract
use DbflowLabs\Core\Contracts\WorkflowHooks;
use DbflowLabs\Core\Models\WorkflowInstance;
interface WorkflowHooks
{
public function onStarted(WorkflowInstance $instance): void;
public function onApproved(WorkflowInstance $instance): void;
public function onRejected(WorkflowInstance $instance): void;
public function onCancelled(WorkflowInstance $instance): void;
}
Implement all four methods even when some are no-ops.
Hook reference
| Hook | Fires when | Typical host use |
|---|---|---|
onStarted |
Instance enters running after DBFlow::start() |
Set pending_review, stamp submitted_at |
onApproved |
Instance reaches an approved terminal outcome | Set approved, unlock downstream actions |
onRejected |
Instance is rejected per runtime strategy | Set rejected, notify submitter |
onCancelled |
DBFlow::cancel() succeeds |
Roll back to draft or mark withdrawn — gate cancel() in the host; Core does not restrict to submitter |
Access the business record through $instance->workflowable.
Example: procurement status mapping
From dbflow-demo — ProcurementRequestWorkflowHooks:
final class ProcurementRequestWorkflowHooks implements WorkflowHooks
{
public function onStarted(WorkflowInstance $instance): void
{
$instance->workflowable?->update([
'status' => ProcurementRequestStatus::PendingReview,
'submitted_at' => now(),
]);
}
public function onApproved(WorkflowInstance $instance): void
{
$instance->workflowable?->update([
'status' => ProcurementRequestStatus::Approved,
'reviewed_at' => now(),
]);
}
public function onRejected(WorkflowInstance $instance): void
{
$instance->workflowable?->update([
'status' => ProcurementRequestStatus::Rejected,
'reviewed_at' => now(),
]);
}
public function onCancelled(WorkflowInstance $instance): void
{
// Demo rolls back to draft unless archived — adjust for production policy
$instance->workflowable?->update([
'status' => ProcurementRequestStatus::Draft,
]);
}
}
See Purchase Request Approval for the full status table.
Example: refund outcome mapping
Refund hooks map workflow completion to won / lost business outcomes while investigation status remains host-managed. Implementation: app/DBFlow/RefundDispute/RefundDisputeWorkflowHooks.php in dbflow-demo.
Appropriate uses
- Mirror workflow outcomes onto Eloquent columns
- Write domain-specific audit notes outside
dbflow_workflow_logs - Enqueue notifications or jobs after state changes
- Unlock Filament actions gated on host status (for example archive after approval)
Avoid in hooks
- Graph routing — use
transitions[].conditionandRejectStrategyinstead - Starting another workflow synchronously — risk nested transactions and duplicate
active_keyconflicts - Heavy external API calls — prefer queued jobs triggered from the hook
- Silent exception swallowing — failed host updates can desync UI and instance status
Hooks vs audit logs
WorkflowLogger writes immutable rows to dbflow_workflow_logs with WorkflowLogEvent types (workflow_started, task_approved, task_rejected, …). Hooks are for mutable host state and side effects.
Do not confuse WorkflowLogEvent with Laravel's event dispatcher.
Testing hooks
Assert host columns in integration tests after driving DBFlow::start(), approve(), reject(), and cancel(). dbflow-demo procurement and refund suites cover hook side effects — see Testing Workflows.
What's next
- Purchase Request Approval → — full hook status table
- Eloquent Models → — model-first integration
- Reject Strategies → — routing vs hook responsibilities
- Architecture → — runtime lifecycle overview