Building workflows
Two ways to author a workflow: in code, or interactively in the terminal. Both produce the same stored definition.
In code
Build the data structure and persist it through the repository:
use Qanna\WorkflowEngine\Engine\Nodes\Action\LogNode;
use Qanna\WorkflowEngine\Engine\Triggers\ManualTrigger;
use Qanna\WorkflowEngine\Models\Workflow;
use Qanna\WorkflowEngine\Storage\Contracts\WorkflowRepositoryContract;
$workflow = Workflow::fromArray([
'id' => 'send-welcome-email',
'name' => 'Send Welcome Email',
'trigger' => ['type' => ManualTrigger::type(), 'config' => []],
'nodes' => [
['id' => 'greet', 'type' => LogNode::type(), 'config' => [
'level' => 'info', 'message' => 'Welcome {{ trigger.email }}',
]],
],
'edges' => [
['from' => 'trigger', 'to' => 'greet', 'branch' => 'main'],
],
]);
app(WorkflowRepositoryContract::class)->create($workflow);
Edges
- The entry edge is
['from' => 'trigger', 'to' => '<first node id>', 'branch' => 'main']. - Every other edge connects two node ids.
branchnames which of the source node's outgoing branches the edge belongs to. For plain nodes that'smain; for branching nodes see Control flow.- To iterate a Loop, add an edge from the last body
node back to the loop node on
main.
A branching example
'nodes' => [
['id' => 'check', 'type' => ConditionNode::type(), 'config' => [
'field' => '{{ trigger.plan }}', 'operator' => '==', 'value' => 'pro',
]],
['id' => 'provision-pro', 'type' => /* ... */],
['id' => 'provision-free', 'type' => /* ... */],
],
'edges' => [
['from' => 'trigger', 'to' => 'check', 'branch' => 'main'],
['from' => 'check', 'to' => 'provision-pro', 'branch' => 'true'],
['from' => 'check', 'to' => 'provision-free', 'branch' => 'false'],
],
Interactively: php artisan workflow:build
php artisan workflow:build # new, or pick an existing one to edit
php artisan workflow:build send-welcome-email # jump straight to that id
The command walks you through:
- Naming the workflow (the id is derived from the name; editing an existing one bumps its version on save).
- Choosing and configuring a trigger. Each trigger's schema is prompted field by field.
- A main menu loop to shape the graph:
- Add a node — pick an attachment point and branch, pick a node type by category, give it an id, and fill in its config (plus connection / advanced settings if the node declares them). Adding after a node that already has a next step offers to insert between them.
- Attach to an open branch — fill in a branch (e.g. a Condition's
false) that has nothing wired to it yet. - Reconfigure / Remove / Undo last add / Reconnect a disconnected node.
- Reconfigure the trigger.
- Finish and save — validates the graph (a trigger is required; the graph must be well-formed) and lets you save anyway if you choose. It reminds you to restart the app when the trigger needs boot-time wiring (webhook / schedule / model event).
Only nodes and triggers that opt into CLI support (cliSupported()) appear in
the builder. Almost all built-ins do; the Switch node is
the exception.
The builder renders a live tree of the workflow after every change, e.g.:
Workflow: Send Welcome Email (send-welcome-email) — 2 node(s)
Manual (trigger)
└─ greet (Log)
└─ check [true] (Condition)
Custom nodes
To make your own node types available to workflows (and the builder), see
Custom nodes and
workflow:make-node.