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 $targetNodeKey only with RejectStrategy::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

Something wrong? Open an issue on GitHub