Conditional
The conditional step type evaluates a registered conditional handler against workflow variables and branches the workflow based on the result. It always produces a 'true' or 'false' outcome that determines the transition path.
Definition
'check_amount' => [
'type' => 'conditional',
'handler' => 'is_high_value',
]Required Fields
| Field | Type | Description |
|---|---|---|
type | string | Must be 'conditional' |
handler | string | Registry name or fully-qualified class name of a Conditional implementation |
Additional keys in the step definition are accessible to the handler via $context->getStepConfig().
Conditional Handlers
Each conditional is a class that implements the Conditional interface:
use Workflowable\Workflowable\Contracts\Conditional;
use Workflowable\Workflowable\Engine\ExecutionContext;
class IsHighValue implements Conditional
{
public function evaluate(ExecutionContext $context): bool
{
$threshold = $context->getStepConfig('threshold', 1000);
$amount = $context->getVariable('amount');
return $amount >= $threshold;
}
}The handler receives the full ExecutionContext, giving it access to:
- Workflow variables via
getVariable()— data from the event and previous step outputs - Step config via
getStepConfig()— parameters set in the workflow definition for this step
Registration
Conditionals are registered in the ConditionalRegistry, just like actions.
Global Registration (config)
Register conditionals available to all workflows in config/workflowable.php:
'conditionals' => [
'is_high_value' => \App\Conditionals\IsHighValue::class,
'is_eligible' => \App\Conditionals\IsEligible::class,
],Event-Scoped Registration
Register conditionals only available to workflows for a specific event:
'events' => [
'order_submitted' => [
'class' => \App\WorkflowEvents\OrderSubmitted::class,
'description' => 'Triggered when a new order is submitted',
'actions' => [
'process_order' => \App\Actions\ProcessOrder::class,
],
'conditionals' => [
'is_high_value' => \App\Conditionals\IsHighValue::class,
],
],
],Programmatic Registration
$registry = app(ConditionalRegistry::class);
$registry->register('is_high_value', IsHighValue::class, 'Checks if order exceeds threshold');Conditional Parameters
Conditionals can define their own parameters by implementing the DefinesParameters interface. This enables validation at workflow definition time:
use Workflowable\Workflowable\Contracts\Conditional;
use Workflowable\Workflowable\Contracts\DefinesParameters;
use Workflowable\Workflowable\Engine\ExecutionContext;
use Workflowable\Workflowable\Support\Parameters\NumberParameter;
use Workflowable\Workflowable\Support\Parameters\TextParameter;
class IsHighValue implements Conditional, DefinesParameters
{
public static function parameters(): array
{
return [
TextParameter::make('variable', 'Variable Name')
->rules(['string']),
NumberParameter::make('threshold', 'Threshold')
->default(1000),
];
}
public function evaluate(ExecutionContext $context): bool
{
$variable = $context->getStepConfig('variable', 'amount');
$threshold = $context->getStepConfig('threshold', 1000);
return $context->getVariable($variable) >= $threshold;
}
}Then in the workflow definition, parameters are passed as step config:
'check_amount' => [
'type' => 'conditional',
'handler' => 'is_high_value',
'variable' => 'order_total',
'threshold' => 5000,
]Required parameters without defaults are validated when the workflow definition is saved.
Handler Resolution
When the engine executes a conditional step:
- It looks up the
handlername in theConditionalRegistry - If not found, it falls back to treating
handleras a fully-qualified class name - The class must implement the
Conditionalinterface - The handler's
evaluate()method is called with theExecutionContext - Returns
StepResult::success()withcondition: 'true'or'false'(used for transition routing)
Transitions
Conditional steps must define transitions for both 'true' and 'false' outcomes:
'transitions' => [
'check_amount' => [
'true' => 'high_value_approval',
'false' => 'standard_process',
],
]Both paths can lead to the same step if needed:
'transitions' => [
'check_amount' => [
'true' => 'process_order',
'false' => 'process_order',
],
]Either path can lead to a terminal state:
'transitions' => [
'check_eligibility' => [
'true' => 'process_application',
'false' => 'failed',
],
]Chaining Conditions
Chain multiple conditional steps to create complex decision trees:
'steps' => [
'check_amount' => [
'type' => 'conditional',
'handler' => 'is_high_value',
'threshold' => 1000,
],
'check_priority' => [
'type' => 'conditional',
'handler' => 'is_priority',
],
'standard_process' => [
'type' => 'action',
'handler' => 'standard_process',
],
'priority_process' => [
'type' => 'action',
'handler' => 'priority_process',
],
'high_value_review' => [
'type' => 'action',
'handler' => 'high_value_review',
],
],
'transitions' => [
'check_amount' => [
'true' => 'high_value_review',
'false' => 'check_priority',
],
'check_priority' => [
'true' => 'priority_process',
'false' => 'standard_process',
],
'high_value_review' => 'completed',
'standard_process' => 'completed',
'priority_process' => 'completed',
]Common Patterns
Gate Check
Use a conditional as a gate to short-circuit the workflow:
'steps' => [
'check_eligible' => [
'type' => 'conditional',
'handler' => 'is_eligible',
],
'process' => [
'type' => 'action',
'handler' => 'process',
],
],
'transitions' => [
'check_eligible' => [
'true' => 'process',
'false' => 'failed',
],
'process' => 'completed',
]Configurable Threshold
Use step config to make a conditional reusable across different steps:
'steps' => [
'check_order_value' => [
'type' => 'conditional',
'handler' => 'is_high_value',
'variable' => 'order_total',
'threshold' => 5000,
],
'check_shipping_cost' => [
'type' => 'conditional',
'handler' => 'is_high_value',
'variable' => 'shipping_cost',
'threshold' => 100,
],
],Boolean Flag Check
Check a flag set by a previous step:
'steps' => [
'validate_order' => [
'type' => 'action',
'handler' => 'validate_order',
// Returns: ['is_valid' => true] or ['is_valid' => false]
],
'check_valid' => [
'type' => 'conditional',
'handler' => 'is_truthy',
'variable' => 'is_valid',
],
],
'transitions' => [
'validate_order' => 'check_valid',
'check_valid' => [
'true' => 'process_order',
'false' => 'failed',
],
]