Reject Strategies
Alpha notice: Reject routing semantics are stable in intent but may gain validation errors in future Core tags. Test your chosen strategy per workflow.
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