Saga

<?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";
}