· 3 min read · updated
Symfony Workflow Component and the Saga Pattern
Series: Messaging & Distributed Transactions · part 4
- 1. RabbitMQ: Exchanges, Queues, Topic Routing and Policies
- 2. Building a High Availability RabbitMQ Cluster
- 3. The Saga Pattern: Distributed Transactions in TypeScript
- 4. Symfony Workflow Component and the Saga Pattern

Introduction#
In modern software development, managing complex business processes can be a daunting task. Whether handling order processing, document approval, or project management, these processes often involve multiple steps and transitions. Symfony’s Workflow Component, paired with the Saga Pattern, offers an elegant solution to this challenge.
In this post, we’ll explore the Symfony Workflow Component, dive into the Saga Pattern, and showcase a full integration example with complete code snippets.
Part 1: Understanding Symfony’s Workflow Component#
What is the Workflow Component?#
The Workflow Component is a Symfony extension that models complex processes as a directed graph. It’s designed to handle stateful entities and guide them through a series of states or transitions.
Configuration Example#
Here’s how you might define a simple order process workflow in YAML:
framework:
workflows:
order_process:
marking_store:
type: 'method'
property: 'currentStatus'
supports:
- App\Entity\Order
places:
- start
- pending
- approved
- shipped
- completed
transitions:
to_pending:
from: start
to: pending
# Additional transitionsUsing the Workflow Component#
You can manage your objects by applying transitions. Here’s a PHP example:
$workflow = $this->get('workflow.order_process');
if ($workflow->can($order, 'to_pending')) {
$workflow->apply($order, 'to_pending');
}Part 2: Connecting with the Saga Pattern#
What is the Saga Pattern?#
The Saga Pattern is an architectural pattern that helps manage long-running, complex processes by breaking them into local transactions, each with a corresponding compensation action.
How Does It Relate to Symfony’s Workflow?#
You can view the transitions in Symfony’s Workflow as individual steps within a Saga. The Workflow Component helps you define and manage these steps, while the Saga Pattern ensures consistency across different parts of your system.
Integration Example#
Consider an e-commerce application where an order goes through several stages, from creation to shipment. This process could be represented using Symfony’s Workflow Component and managed as a Saga.
- Define the Order Entity
namespace App\Entity;
class Order {
private string $currentStatus;
public function getCurrentStatus(): string {
return $this->currentStatus;
}
public function setCurrentStatus(string $status): void {
$this->currentStatus = $status;
}
}- Implement Saga Steps
use Symfony\Component\Workflow\Workflow;
class OrderSagaStep {
private $workflow;
public function __construct(Workflow $workflow) {
$this->workflow = $workflow;
}
public function execute(Order $order) {
if ($this->workflow->can($order, 'to_pending')) {
$this->workflow->apply($order, 'to_pending');
}
}
public function compensate(Order $order) {
// Compensation logic
}
}
// Additional steps here- Orchestrate the Saga
class OrderSagaOrchestrator {
private array $steps;
public function __construct(array $steps) {
$this->steps = $steps;
}
public function execute(Order $order) {
foreach ($this->steps as $step) {
$step->execute($order);
}
}
public function compensate(Order $order) {
foreach (array_reverse($this->steps) as $step) {
$step->compensate($order);
}
}
}- Execute the Order Saga
$order = new Order();
$sagaSteps = [new OrderSagaStep($workflow), /* more steps */ ];
$saga = new OrderSagaOrchestrator($sagaSteps);
try {
$saga->execute($order);
} catch (\Exception $e) {
$saga->compensate($order);
}Conclusion#
Combining Symfony’s Workflow Component with the Saga Pattern offers a powerful way to model and manage complex business processes. By utilizing these tools, developers can create robust, scalable systems that can easily adapt to changing business requirements.
Whether you’re building an e-commerce platform, managing internal workflows, or crafting any application with stateful entities, this combination of Symfony and Saga provides a flexible and maintainable solution. Explore more architectural patterns in our previous posts, and unlock the potential of these tools in your next project!
$ related posts
15 min readNEW
The Read Side Does Not Go Through the Aggregate
CQRS read models in Symfony 8: a read port the domain does not own, a query bus that returns a value, and when a projection table earns its place. Part 3.
DDD, CQRS and Hexagonal Architecture in Symfony 8 · part 3#cqrs#ddd#hexagonal-architecture#symfony#php#postgresql#doctrine18 min readNEW
The Application Layer, the Transaction, and a Working API
Application layer in Symfony 8: use cases on a Messenger command bus, the transaction boundary in config, optimistic locking and RFC 9457 errors. Part 2.
DDD, CQRS and Hexagonal Architecture in Symfony 8 · part 2#ddd#hexagonal-architecture#symfony#php#cqrs#messenger#software-architecture15 min readNEW
The Domain Model, and the Only Rule That Matters
DDD domain model in PHP 8.5 and Symfony 8: keep the container out of the domain, and choose Doctrine ORM or DBAL with the costs on the table. Series part 1.
DDD, CQRS and Hexagonal Architecture in Symfony 8 · part 1#ddd#hexagonal-architecture#symfony#php#doctrine#software-architecture