-
-
Notifications
You must be signed in to change notification settings - Fork 0
Conditions Branching
Jean-Marc Strauven edited this page Aug 6, 2025
·
1 revision
β Error Handling | Home | Queue Integration β
Laravel Flowpipe supports powerful conditional logic to create dynamic workflows that adapt based on data and business rules.
Conditional execution allows your workflows to make decisions and follow different paths based on the payload data. This enables dynamic, intelligent workflows that respond to real-world scenarios.
# Simple example: Different paths for different user types
steps:
- condition:
field: user_type
operator: equals
value: premium
then:
- type: action
class: PremiumUserOnboardingStep
else:
- type: action
class: BasicUserOnboardingStep
steps:
- condition:
field: payment_required
operator: equals
value: true
then:
- type: action
class: ProcessPaymentStep
else:
- type: action
class: MarkAsFreeStep
steps:
- type: action
name: send-premium-features-email
class: SendPremiumFeaturesEmailStep
when:
field: user_type
operator: equals
value: premium
steps:
- condition:
field: user.profile.country
operator: equals
value: "US"
then:
- type: action
class: ApplyUSTaxesStep
# Exact match
operator: equals
operator: not_equals
# Examples
condition:
field: status
operator: equals
value: "active"
condition:
field: verified
operator: not_equals
value: false
# Numeric comparisons
operator: greater_than
operator: less_than
operator: greater_than_or_equal
operator: less_than_or_equal
# Examples
condition:
field: order_total
operator: greater_than
value: 100
condition:
field: user_age
operator: greater_than_or_equal
value: 18
# String operations
operator: contains
operator: not_contains
operator: starts_with
operator: ends_with
# Examples
condition:
field: email
operator: ends_with
value: "@company.com"
condition:
field: description
operator: contains
value: "urgent"
# Array membership
operator: in
operator: not_in
# Examples
condition:
field: country
operator: in
value: ["US", "CA", "GB"]
condition:
field: user_role
operator: not_in
value: ["banned", "suspended"]
# Field existence
operator: exists
operator: not_exists
operator: is_null
operator: is_not_null
operator: is_empty
operator: is_not_empty
# Examples
condition:
field: profile_picture
operator: exists
condition:
field: middle_name
operator: is_not_null
condition:
all:
- field: user_type
operator: equals
value: premium
- field: subscription_active
operator: equals
value: true
- field: account_balance
operator: greater_than
value: 0
then:
- type: action
class: GrantPremiumAccessStep
condition:
any:
- field: user_role
operator: equals
value: admin
- field: user_role
operator: equals
value: moderator
- field: has_special_permission
operator: equals
value: true
then:
- type: action
class: GrantAdminAccessStep
condition:
all:
- field: order_type
operator: equals
value: "subscription"
- any:
- field: payment_method
operator: equals
value: "credit_card"
- all:
- field: payment_method
operator: equals
value: "bank_transfer"
- field: account_verified
operator: equals
value: true
then:
- type: action
class: ProcessSubscriptionStep
steps:
# User type routing
- condition:
field: user_type
operator: equals
value: enterprise
then:
- type: group
name: enterprise-onboarding
- condition:
field: user_type
operator: equals
value: premium
then:
- type: group
name: premium-onboarding
- condition:
field: user_type
operator: equals
value: basic
then:
- type: group
name: basic-onboarding
else:
# Default case
- type: action
class: DefaultOnboardingStep
steps:
- type: switch
field: payment_method
cases:
credit_card:
- type: action
class: ProcessCreditCardStep
- type: action
class: UpdateCreditCardRewardsStep
paypal:
- type: action
class: ProcessPaypalStep
- type: action
class: SyncPaypalAccountStep
bank_transfer:
- type: action
class: ProcessBankTransferStep
- type: action
class: ScheduleBankTransferStep
default:
- type: action
class: ProcessGenericPaymentStep
steps:
# Base functionality (always executed)
- type: action
name: create-basic-profile
class: CreateBasicProfileStep
# Enhanced features based on user type
- type: action
name: add-premium-features
class: AddPremiumFeaturesStep
when:
field: user_type
operator: in
value: ["premium", "enterprise"]
- type: action
name: setup-enterprise-integration
class: SetupEnterpriseIntegrationStep
when:
field: user_type
operator: equals
value: enterprise
- type: action
name: assign-account-manager
class: AssignAccountManagerStep
when:
all:
- field: user_type
operator: equals
value: enterprise
- field: annual_revenue
operator: greater_than
value: 1000000
flow: smart-order-processing
description: Intelligent order processing with dynamic routing
send:
order_id: "ORD-12345"
customer_type: "premium"
order_total: 250.00
items_count: 3
shipping_country: "US"
steps:
# Basic validation (always runs)
- type: action
name: validate-order
class: ValidateOrderStep
# Premium customer benefits
- condition:
field: customer_type
operator: equals
value: premium
then:
- type: action
name: apply-premium-discount
class: ApplyPremiumDiscountStep
- type: action
name: upgrade-shipping
class: UpgradeToFreeShippingStep
# Large order handling
- condition:
field: order_total
operator: greater_than
value: 200
then:
- type: action
name: fraud-check
class: EnhancedFraudCheckStep
- type: action
name: manager-approval
class: RequireManagerApprovalStep
when:
field: order_total
operator: greater_than
value: 500
# International shipping
- condition:
field: shipping_country
operator: not_equals
value: "US"
then:
- type: action
name: calculate-duties
class: CalculateCustomsDutiesStep
- type: action
name: verify-shipping-restrictions
class: VerifyShippingRestrictionsStep
# Payment processing (different methods)
- condition:
field: payment_method
operator: equals
value: "credit_card"
then:
- type: action
class: ProcessCreditCardPaymentStep
else:
- condition:
field: payment_method
operator: equals
value: "paypal"
then:
- type: action
class: ProcessPaypalPaymentStep
else:
- type: action
class: ProcessAlternativePaymentStep
flow: content-moderation
description: Smart content moderation with escalation
send:
content_id: "POST-456"
user_reputation: 85
content_type: "image"
reported_count: 2
steps:
# Automated checks
- type: action
name: spam-detection
class: SpamDetectionStep
- type: action
name: profanity-filter
class: ProfanityFilterStep
# Image-specific checks
- condition:
field: content_type
operator: equals
value: "image"
then:
- type: action
name: image-content-scan
class: ImageContentScanStep
- type: action
name: nsfw-detection
class: NsfwDetectionStep
# User reputation-based processing
- condition:
field: user_reputation
operator: greater_than
value: 90
then:
# High reputation users get auto-approved
- type: action
name: auto-approve
class: AutoApproveContentStep
else:
- condition:
any:
- field: user_reputation
operator: less_than
value: 50
- field: reported_count
operator: greater_than
value: 1
then:
# Low reputation or reported content goes to human review
- type: action
name: queue-human-review
class: QueueForHumanReviewStep
else:
# Medium reputation gets AI review
- type: action
name: ai-content-analysis
class: AiContentAnalysisStep
- condition:
field: ai_confidence
operator: greater_than
value: 0.8
then:
- type: action
name: auto-approve
class: AutoApproveContentStep
else:
- type: action
name: queue-human-review
class: QueueForHumanReviewStep
flow: notification-routing
description: Smart notification delivery based on user preferences
send:
user_id: 123
notification_type: "order_update"
urgency: "medium"
user_timezone: "America/New_York"
steps:
# Get user preferences
- type: action
name: fetch-preferences
class: FetchUserPreferencesStep
# Check if notifications are enabled
- condition:
field: preferences.notifications_enabled
operator: equals
value: false
then:
- type: action
name: log-notification-skipped
class: LogNotificationSkippedStep
# Exit early
else:
# Determine delivery method based on urgency and preferences
- condition:
field: urgency
operator: equals
value: "high"
then:
# High urgency: multiple channels
- type: action
name: send-push-notification
class: SendPushNotificationStep
- type: action
name: send-sms
class: SendSmsStep
when:
field: preferences.sms_enabled
operator: equals
value: true
- type: action
name: send-email
class: SendEmailStep
else:
# Medium/Low urgency: preferred channel only
- condition:
field: preferences.preferred_channel
operator: equals
value: "push"
then:
- type: action
name: send-push-notification
class: SendPushNotificationStep
- condition:
field: preferences.preferred_channel
operator: equals
value: "email"
then:
- type: action
name: send-email
class: SendEmailStep
- condition:
field: preferences.preferred_channel
operator: equals
value: "sms"
then:
- type: action
name: send-sms
class: SendSmsStep
# Respect quiet hours
- condition:
all:
- field: current_hour_in_user_tz
operator: greater_than_or_equal
value: 22
- field: urgency
operator: not_equals
value: "high"
then:
- type: action
name: schedule-for-later
class: ScheduleNotificationStep
config:
delay_until_hour: 9
<?php
namespace App\Flowpipe\Conditions;
use Grazulex\LaravelFlowpipe\Contracts\Condition;
class BusinessHoursCondition implements Condition
{
public function evaluate(array $payload, array $context = []): bool
{
$timezone = $payload['user_timezone'] ?? 'UTC';
$now = now($timezone);
// Business hours: 9 AM to 6 PM, Monday to Friday
return $now->isWeekday() &&
$now->hour >= 9 &&
$now->hour < 18;
}
}
steps:
- condition:
custom: App\Flowpipe\Conditions\BusinessHoursCondition
then:
- type: action
name: process-immediately
class: ProcessImmediatelyStep
else:
- type: action
name: queue-for-business-hours
class: QueueForBusinessHoursStep
<?php
namespace Tests\Unit\Flowpipe;
use Tests\TestCase;
use Grazulex\LaravelFlowpipe\Flowpipe;
class ConditionalLogicTest extends TestCase
{
public function test_premium_user_gets_special_treatment()
{
$result = Flowpipe::fromYaml('user-onboarding')
->send([
'user_type' => 'premium',
'email' => '[email protected]'
])
->execute();
$this->assertTrue($result->isSuccessful());
$this->assertTrue($result->data['premium_features_enabled']);
$this->assertEquals('premium', $result->data['onboarding_track']);
}
public function test_basic_user_gets_standard_treatment()
{
$result = Flowpipe::fromYaml('user-onboarding')
->send([
'user_type' => 'basic',
'email' => '[email protected]'
])
->execute();
$this->assertTrue($result->isSuccessful());
$this->assertFalse($result->data['premium_features_enabled']);
$this->assertEquals('basic', $result->data['onboarding_track']);
}
}
public function test_order_processing_handles_all_scenarios()
{
// Test premium customer with large order
$premiumResult = Flowpipe::fromYaml('smart-order-processing')
->send([
'customer_type' => 'premium',
'order_total' => 300.00,
'shipping_country' => 'CA'
])
->execute();
$this->assertTrue($premiumResult->data['premium_discount_applied']);
$this->assertTrue($premiumResult->data['enhanced_fraud_check_performed']);
$this->assertTrue($premiumResult->data['customs_duties_calculated']);
// Test basic customer with small order
$basicResult = Flowpipe::fromYaml('smart-order-processing')
->send([
'customer_type' => 'basic',
'order_total' => 50.00,
'shipping_country' => 'US'
])
->execute();
$this->assertFalse($basicResult->data['premium_discount_applied']);
$this->assertFalse($basicResult->data['enhanced_fraud_check_performed']);
}
# Good: Simple, readable condition
condition:
field: user_type
operator: equals
value: premium
# Avoid: Overly complex nested conditions
condition:
all:
- any:
- all: [...]
- field: complex_field
operator: contains
value: "something"
- any: [...]
# Good: Descriptive field names
condition:
field: subscription_active
operator: equals
value: true
# Avoid: Cryptic field names
condition:
field: flag_1
operator: equals
value: true
# Document complex business rules
- condition:
# European users need GDPR consent for marketing emails
all:
- field: user_location.region
operator: equals
value: "EU"
- field: gdpr_consent_marketing
operator: not_equals
value: true
then:
- type: action
name: skip-marketing-email
class: SkipMarketingEmailStep
# Always provide an else case for critical paths
- condition:
field: payment_processor_available
operator: equals
value: true
then:
- type: action
class: ProcessPaymentStep
else:
# Fallback to queue processing
- type: action
class: QueuePaymentForLaterStep
- Queue Integration - Asynchronous conditional processing
- Error Handling - Error handling with conditions
- PHP Steps - Complex conditional step logic
- Example User Registration - See conditions in action
Laravel Flowpipe - YAML-driven workflow engine for Laravel
GitHub: Laravel Flowpipe Repository | Support: GitHub Issues
Quick Navigation: Home β’ Installation β’ Configuration β’ Commands β’ Examples
π§ Developed by Grazulex