A modern, type-safe workflow engine for Laravel built with PHP 8.3+ features
Create powerful business workflows with simple, maintainable code.
β οΈ WARNING: DEVELOPMENT STATUSβ οΈ This package is currently under active development and is NOT READY FOR PRODUCTION USE.
Features may be incomplete, APIs might change, and there could be breaking changes. Use at your own risk in development environments only.
- π¨ Simple & Intuitive - Array-based workflow definitions and fluent WorkflowBuilder API
- π·οΈ Modern PHP 8.3+ Attributes - Declarative configuration with #[WorkflowStep], #[Retry], #[Timeout]
- π Type Safety First - Built with enums, strong typing, and modern PHP features
- β‘ Laravel Native - Seamless integration with Laravel's ecosystem and helpers
- π§© Extensible - Easy to extend with custom actions and storage adapters
- π Well Tested - Comprehensive test suite with real-world examples
composer require solution-forest/workflow-engine-laravel
Optionally publish the config file:
php artisan vendor:publish --tag="workflow-engine-config"
For database storage, run the migrations:
php artisan migrate
The migration will create a workflow_instances
table to store workflow state and progress.
use SolutionForest\WorkflowEngine\Core\WorkflowEngine;
// Create a simple workflow definition
$definition = [
'name' => 'User Onboarding',
'version' => '1.0',
'steps' => [
[
'id' => 'welcome',
'name' => 'Send Welcome',
'action' => 'log',
'parameters' => [
'message' => 'Welcome {{ user.name }}!',
'level' => 'info'
]
],
[
'id' => 'setup',
'name' => 'Setup Account',
'action' => 'log',
'parameters' => [
'message' => 'Setting up account for {{ user.email }}',
'level' => 'info'
]
]
]
];
// Start the workflow using the engine
$workflowId = workflow()->start('user-onboarding-001', $definition, [
'user' => ['name' => 'John Doe', 'email' => '[email protected]']
]);
// Or use the helper functions
$workflowId = start_workflow('user-onboarding-002', $definition, [
'user' => ['name' => 'Jane Doe', 'email' => '[email protected]']
]);
$definition = [
'name' => 'Order Processing',
'version' => '1.0',
'steps' => [
[
'id' => 'validate-order',
'name' => 'Validate Order',
'action' => 'log',
'parameters' => [
'message' => 'Validating order {{ order.id }}',
'level' => 'info'
]
],
[
'id' => 'process-payment',
'name' => 'Process Payment',
'action' => 'log',
'parameters' => [
'message' => 'Processing payment for {{ order.total }}',
'level' => 'info'
]
],
[
'id' => 'fulfill-order',
'name' => 'Fulfill Order',
'action' => 'log',
'parameters' => [
'message' => 'Order {{ order.id }} fulfilled',
'level' => 'info'
]
]
]
];
$workflowId = start_workflow('order-001', $definition, [
'order' => ['id' => 'ORD-001', 'total' => 99.99]
]);
$definition = [
'name' => 'Document Approval',
'version' => '1.0',
'steps' => [
[
'id' => 'submit',
'name' => 'Submit Document',
'action' => 'log',
'parameters' => [
'message' => 'Document {{ document.id }} submitted by {{ user.name }}',
'level' => 'info'
]
],
[
'id' => 'review',
'name' => 'Manager Review',
'action' => 'log',
'parameters' => [
'message' => 'Document {{ document.id }} under review',
'level' => 'info'
]
],
[
'id' => 'approve',
'name' => 'Final Approval',
'action' => 'log',
'parameters' => [
'message' => 'Document {{ document.id }} approved',
'level' => 'info'
]
]
]
];
$workflowId = start_workflow('doc-approval-001', $definition, [
'document' => ['id' => 'DOC-001'],
'user' => ['name' => 'John Doe']
]);
$definition = [
'name' => 'User Onboarding',
'version' => '1.0',
'steps' => [
[
'id' => 'welcome',
'name' => 'Send Welcome Message',
'action' => 'log',
'parameters' => [
'message' => 'Welcome {{ user.name }}! Starting onboarding...',
'level' => 'info'
]
],
[
'id' => 'setup-profile',
'name' => 'Setup User Profile',
'action' => 'log',
'parameters' => [
'message' => 'Setting up profile for {{ user.email }}',
'level' => 'info'
]
],
[
'id' => 'complete',
'name' => 'Complete Onboarding',
'action' => 'log',
'parameters' => [
'message' => 'Onboarding complete for {{ user.name }}',
'level' => 'info'
]
]
]
];
$workflowId = start_workflow('onboarding-001', $definition, [
'user' => ['name' => 'Jane Doe', 'email' => '[email protected]']
]);
<?php
namespace App\Actions;
use SolutionForest\WorkflowEngine\Contracts\WorkflowAction;
use SolutionForest\WorkflowEngine\Core\ActionResult;
use SolutionForest\WorkflowEngine\Core\WorkflowContext;
class SendEmailAction implements WorkflowAction
{
private array $config;
public function __construct(array $config = [])
{
$this->config = $config;
}
public function execute(WorkflowContext $context): ActionResult
{
$to = $this->config['to'] ?? '[email protected]';
$subject = $this->config['subject'] ?? 'Notification';
// Process template variables
$processedTo = $this->processTemplate($to, $context->getData());
$processedSubject = $this->processTemplate($subject, $context->getData());
// Send email using Laravel's Mail facade
Mail::to($processedTo)->send(new WorkflowNotification($processedSubject));
return ActionResult::success([
'email_sent' => true,
'recipient' => $processedTo
]);
}
private function processTemplate(string $template, array $data): string
{
return preg_replace_callback('/\{\{\s*([^}]+)\s*\}\}/', function ($matches) use ($data) {
$key = trim($matches[1]);
return data_get($data, $key, $matches[0]);
}, $template);
}
}
Then use it in your workflows:
$definition = [
'name' => 'Email Workflow',
'steps' => [
[
'id' => 'send-email',
'action' => SendEmailAction::class,
'parameters' => [
'to' => '{{ user.email }}',
'subject' => 'Welcome {{ user.name }}!'
]
]
]
];
Enhance your workflow actions with declarative attributes for configuration:
<?php
namespace App\Actions;
use SolutionForest\WorkflowEngine\Attributes\WorkflowStep;
use SolutionForest\WorkflowEngine\Attributes\Timeout;
use SolutionForest\WorkflowEngine\Attributes\Retry;
use SolutionForest\WorkflowEngine\Attributes\Condition;
use SolutionForest\WorkflowEngine\Contracts\WorkflowAction;
use SolutionForest\WorkflowEngine\Core\ActionResult;
use SolutionForest\WorkflowEngine\Core\WorkflowContext;
#[WorkflowStep(
id: 'send_email',
name: 'Send Welcome Email',
description: 'Sends a welcome email to new users'
)]
#[Timeout(minutes: 5)]
#[Retry(attempts: 3, backoff: 'exponential')]
#[Condition('user.email is not null')]
class SendWelcomeEmailAction implements WorkflowAction
{
public function execute(WorkflowContext $context): ActionResult
{
$user = $context->getData('user');
// Send email logic here
Mail::to($user['email'])->send(new WelcomeEmail($user));
return ActionResult::success(['email_sent' => true]);
}
}
#[WorkflowStep]
- Define step metadata (id, name, description, config)#[Timeout]
- Set execution timeouts (seconds, minutes, hours)#[Retry]
- Configure retry behavior (attempts, backoff strategy, delays)#[Condition]
- Add conditional execution rules
Create workflows with an intuitive, chainable API:
use SolutionForest\WorkflowEngine\Core\WorkflowBuilder;
$workflow = WorkflowBuilder::create('user-onboarding')
->description('Complete user onboarding process')
->addStep('welcome', SendWelcomeEmailAction::class)
->addStep('setup', SetupUserAction::class, ['template' => 'premium'])
->when('user.plan === "premium"', function($builder) {
$builder->addStep('premium-setup', PremiumSetupAction::class);
})
->email('tips-email', '{{ user.email }}', 'Getting Started Tips')
->delay(hours: 24)
->addStep('complete', CompleteOnboardingAction::class)
->build();
// Start the workflow
$workflowId = $workflow->start('user-001', [
'user' => ['email' => '[email protected]', 'plan' => 'premium']
]);
use SolutionForest\WorkflowEngine\Core\WorkflowState;
// Rich, type-safe workflow states
$state = WorkflowState::RUNNING;
echo $state->color(); // 'blue'
echo $state->icon(); // 'βΆοΈ'
echo $state->label(); // 'Running'
// Smart state transitions
if ($state->canTransitionTo(WorkflowState::COMPLETED)) {
workflow()->complete($workflowId);
}
// Use template variables in your workflow steps
$definition = [
'name' => 'User Notification',
'steps' => [
[
'id' => 'notify',
'action' => 'log',
'parameters' => [
'message' => 'Hello {{ user.name }}, your order {{ order.id }} is ready!',
'level' => 'info'
]
]
]
];
start_workflow('notification-001', $definition, [
'user' => ['name' => 'John'],
'order' => ['id' => 'ORD-123']
]);
// Log Action - Built-in logging with template support
[
'id' => 'log-step',
'action' => 'log',
'parameters' => [
'message' => 'Processing {{ item.name }}',
'level' => 'info'
]
]
// Delay Action - Built-in delays (for testing/demo)
[
'id' => 'delay-step',
'action' => 'delay',
'parameters' => [
'seconds' => 2
]
]
// Start workflows
$workflowId = start_workflow('my-workflow', $definition, $context);
// Get workflow status
$instance = get_workflow($workflowId);
echo $instance->getState()->label(); // Current state
// List all workflows
$workflows = list_workflows();
// Filter workflows by state
$runningWorkflows = list_workflows(['state' => WorkflowState::RUNNING]);
// Cancel a workflow
cancel_workflow($workflowId, 'User requested cancellation');
The package provides convenient helper functions for common operations:
// Get the workflow engine instance
$engine = workflow();
// Start a workflow
$workflowId = start_workflow('my-workflow-id', $definition, $context);
// Get a workflow instance
$instance = get_workflow('my-workflow-id');
// List all workflows
$workflows = list_workflows();
// List workflows filtered by state
$runningWorkflows = list_workflows(['state' => WorkflowState::RUNNING]);
// Cancel a workflow
cancel_workflow('my-workflow-id', 'User cancelled');
- Getting Started Guide - Complete setup and basic usage
- API Reference - Detailed API documentation
- Advanced Features - Error handling, timeouts, retries
- Best Practices - Performance tips and patterns
- Migration Guide - Upgrading from older versions
- Architecture - Technical implementation details
composer test
Please see CHANGELOG for more information on what has changed recently.
Please see CONTRIBUTING for details.
Please review our security policy on how to report security vulnerabilities.
The MIT License (MIT). Please see License File for more information.