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 $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