solution-forest/workflow-engine-laravel
Installation
composer require solution-forest/workflow-engine-laravel
php artisan vendor:publish --provider="SolutionForest\WorkflowEngine\Providers\WorkflowEngineServiceProvider"
Define a Workflow
Create a workflow enum (app/Enums/ExampleWorkflow.php):
namespace App\Enums;
use SolutionForest\WorkflowEngine\Attributes\Workflow;
use SolutionForest\WorkflowEngine\Workflow\WorkflowDefinition;
#[Workflow]
enum ExampleWorkflow: string
{
case INITIALIZE = 'initialize';
case PROCESS = 'process';
case FINALIZE = 'finalize';
public function definition(): WorkflowDefinition
{
return WorkflowDefinition::create()
->from(self::INITIALIZE)
->to(self::PROCESS)
->to(self::FINALIZE);
}
}
First Use Case Trigger a workflow in a controller:
use SolutionForest\WorkflowEngine\Facades\WorkflowEngine;
public function startWorkflow()
{
$workflow = WorkflowEngine::create(ExampleWorkflow::INITIALIZE);
$workflow->execute();
}
config/workflow-engine.php for core settings.php artisan workflow:list to inspect registered workflows.SolutionForest\WorkflowEngine\Attributes for decorators like #[WorkflowStep].Step-Based Execution Define steps with attributes:
#[WorkflowStep(ExampleWorkflow::PROCESS)]
public function handleProcessing(WorkflowContext $context)
{
// Business logic here
$context->transitionTo(ExampleWorkflow::FINALIZE);
}
Event-Driven Workflows Listen to workflow events:
WorkflowEngine::on('workflow.started', fn ($event) => {
Log::info("Workflow started: {$event->workflow->name}");
});
Retry & Timeout Policies Apply retry logic to steps:
#[Retry(maxAttempts: 3, delay: 1000)]
#[Timeout(seconds: 30)]
#[WorkflowStep(ExampleWorkflow::PROCESS)]
public function handleProcessing(WorkflowContext $context)
{
// ...
}
Eloquent Models: Attach workflows to models via traits:
use SolutionForest\WorkflowEngine\Eloquent\HasWorkflows;
class Order extends Model
{
use HasWorkflows;
protected $workflowClass = ExampleWorkflow::class;
}
Queue Jobs: Offload workflow steps to queues:
WorkflowEngine::create(ExampleWorkflow::INITIALIZE)
->queue()
->execute();
Testing: Use the WorkflowTestCase base class:
use SolutionForest\WorkflowEngine\Testing\WorkflowTestCase;
class ExampleWorkflowTest extends WorkflowTestCase
{
public function test_workflow_execution()
{
$this->assertWorkflowExecutes(ExampleWorkflow::INITIALIZE);
}
}
Attribute Registration
config/workflow-engine.php under workflows.workflows array:
'workflows' => [
ExampleWorkflow::class,
],
Type Safety Mismatches
php.ini and use IDE autocompletion for enums.Circular Dependencies
A → B → A) will throw WorkflowException.$definition = ExampleWorkflow::INITIALIZE->definition();
$definition->validate();
Context Serialization
JsonSerializable or cast complex objects to arrays.config/workflow-engine.php:
'debug' => env('WORKFLOW_DEBUG', false),
php artisan workflow:inspect <workflow_id> to debug stuck workflows.#[WorkflowStep(log: true)] to log step execution details.Custom Step Handlers
Extend the WorkflowStepHandler interface to add custom logic:
class CustomStepHandler implements WorkflowStepHandler
{
public function handle(WorkflowContext $context, string $step): void
{
// Custom logic
}
}
Middleware Add middleware to workflow execution:
WorkflowEngine::middleware(function ($workflow, $next) {
// Pre-execution logic
return $next($workflow);
});
Storage Backends
Override the default database storage by binding a custom WorkflowRepository:
$this->app->bind(WorkflowRepository::class, function ($app) {
return new CustomWorkflowRepository();
});
WorkflowEngine::batch() to process multiple workflows efficiently.WorkflowEngine::cacheDefinitions(true);
How can I help you explore Laravel packages today?