Defining flows
A flow is the template; an approval is one run of that template against a record. This page is the field reference for flows and steps.
Flows
ApprovalFlow fields:
| Field | Type | Notes |
|---|---|---|
name |
string | Human label, shown in the panel. |
model_type |
string | Fully-qualified model class the flow applies to, e.g. App\Models\PurchaseOrder. |
is_active |
bool | Only an active flow is picked up by submitForApproval(). Default true. |
One active flow per model type
submitForApproval() with no explicit flow calls ApprovalFlow::activeFor($model::class), which returns the first active flow for that model type:
public static function activeFor(string $modelType): ?ApprovalFlow
{
return static::query()
->where('model_type', $modelType)
->where('is_active', true)
->first();
}
Keep exactly one active flow per model type, or pass the flow explicitly:
$po->submitForApproval(flow: $specificFlow);
If no active flow is found, submitForApproval() throws ApprovalException::noActiveFlow(). If the flow has no steps, it throws ApprovalException::flowHasNoSteps().
Steps
ApprovalStep fields:
| Field | Type | Notes |
|---|---|---|
sort_order |
int | Steps run ascending. Start at 0. |
name |
string | Human label for the step. |
mode |
any | all |
How the step passes. See below. Default any. |
approver_type |
role | users |
How approvers are resolved. Default role. |
approver_role |
string|null | Role name when approver_type is role. |
approver_ids |
array|null | User IDs when approver_type is users. |
allow_delegation |
bool | Whether approvers may delegate this step. Default true. |
escalate_after_hours |
int|null | Per-step escalation window; falls back to the config default. |
Step modes
any— the step passes as soon as one assigned approver approves. Use for "any manager can sign".all— the step passes only when every resolved approver has approved (parallel sign-off). Use for "both finance officers must agree".
$flow->steps()->create([
'sort_order' => 0,
'name' => 'Any manager',
'approver_type' => 'role',
'approver_role' => 'manager',
'mode' => 'any',
]);
$flow->steps()->create([
'sort_order' => 1,
'name' => 'Both signatories',
'approver_type' => 'users',
'approver_ids' => [$cfo->id, $ceo->id],
'mode' => 'all',
]);
With mode
alland a role approver, "everyone" means every user currently holding that role. Adding a user to the role mid-run adds them to the required set. For a fixed set of signatories, useapprover_type = users.
Ordering and advancing
When a step passes, the plugin looks up the next step by sort_order (ApprovalStep::nextStep()). If there is none, the run is marked approved and ApprovalCompleted fires. Rejection at any step ends the run immediately with status rejected.
Editing flows at runtime
Because flows and steps are ordinary rows, you can manage them from the bundled Approval Flows resource (or your own UI) with no deploy. Changes affect new runs; approvals already in progress keep the step rows they were created against.
Next: Approver resolution.