<?php
// Event class to represent different steps in the saga
class SagaEvent { private string $eventType; private array $data; public function __construct(string $eventType, array $data) { $this->eventType = $eventType;
$this->data = $data;
}
public function getEventType(): string {
return $this->eventType;
}
public function getData(): array {
return $this->data;
}
}
// Interface for saga steps
interface SagaStep {
public function execute(array $data): bool;
public function compensate(array $data): void;
}
// Concrete implementation of Order service step
class OrderStep implements SagaStep {
public function execute(array $data): bool {
try {
// Create order in database
echo "Creating order: " . $data['orderId'] . "\n";
// Simulate database operation
return true;
} catch (Exception $e) {
return false;
}
}
public function compensate(array $data): void {
echo "Cancelling order: " . $data['orderId'] . "\n";
// Rollback order creation
}
}
// Payment service step
class PaymentStep implements SagaStep {
public function execute(array $data): bool {
try {
// Process payment
echo "Processing payment for order: " . $data['orderId'] .
" Amount: $" . $data['amount'] . "\n";
// Simulate payment processing
return true;
} catch (Exception $e) {
return false;
}
}
public function compensate(array $data): void {
echo "Refunding payment for order: " . $data['orderId'] .
" Amount: $" . $data['amount'] . "\n";
// Reverse payment
}
}
// Inventory service step
class InventoryStep implements SagaStep {
public function execute(array $data): bool {
try {
// Reserve inventory
echo "Reserving inventory for order: " . $data['orderId'] .
" Quantity: " . $data['quantity'] . "\n";
// Simulate inventory reservation
return true;
} catch (Exception $e) {
return false;
}
}
public function compensate(array $data): void {
echo "Releasing inventory for order: " . $data['orderId'] .
" Quantity: " . $data['quantity'] . "\n";
// Release reserved inventory
}
}
// Saga orchestrator to manage the transaction
class OrderSagaOrchestrator {
private array $steps;
private array $completedSteps;
public function __construct() {
$this->steps = [
new OrderStep(),
new PaymentStep(),
new InventoryStep()
];
$this->completedSteps = [];
}
public function execute(array $data): bool {
// Execute each step in sequence
foreach ($this->steps as $step) {
if (!$step->execute($data)) {
// If any step fails, compensate all completed steps
$this->compensate($data);
return false;
}
$this->completedSteps[] = $step;
}
return true;
}
private function compensate(array $data): void {
// Compensate completed steps in reverse order
foreach (array_reverse($this->completedSteps) as $step) {
$step->compensate($data);
}
}
}
// Example usage
$orderData = [
'orderId' => 'ORD-123',
'amount' => 99.99,
'quantity' => 2
];
$saga = new OrderSagaOrchestrator();
$success = $saga->execute($orderData);
if ($success) {
echo "Order process completed successfully!\n";
} else {
echo "Order process failed and was rolled back.\n";
}