Reject Strategies
Stable 1.0: Reject routing semantics are frozen for the 1.x runtime API. Test your chosen strategy per workflow in integration tests.
Rejection in DBFlow is not always terminal. When an assignee rejects a pending approval task, the fourth argument to DBFlow::reject() selects how the instance should resume.
Runtime API
use DbflowLabs\Core\DBFlow;
use DbflowLabs\Core\Enums\RejectStrategy;
use DbflowLabs\Core\Models\WorkflowTask;
DBFlow::reject(
WorkflowTask $task,
mixed $actor = null,
?string $comment = null,
RejectStrategy $strategy = RejectStrategy::Starter,
?string $targetNodeKey = null,
);
- Pass a comment on reject when possible — it is stored on
dbflow_workflow_logs. - Pass
$targetNodeKeyonly withRejectStrategy::SpecificNode.
Filament My Tasks calls the same Core handlers. Default reject strategy comes from config('dbflow-filament.reject_strategy') (commonly end).
Enum reference
| Enum case | Stored value | When to use |
|---|---|---|
RejectStrategy::Starter |
starter |
Send the workflow back toward the initiator / restart path so the submitter can fix data and resubmit |
RejectStrategy::PreviousNode |
previous_node |
Return to the immediately preceding approval node for a light revision loop |
RejectStrategy::SpecificNode |
specific_node |
Jump back to a named approval node (pass $targetNodeKey) |
RejectStrategy::End |
end |
Terminate the instance as rejected — no further approvals |
Examples
Return to starter path
Use when the submitter must correct the record and start again:
DBFlow::reject(
$task,
$user,
'Missing invoice attachment.',
RejectStrategy::Starter,
);
Return to previous approval
Use for a single-step escalation return path:
DBFlow::reject(
$task,
$user,
'Escalation required.',
RejectStrategy::PreviousNode,
);
Return to a named node
Use when your graph requires a specific rework step — for example sending finance work back to support lead review:
DBFlow::reject(
$task,
$user,
'Send back to support lead.',
RejectStrategy::SpecificNode,
'support_lead_review', // targetNodeKey — must match a node key in the definition
);
Terminal rejection
Use when the business case is closed as rejected:
DBFlow::reject(
$task,
$user,
'Rejected permanently.',
RejectStrategy::End,
);
The refund demo's My Tasks flow commonly uses RejectStrategy::End so a rejected dispute maps to a lost outcome through hooks.
Pair strategy with hooks
Reject strategy controls graph position. WorkflowHooks::onRejected() controls host business state (status columns, notifications, downstream unlocks).
Keep routing decisions in the runtime call. Use hooks to mirror outcomes onto your model — not to secretly change which node comes next.
Choosing a strategy
| Scenario | Suggested strategy |
|---|---|
| Submitter must edit and resubmit the record | Starter |
| Prior approver should re-review only | PreviousNode |
| Rework must land on a specific approval step | SpecificNode + targetNodeKey |
| No further review; close as rejected | End |
Validate behaviour with integration tests — especially SpecificNode targets and graphs with parallel branches.
Audit trail
Every reject writes a task_rejected log row through WorkflowLogger. Query via workflowLogs() on the workflowable model or open the Filament instance timeline.
What's next
- Approve and Reject → — pending tasks, approve API, concurrency guards
- Workflow Hooks → — map rejected instances to host status
- Testing Workflows → — assert reject routing in PHPUnit
- Refund Approval → — demo using
RejectStrategy::End