DefaultWorkflowEngine
in package
implements
WorkflowEngineInterface
Default workflow execution engine.
Executes workflow graphs by traversing nodes, invoking actions/conditions from the registries, and managing instance lifecycle state.
Transaction strategy: durable public entry points (startWorkflow, resumeWorkflow, cancelWorkflow, fireIntermediateApprovalActions) wrap work in a single database transaction via ConnectionManager::get('default')->transactional(). Ephemeral startWorkflow executions skip the engine transaction so synchronous domain actions can own their own rollback behavior. Recursive calls (e.g., subworkflow nodes calling startWorkflow, or child completion calling resumeWorkflow) share the outer transaction instead of opening a nested one. The $isInTransaction flag tracks this.
Action nodes may invoke services (e.g., WarrantManager) that manage their own internal transactions. CakePHP's Connection handles nested transactional() calls via savepoints, so these are safe and will participate correctly in the outer transaction's commit/rollback.
When a workflow hits a WAITING state (approval gate, delay node, subworkflow), the transaction commits at that point. A later resumeWorkflow() call starts a fresh transaction.
Table of Contents
Interfaces
- WorkflowEngineInterface
- Contract for the workflow execution engine.
Constants
- MAX_EXECUTION_DEPTH : mixed = 200
- Maximum node execution depth to prevent infinite recursion.
Properties
- $container : ContainerInterface
- $ephemeral : bool
- Whether the current execution is ephemeral (in-memory, no persistence).
- $executionDepth : int
- Current execution depth counter.
- $isInTransaction : bool
- Whether we are currently inside a database transaction.
- $visitedNodes : array<string, bool>
- Tracks visited nodes during a single execution pass to detect cycles.
Methods
- __construct() : mixed
- Constructor.
- cancelHumanTask() : ServiceResult
- Cancel a pending human task without resuming the workflow.
- cancelWorkflow() : ServiceResult
- Cancel a running or waiting workflow instance.
- completeHumanTask() : ServiceResult
- Complete a human task and resume the workflow.
- dispatchTrigger() : array<string|int, ServiceResult>
- Dispatch a trigger event and start any matching workflows.
- fireIntermediateApprovalActions() : ServiceResult
- Fire actions connected to an approval node's on_each_approval port.
- getInstanceState() : array<string|int, mixed>|null
- Get the current state of a workflow instance.
- resumeWorkflow() : ServiceResult
- Resume a waiting workflow instance from a specific node output.
- startWorkflow() : ServiceResult
- Start a new workflow instance from a definition slug.
- advanceToOutputs() : void
- Advance execution to all targets of a node's output port.
- collectDescendants() : void
- Collect all descendant node IDs reachable from a starting node.
- createExecutionLog() : WorkflowExecutionLog|null
- Create an execution log entry. Returns null for ephemeral workflows.
- executeActionNode() : void
- Execute an action node via the WorkflowActionRegistry.
- executeApprovalNode() : void
- Execute an approval node — creates approval record, sets instance to WAITING.
- executeConditionNode() : void
- Execute a condition node and follow the matching output port.
- executeDelayNode() : void
- Execute a delay node — sets instance to WAITING for later resumption.
- executeEndNode() : void
- Execute an end node — completes this path, finishes instance if no active nodes remain.
- executeForEachNode() : void
- Execute a forEach node — iterates over a collection, executing child nodes per item.
- executeForkNode() : void
- Execute a fork node — marks complete and executes all output targets.
- executeHumanTaskNode() : void
- Execute a humanTask node — creates a task record and pauses the workflow.
- executeJoinNode() : void
- Execute a join node — waits for all input paths before advancing.
- executeLoopNode() : void
- Execute a loop node — iterates until max count or exit condition.
- executeNode() : void
- Execute a single workflow node and advance to connected outputs.
- executeStateMachineNode() : void
- Execute a state machine node — validates and applies a state transition with configurable rules, status resolution, and audit logging.
- executeSubworkflowNode() : void
- Execute a subworkflow node — starts a child workflow, sets instance to WAITING.
- findContextValueByKey() : mixed
- Recursively find the first non-empty value for a key in workflow context.
- findIncomingSource() : string
- Find which source node most recently completed execution leading into a join.
- findNodesByType() : array<string|int, mixed>
- Find all nodes of a given type in the definition.
- getAllOutputTargets() : array<string|int, string>
- Get all output targets for a node regardless of port.
- getNodeInputSources() : array<string|int, string>
- Get all source node IDs that have edges leading into the given node.
- getNodeOutputTargets() : array<string|int, string>
- Get target node IDs for a given node's output port.
- getTriggerEntityIdField() : string|null
- Resolve the trigger-configured entity ID field name for a workflow.
- hydrateInstanceEntityMetadata() : void
- Persist the workflow entity_id once it becomes available in context.
- parseDeadline() : DateTime|null
- Parse a deadline duration string (e.g., "14d", "24h", "7d") into a future DateTime.
- portsMatch() : bool
- Check if two port names are equivalent.
- removeFromActiveNodes() : void
- Remove a node from the instance's active_nodes list.
- resolveContextValue() : mixed
- Resolve a context value using a dot-path (e.g., '$.trigger.officer.id').
- resolveInputData() : array<string|int, mixed>
- Resolve input data for a node from context using configured mappings.
- resolveParamValue() : mixed
- Resolve a parameter value that may be a plain scalar, a $.path string, or a value descriptor object {type: '...', ...}.
- resolveRequiredCount() : int
- Resolve a required count value that may be an integer or a config object.
- saveLog() : void
- Save an execution log update. No-op if log is null (ephemeral mode).
- setContextValue() : void
- Set a value in the context at the given dot-path.
- updateInstance() : void
- Save instance changes to the database.
- applyActionContextUpdates() : mixed
- Apply action-requested context updates and remove private payload data from output.
- beginExecution() : array<string, mixed>
- Reset per-execution state and return the previous state for restoration.
- executeActionService() : mixed
- Execute a workflow action service while suppressing model-trigger loops.
- executeInTransaction() : ServiceResult
- Execute a callable inside a single database transaction, avoiding nesting.
- markInstanceFailed() : void
- Mark a workflow instance as FAILED after a transaction rollback.
- nodeHasOutput() : bool
- Check whether a node declares a connected output port.
- normalizeActionResult() : array<string, mixed>
- Normalize action provider output into the standard result envelope.
- refreshInstanceExecutionState() : void
- Synchronize an in-flight entity after a nested callback updated its row.
- restoreExecution() : void
- Restore per-execution state after a public engine entry point completes.
- startWorkflowInternal() : ServiceResult
- Start a workflow with optional parent callback metadata.
Constants
MAX_EXECUTION_DEPTH
Maximum node execution depth to prevent infinite recursion.
private
mixed
MAX_EXECUTION_DEPTH
= 200
Properties
$container
private
ContainerInterface
$container
$ephemeral
Whether the current execution is ephemeral (in-memory, no persistence).
private
bool
$ephemeral
= false
Set per-execution based on the workflow definition's execution_mode.
$executionDepth
Current execution depth counter.
private
int
$executionDepth
= 0
$isInTransaction
Whether we are currently inside a database transaction.
private
bool
$isInTransaction
= false
Prevents nested transaction wrapping when methods like startWorkflow() or resumeWorkflow() are called recursively (e.g., subworkflow nodes, child completion callbacks).
$visitedNodes
Tracks visited nodes during a single execution pass to detect cycles.
private
array<string, bool>
$visitedNodes
= []
Reset at the start of each startWorkflow/resumeWorkflow call.
Methods
__construct()
Constructor.
public
__construct(ContainerInterface $container) : mixed
Parameters
- $container : ContainerInterface
-
Service container
cancelHumanTask()
Cancel a pending human task without resuming the workflow.
public
cancelHumanTask(int $taskId[, string|null $reason = null ]) : ServiceResult
Parameters
- $taskId : int
-
The workflow_tasks.id to cancel
- $reason : string|null = null
-
Optional cancellation reason
Return values
ServiceResultcancelWorkflow()
Cancel a running or waiting workflow instance.
public
cancelWorkflow(int $instanceId[, string|null $reason = null ]) : ServiceResult
Parameters
- $instanceId : int
-
The workflow instance ID
- $reason : string|null = null
-
Optional cancellation reason
Tags
Return values
ServiceResultcompleteHumanTask()
Complete a human task and resume the workflow.
public
completeHumanTask(int $taskId, array<string|int, mixed> $formData, int $completedBy) : ServiceResult
Validates required form fields, saves form data to the task record, merges values into the workflow context via contextMapping, and resumes the workflow from the humanTask node's default output.
Parameters
- $taskId : int
-
The workflow_tasks.id to complete
- $formData : array<string|int, mixed>
-
Submitted form field values
- $completedBy : int
-
Member ID of the user completing the task
Return values
ServiceResultdispatchTrigger()
Dispatch a trigger event and start any matching workflows.
public
dispatchTrigger(string $eventName[, array<string|int, mixed> $eventData = [] ][, int|null $triggeredBy = null ]) : array<string|int, ServiceResult>
Parameters
- $eventName : string
-
The event name to match against triggers
- $eventData : array<string|int, mixed> = []
-
Data associated with the event
- $triggeredBy : int|null = null
-
Member ID who triggered the event
Tags
Return values
array<string|int, ServiceResult> —Results for each started workflow
fireIntermediateApprovalActions()
Fire actions connected to an approval node's on_each_approval port.
public
fireIntermediateApprovalActions(int $instanceId, string $nodeId, array<string|int, mixed> $approvalData[, string $outputPort = 'on_each_approval' ]) : ServiceResult
Parameters
- $instanceId : int
-
The workflow instance ID
- $nodeId : string
-
The approval node ID
- $approvalData : array<string|int, mixed>
-
Approval progress data (approverId, decision, comment, nextApproverId)
- $outputPort : string = 'on_each_approval'
-
Approval node output port to follow
Tags
Return values
ServiceResultgetInstanceState()
Get the current state of a workflow instance.
public
getInstanceState(int $instanceId) : array<string|int, mixed>|null
Parameters
- $instanceId : int
-
The workflow instance ID
Tags
Return values
array<string|int, mixed>|null —Instance state array or null if not found
resumeWorkflow()
Resume a waiting workflow instance from a specific node output.
public
resumeWorkflow(int $instanceId, string $nodeId, string $outputPort[, array<string|int, mixed> $additionalData = [] ]) : ServiceResult
Parameters
- $instanceId : int
-
The workflow instance ID
- $nodeId : string
-
The node to resume from
- $outputPort : string
-
The output port to follow
- $additionalData : array<string|int, mixed> = []
-
Extra data to merge into context
Tags
Return values
ServiceResultstartWorkflow()
Start a new workflow instance from a definition slug.
public
startWorkflow(string $workflowSlug[, array<string|int, mixed> $triggerData = [] ][, int|null $startedBy = null ][, string|null $entityType = null ][, int|null $entityId = null ]) : ServiceResult
Parameters
- $workflowSlug : string
-
The workflow definition slug
- $triggerData : array<string|int, mixed> = []
-
Data passed by the trigger event
- $startedBy : int|null = null
-
Member ID who initiated the workflow
- $entityType : string|null = null
-
Optional entity type this workflow operates on
- $entityId : int|null = null
-
Optional entity ID this workflow operates on
Tags
Return values
ServiceResult —Contains instanceId on success
advanceToOutputs()
Advance execution to all targets of a node's output port.
protected
advanceToOutputs(WorkflowInstance $instance, string $nodeId, string $port, array<string|int, mixed> $definition) : void
Parameters
- $instance : WorkflowInstance
- $nodeId : string
- $port : string
- $definition : array<string|int, mixed>
collectDescendants()
Collect all descendant node IDs reachable from a starting node.
protected
collectDescendants(array<string|int, mixed> $definition, string $nodeId, array<string|int, mixed> &$collected) : void
Parameters
- $definition : array<string|int, mixed>
- $nodeId : string
- $collected : array<string|int, mixed>
createExecutionLog()
Create an execution log entry. Returns null for ephemeral workflows.
protected
createExecutionLog(WorkflowInstance $instance, string $nodeId, string $nodeType, int $attempt[, array<string|int, mixed>|null $inputData = null ][, array<string|int, mixed>|null $outputData = null ]) : WorkflowExecutionLog|null
Parameters
- $instance : WorkflowInstance
-
Current instance
- $nodeId : string
-
Node identifier
- $nodeType : string
-
Node type
- $attempt : int
-
Attempt number
- $inputData : array<string|int, mixed>|null = null
-
Input data for the node
- $outputData : array<string|int, mixed>|null = null
-
Output data (for completed-on-create logs like triggers)
Return values
WorkflowExecutionLog|nullexecuteActionNode()
Execute an action node via the WorkflowActionRegistry.
protected
executeActionNode(WorkflowInstance $instance, string $nodeId, array<string|int, mixed> $node, WorkflowExecutionLog|null $log, array<string|int, mixed> $definition) : void
Parameters
- $instance : WorkflowInstance
- $nodeId : string
- $node : array<string|int, mixed>
- $log : WorkflowExecutionLog|null
- $definition : array<string|int, mixed>
executeApprovalNode()
Execute an approval node — creates approval record, sets instance to WAITING.
protected
executeApprovalNode(WorkflowInstance $instance, string $nodeId, array<string|int, mixed> $node, WorkflowExecutionLog|null $log) : void
Parameters
- $instance : WorkflowInstance
- $nodeId : string
- $node : array<string|int, mixed>
- $log : WorkflowExecutionLog|null
executeConditionNode()
Execute a condition node and follow the matching output port.
protected
executeConditionNode(WorkflowInstance $instance, string $nodeId, array<string|int, mixed> $node, WorkflowExecutionLog|null $log, array<string|int, mixed> $definition) : void
Parameters
- $instance : WorkflowInstance
- $nodeId : string
- $node : array<string|int, mixed>
- $log : WorkflowExecutionLog|null
- $definition : array<string|int, mixed>
executeDelayNode()
Execute a delay node — sets instance to WAITING for later resumption.
protected
executeDelayNode(WorkflowInstance $instance, string $nodeId, array<string|int, mixed> $node, WorkflowExecutionLog|null $log) : void
Parameters
- $instance : WorkflowInstance
- $nodeId : string
- $node : array<string|int, mixed>
- $log : WorkflowExecutionLog|null
executeEndNode()
Execute an end node — completes this path, finishes instance if no active nodes remain.
protected
executeEndNode(WorkflowInstance $instance, string $nodeId, array<string|int, mixed> $node, WorkflowExecutionLog|null $log) : void
If this instance is a child workflow, resumes the parent instance.
Parameters
- $instance : WorkflowInstance
- $nodeId : string
- $node : array<string|int, mixed>
- $log : WorkflowExecutionLog|null
executeForEachNode()
Execute a forEach node — iterates over a collection, executing child nodes per item.
protected
executeForEachNode(WorkflowInstance $instance, string $nodeId, array<string|int, mixed> $node, WorkflowExecutionLog|null $log, array<string|int, mixed> $definition) : void
Output ports: 'iterate' (per item), 'complete' (after all), 'error' (on failure).
Parameters
- $instance : WorkflowInstance
- $nodeId : string
- $node : array<string|int, mixed>
- $log : WorkflowExecutionLog|null
- $definition : array<string|int, mixed>
executeForkNode()
Execute a fork node — marks complete and executes all output targets.
protected
executeForkNode(WorkflowInstance $instance, string $nodeId, WorkflowExecutionLog|null $log, array<string|int, mixed> $definition) : void
Parameters
- $instance : WorkflowInstance
- $nodeId : string
- $log : WorkflowExecutionLog|null
- $definition : array<string|int, mixed>
executeHumanTaskNode()
Execute a humanTask node — creates a task record and pauses the workflow.
protected
executeHumanTaskNode(WorkflowInstance $instance, string $nodeId, array<string|int, mixed> $node, WorkflowExecutionLog|null $log) : void
The workflow remains in WAITING status until completeHumanTask() is called with the submitted form data.
Parameters
- $instance : WorkflowInstance
- $nodeId : string
- $node : array<string|int, mixed>
- $log : WorkflowExecutionLog|null
executeJoinNode()
Execute a join node — waits for all input paths before advancing.
protected
executeJoinNode(WorkflowInstance $instance, string $nodeId, array<string|int, mixed> $node, WorkflowExecutionLog|null $log, array<string|int, mixed> $definition) : void
Parameters
- $instance : WorkflowInstance
- $nodeId : string
- $node : array<string|int, mixed>
- $log : WorkflowExecutionLog|null
- $definition : array<string|int, mixed>
executeLoopNode()
Execute a loop node — iterates until max count or exit condition.
protected
executeLoopNode(WorkflowInstance $instance, string $nodeId, array<string|int, mixed> $node, WorkflowExecutionLog|null $log, array<string|int, mixed> $definition) : void
Parameters
- $instance : WorkflowInstance
- $nodeId : string
- $node : array<string|int, mixed>
- $log : WorkflowExecutionLog|null
- $definition : array<string|int, mixed>
executeNode()
Execute a single workflow node and advance to connected outputs.
protected
executeNode(WorkflowInstance $instance, string $nodeId, array<string|int, mixed> $definition) : void
Parameters
- $instance : WorkflowInstance
-
The workflow instance
- $nodeId : string
-
The node ID to execute
- $definition : array<string|int, mixed>
-
The workflow definition graph
executeStateMachineNode()
Execute a state machine node — validates and applies a state transition with configurable rules, status resolution, and audit logging.
protected
executeStateMachineNode(WorkflowInstance $instance, string $nodeId, array<string|int, mixed> $node, WorkflowExecutionLog|null $log, array<string|int, mixed> $definition) : void
Parameters
- $instance : WorkflowInstance
- $nodeId : string
- $node : array<string|int, mixed>
- $log : WorkflowExecutionLog|null
- $definition : array<string|int, mixed>
executeSubworkflowNode()
Execute a subworkflow node — starts a child workflow, sets instance to WAITING.
protected
executeSubworkflowNode(WorkflowInstance $instance, string $nodeId, array<string|int, mixed> $node, WorkflowExecutionLog|null $log) : void
Passes parent instance/node info so the child can resume the parent on completion.
Parameters
- $instance : WorkflowInstance
- $nodeId : string
- $node : array<string|int, mixed>
- $log : WorkflowExecutionLog|null
findContextValueByKey()
Recursively find the first non-empty value for a key in workflow context.
protected
findContextValueByKey(mixed $value, string $targetKey) : mixed
Parameters
- $value : mixed
-
Context value to inspect
- $targetKey : string
-
Key to locate
findIncomingSource()
Find which source node most recently completed execution leading into a join.
protected
findIncomingSource(array<string|int, mixed> $definition, string $joinNodeId, WorkflowInstance $instance[, array<string|int, mixed> $alreadyCompletedInputs = [] ]) : string
Parameters
- $definition : array<string|int, mixed>
-
The workflow definition
- $joinNodeId : string
-
The join node ID
- $instance : WorkflowInstance
-
The workflow instance
- $alreadyCompletedInputs : array<string|int, mixed> = []
Return values
string —The most recently completed source node ID
findNodesByType()
Find all nodes of a given type in the definition.
protected
findNodesByType(array<string|int, mixed> $definition, string $type) : array<string|int, mixed>
Parameters
- $definition : array<string|int, mixed>
-
The workflow definition
- $type : string
-
Node type to find
Return values
array<string|int, mixed> —Matching nodes keyed by node ID
getAllOutputTargets()
Get all output targets for a node regardless of port.
protected
getAllOutputTargets(array<string|int, mixed> $definition, string $nodeId) : array<string|int, string>
Parameters
- $definition : array<string|int, mixed>
-
The workflow definition
- $nodeId : string
-
Source node ID
Return values
array<string|int, string> —Target node IDs
getNodeInputSources()
Get all source node IDs that have edges leading into the given node.
protected
getNodeInputSources(array<string|int, mixed> $definition, string $nodeId) : array<string|int, string>
Parameters
- $definition : array<string|int, mixed>
-
The workflow definition
- $nodeId : string
-
The target node ID
Return values
array<string|int, string> —Source node IDs
getNodeOutputTargets()
Get target node IDs for a given node's output port.
protected
getNodeOutputTargets(array<string|int, mixed> $definition, string $nodeId, string $port) : array<string|int, string>
Parameters
- $definition : array<string|int, mixed>
-
The workflow definition
- $nodeId : string
-
Source node ID
- $port : string
-
Output port name
Return values
array<string|int, string> —Target node IDs
getTriggerEntityIdField()
Resolve the trigger-configured entity ID field name for a workflow.
protected
getTriggerEntityIdField(array<string|int, mixed> $definition) : string|null
Parameters
- $definition : array<string|int, mixed>
-
Workflow definition graph
Return values
string|nullhydrateInstanceEntityMetadata()
Persist the workflow entity_id once it becomes available in context.
protected
hydrateInstanceEntityMetadata(WorkflowInstance $instance, array<string|int, mixed> $definition) : void
Some durable workflows create the underlying entity inside an action node, after the workflow instance has already been inserted. When the trigger node declares an entityIdField, scan the accumulated context for that key and promote it onto the workflow instance as soon as it appears.
Parameters
- $instance : WorkflowInstance
-
Current workflow instance
- $definition : array<string|int, mixed>
-
Workflow definition graph
parseDeadline()
Parse a deadline duration string (e.g., "14d", "24h", "7d") into a future DateTime.
protected
parseDeadline(string $deadline) : DateTime|null
Parameters
- $deadline : string
Return values
DateTime|nullportsMatch()
Check if two port names are equivalent.
protected
portsMatch(string $a, string $b) : bool
Treats "next" and "default" as equivalent for regular action/trigger outputs.
Parameters
- $a : string
- $b : string
Return values
boolremoveFromActiveNodes()
Remove a node from the instance's active_nodes list.
protected
removeFromActiveNodes(WorkflowInstance $instance, string $nodeId) : void
Parameters
- $instance : WorkflowInstance
- $nodeId : string
resolveContextValue()
Resolve a context value using a dot-path (e.g., '$.trigger.officer.id').
protected
resolveContextValue(array<string|int, mixed> $context, string $path) : mixed
Parameters
- $context : array<string|int, mixed>
-
The workflow context
- $path : string
-
Dot-separated path, optionally prefixed with '$.'
resolveInputData()
Resolve input data for a node from context using configured mappings.
protected
resolveInputData(array<string|int, mixed> $context, array<string|int, mixed> $nodeConfig) : array<string|int, mixed>
Parameters
- $context : array<string|int, mixed>
-
The workflow context
- $nodeConfig : array<string|int, mixed>
-
The node's configuration
Return values
array<string|int, mixed> —Resolved input data
resolveParamValue()
Resolve a parameter value that may be a plain scalar, a $.path string, or a value descriptor object {type: '...', ...}.
protected
resolveParamValue(mixed $value, array<string|int, mixed> $context[, mixed $default = null ]) : mixed
Parameters
- $value : mixed
-
The raw parameter value from workflow config
- $context : array<string|int, mixed>
-
The workflow instance context
- $default : mixed = null
-
Fallback if resolution fails
Return values
mixed —The resolved value
resolveRequiredCount()
Resolve a required count value that may be an integer or a config object.
protected
resolveRequiredCount(mixed $value, array<string|int, mixed> $context) : int
Delegates to resolveParamValue() for universal resolution, then ensures the result is an integer >= 1.
Parameters
- $value : mixed
- $context : array<string|int, mixed>
Return values
intsaveLog()
Save an execution log update. No-op if log is null (ephemeral mode).
protected
saveLog(WorkflowExecutionLog|null $log) : void
Parameters
- $log : WorkflowExecutionLog|null
setContextValue()
Set a value in the context at the given dot-path.
protected
setContextValue(array<string|int, mixed> &$context, string $path, mixed $value) : void
Parameters
- $context : array<string|int, mixed>
-
The workflow context (by reference)
- $path : string
-
Dot-separated path
- $value : mixed
-
The value to set
updateInstance()
Save instance changes to the database.
protected
updateInstance(WorkflowInstance $instance, array<string|int, mixed> $changes) : void
Parameters
- $instance : WorkflowInstance
-
The instance to save
- $changes : array<string|int, mixed>
-
Additional field changes to apply
applyActionContextUpdates()
Apply action-requested context updates and remove private payload data from output.
private
applyActionContextUpdates(array<string|int, mixed> &$context, mixed $result) : mixed
Parameters
- $context : array<string|int, mixed>
-
Workflow context, updated by reference
- $result : mixed
-
Raw action result
Return values
mixed —Public action result
beginExecution()
Reset per-execution state and return the previous state for restoration.
private
beginExecution(bool $ephemeral) : array<string, mixed>
Parameters
- $ephemeral : bool
-
Whether this execution should avoid persistence
Return values
array<string, mixed>executeActionService()
Execute a workflow action service while suppressing model-trigger loops.
private
executeActionService(object $service, string $serviceMethod, array<string, mixed> $context, array<string, mixed> $nodeConfig) : mixed
Workflow actions often save the same entities that can emit workflow triggers. Suppression prevents recursive duplicate workflows while the workflow engine is already applying an intentional state transition.
Parameters
- $service : object
-
Workflow action service instance.
- $serviceMethod : string
-
Method to invoke.
- $context : array<string, mixed>
-
Workflow context.
- $nodeConfig : array<string, mixed>
-
Resolved node config.
executeInTransaction()
Execute a callable inside a single database transaction, avoiding nesting.
private
executeInTransaction(callable $work, string $methodName[, int|null $existingInstanceId = null ]) : ServiceResult
When already inside a transaction (e.g., subworkflow calling startWorkflow, or child completion calling resumeWorkflow), the callable runs directly without a new transactional() wrapper — all work shares the outer transaction.
CakePHP supports nested transactional() calls via savepoints, so services invoked by action nodes (e.g., WarrantManager) that open their own transactional() blocks are safe and participate in the outer transaction.
On failure at the top level the transaction is rolled back automatically. If $existingInstanceId is provided, the instance is marked FAILED in a separate post-rollback save so the database reflects the terminal state.
Parameters
- $work : callable
-
The work to execute inside the transaction
- $methodName : string
-
Method name for error logging
- $existingInstanceId : int|null = null
-
Instance ID to mark FAILED on rollback
Return values
ServiceResultmarkInstanceFailed()
Mark a workflow instance as FAILED after a transaction rollback.
private
markInstanceFailed(int $instanceId, string $errorMessage) : void
Runs outside any transaction so the FAILED status persists even though the main transaction was rolled back.
Parameters
- $instanceId : int
-
The instance to mark
- $errorMessage : string
-
The error that caused the failure
nodeHasOutput()
Check whether a node declares a connected output port.
private
nodeHasOutput(array<string|int, mixed> $node, string $outputPort) : bool
Parameters
- $node : array<string|int, mixed>
-
Workflow node definition
- $outputPort : string
-
Port name
Return values
boolnormalizeActionResult()
Normalize action provider output into the standard result envelope.
private
normalizeActionResult(mixed $result) : array<string, mixed>
Parameters
- $result : mixed
-
Raw action provider result
Return values
array<string, mixed>refreshInstanceExecutionState()
Synchronize an in-flight entity after a nested callback updated its row.
private
refreshInstanceExecutionState(WorkflowInstance $instance) : void
Parameters
- $instance : WorkflowInstance
restoreExecution()
Restore per-execution state after a public engine entry point completes.
private
restoreExecution(array<string, mixed> $state) : void
Parameters
- $state : array<string, mixed>
-
State returned by beginExecution()
startWorkflowInternal()
Start a workflow with optional parent callback metadata.
private
startWorkflowInternal(string $workflowSlug[, array<string|int, mixed> $triggerData = [] ][, int|null $startedBy = null ][, string|null $entityType = null ][, int|null $entityId = null ][, int|null $parentInstanceId = null ][, string|null $parentNodeId = null ]) : ServiceResult
Parameters
- $workflowSlug : string
- $triggerData : array<string|int, mixed> = []
- $startedBy : int|null = null
- $entityType : string|null = null
- $entityId : int|null = null
- $parentInstanceId : int|null = null
- $parentNodeId : string|null = null