PHPackages                             dimita/laravel-business-orchestration-engine - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Framework](/categories/framework)
4. /
5. dimita/laravel-business-orchestration-engine

ActiveLibrary[Framework](/categories/framework)

dimita/laravel-business-orchestration-engine
============================================

A Laravel library for business orchestration including Saga Pattern, Workflow, Event Sourcing, Versioning, Rule Engine, and more.

1.0.0(6mo ago)210MITPHPPHP ^8.1CI failing

Since Dec 29Pushed 6mo agoCompare

[ Source](https://github.com/DIMITA/laravel-business-orchestration-engine)[ Packagist](https://packagist.org/packages/dimita/laravel-business-orchestration-engine)[ RSS](/packages/dimita-laravel-business-orchestration-engine/feed)WikiDiscussions main Synced today

READMEChangelog (1)Dependencies (3)Versions (2)Used By (0)

Laravel Business Orchestration Engine
=====================================

[](#laravel-business-orchestration-engine)

[![Latest Stable Version](https://camo.githubusercontent.com/0502a807c758ce0675930b47e7d80632818a92a5d17685aa95c41ae675ba62df/68747470733a2f2f706f7365722e707567782e6f72672f64696d6974612f6c61726176656c2d627573696e6573732d6f726368657374726174696f6e2d656e67696e652f762f737461626c65)](https://packagist.org/packages/dimita/laravel-business-orchestration-engine)[![Total Downloads](https://camo.githubusercontent.com/3b3b0a3e30ebb9d79de7a37e83fd68bb1d2346f3de26221668e346be0fa97f62/68747470733a2f2f706f7365722e707567782e6f72672f64696d6974612f6c61726176656c2d627573696e6573732d6f726368657374726174696f6e2d656e67696e652f646f776e6c6f616473)](https://packagist.org/packages/dimita/laravel-business-orchestration-engine)[![Monthly Downloads](https://camo.githubusercontent.com/3df79142febc2d484dd1939ab939b40596e9384f5326aac2501b4e24b508d417/68747470733a2f2f706f7365722e707567782e6f72672f64696d6974612f6c61726176656c2d627573696e6573732d6f726368657374726174696f6e2d656e67696e652f642f6d6f6e74686c79)](https://packagist.org/packages/dimita/laravel-business-orchestration-engine)

A comprehensive Laravel package for business orchestration, including Saga Pattern, Workflow Management, Event Sourcing, Versioning, Rule Engine, and Dependency Management.

> **Note**: This package is based on battle-tested code patterns I've been using in production for years. I've packaged it to make these proven patterns easily reusable across projects.

![Tests](https://camo.githubusercontent.com/03d6e029397342cebb214522a2cc275f4bf4f89d99eac8d4f1d2adcd96c49a18/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f74657374732d31383825323070617373696e672d627269676874677265656e)![Coverage](https://camo.githubusercontent.com/32855e94577df9d0a30995653b17d33a5fbfdf644518f96ea0374313397d19b7/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f636f7665726167652d3130302532352d627269676874677265656e)![PHP](https://camo.githubusercontent.com/cc9cdea9aa96b40a822425e981b0a030e3371202973c7d57b74e8e99834f81dc/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f7068702d253545382e312d626c7565)![Laravel](https://camo.githubusercontent.com/3020a5644b41b0a6e42c716ae0486d76e1af9fdfb5ccbce77edf26d8c4e0554e/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c61726176656c2d25354531302e3025323025374325323025354531312e302d726564)

Requirements
------------

[](#requirements)

- **PHP**: ^8.1 or higher
- **Laravel**: ^10.0 or ^11.0
- **Database**: MySQL 5.7+, PostgreSQL 10+, or SQLite 3.8+
- **Extensions**:
    - `ext-json` - JSON support for payload serialization
    - `ext-pdo` - Database connectivity

### Optional Requirements

[](#optional-requirements)

For enhanced saga orchestration capabilities:

- **Queue Driver**: Redis, Database, or SQS for asynchronous step execution
- **Cache Driver**: Redis or Memcached for performance optimization
- **Message Queue** (optional): RabbitMQ for distributed saga coordination

Table of Contents
-----------------

[](#table-of-contents)

- [Installation](#installation)
- [Features](#features)
- [Independent vs Combined Usage](#independent-vs-combined-usage)
- [Usage Guide](#usage-guide)
    - [1. Saga Pattern](#1-saga-pattern)
    - [2. Workflow Engine](#2-workflow-engine)
    - [3. Event Sourcing](#3-event-sourcing)
    - [4. Versioning](#4-versioning)
    - [5. Rule Engine](#5-rule-engine)
    - [6. Sync Engine](#6-sync-engine)
    - [7. Dependency Engine](#7-dependency-engine)
- [Real-World Use Cases](#real-world-use-cases)
- [Architecture](#architecture)
- [Testing](#testing)

Installation
------------

[](#installation)

Install the package via Composer:

```
composer require dimita/laravel-business-orchestration-engine
```

Publish the configuration and migrations:

```
php artisan vendor:publish --provider="Dimita\\BusinessOrchestration\\BusinessOrchestrationServiceProvider"
php artisan migrate
```

Features
--------

[](#features)

### ✨ 7 Powerful Engines

[](#-7-powerful-engines)

EngineDescriptionUse Case**Saga Pattern**Distributed transactions with automatic compensationComplex business processes (orders, payments)**Workflow Engine**State machine with guards and transitionsDocument validation, approval processes**Event Sourcing**Append-only event storeAudit trail, historical state reconstruction**Versioning**Immutable model snapshotsChange history, rollback capability**Rule Engine**Business rule evaluation via ASTDynamic discounts, business validation**Sync Engine**Multi-device synchronizationOffline-first apps, mobile sync**Dependency Engine**Business constraint managementPre-delete validation, dependency graphsIndependent vs Combined Usage
-----------------------------

[](#independent-vs-combined-usage)

This package offers **maximum flexibility** - use engines independently or together based on your needs.

### Independent Usage

[](#independent-usage)

Perfect when you only need specific functionality:

```
use Dimita\BusinessOrchestration\Core\VersionEngine;
use Dimita\BusinessOrchestration\Core\RuleEngine;
use Dimita\BusinessOrchestration\Core\SyncEngine;

// Method 1: Direct class resolution
$versionEngine = app(VersionEngine::class);
$versionEngine->snapshot($model);

// Method 2: Using aliases
$ruleEngine = app('rule-engine');
$rule = $ruleEngine->rule('MyRule')
    ->when('amount', '>', 1000)
    ->then(fn($ctx) => ['discount' => 10]);

// Method 3: Dependency injection (recommended)
class OrderController
{
    public function __construct(
        private VersionEngine $version,
        private RuleEngine $rules
    ) {}

    public function process(Order $order)
    {
        $this->version->snapshot($order);
        $discountRule = $this->rules->getMatchingRules(['amount' => $order->total]);
    }
}
```

### Combined Usage

[](#combined-usage)

Use the main facade when working with multiple engines:

```
$orchestration = app('business-orchestration');

// Access any engine
$saga = $orchestration->saga();
$workflow = $orchestration->workflow();
$version = $orchestration->version();
$rules = $orchestration->rule();
$sync = $orchestration->sync();
$eventSourcing = $orchestration->eventSourcing();
$dependency = $orchestration->dependency();
```

### Available Aliases

[](#available-aliases)

```
// All engines are available via these aliases:
app('saga-engine')           // SagaEngine
app('workflow-engine')       // WorkflowEngine
app('sync-engine')           // SyncEngine
app('version-engine')        // VersionEngine
app('event-sourcing-engine') // EventSourcingEngine
app('rule-engine')           // RuleEngine
app('dependency-engine')     // DependencyEngine
```

### When to Use Each Approach

[](#when-to-use-each-approach)

ApproachBest For**Independent (Class)**Type safety, IDE autocompletion, single-engine projects**Independent (Alias)**Quick prototyping, flexibility, simpler syntax**Dependency Injection**Production code, testability, SOLID principles**Combined Facade**Complex workflows using multiple engines### Configuration for Selective Loading

[](#configuration-for-selective-loading)

Improve performance by loading only the engines you need. Edit `config/business-orchestration.php`:

```
'engines' => [
    'saga' => true,              // Enable Saga Pattern
    'workflow' => true,          // Enable Workflow Engine
    'sync' => false,             // Disable Sync Engine (not needed)
    'version' => true,           // Enable Versioning
    'event_sourcing' => false,   // Disable Event Sourcing (not needed)
    'rule' => true,              // Enable Rule Engine
    'dependency' => false,       // Disable Dependency Engine (not needed)
],
```

Or use environment variables in your `.env`:

```
# Enable only the engines you need
ORCHESTRATION_SAGA_ENABLED=true
ORCHESTRATION_WORKFLOW_ENABLED=true
ORCHESTRATION_SYNC_ENABLED=false
ORCHESTRATION_VERSION_ENABLED=true
ORCHESTRATION_EVENT_SOURCING_ENABLED=false
ORCHESTRATION_RULE_ENABLED=true
ORCHESTRATION_DEPENDENCY_ENABLED=false
```

**Benefits of selective loading:**

- Reduced memory footprint
- Faster application bootstrap
- Cleaner service container
- Only load what you actually use

**Note:** If you try to use a disabled engine, you'll get a clear error message:

```
RuntimeException: SyncEngine is not enabled. Enable it in config/business-orchestration.php

```

Usage Guide
-----------

[](#usage-guide)

### 1. Saga Pattern

[](#1-saga-pattern)

**When to use?** When you have a business transaction involving multiple services and need to rollback (compensate) on failure.

#### Simple Example - Order Processing

[](#simple-example---order-processing)

```
use Dimita\BusinessOrchestration\BusinessOrchestration;

// Define your saga steps
class ValidateOrderStep
{
    public function execute($payload)
    {
        $order = Order::find($payload['order_id']);

        if (!$order->isValid()) {
            throw new \Exception('Invalid order');
        }

        return true;
    }
}

class ChargePaymentStep
{
    public function execute($payload)
    {
        $order = Order::find($payload['order_id']);

        // Charge payment
        $payment = PaymentGateway::charge($order->total);

        if (!$payment->success) {
            throw new \Exception('Payment failed');
        }

        return true;
    }
}

class ShipOrderStep
{
    public function execute($payload)
    {
        $order = Order::find($payload['order_id']);

        // Ship the order
        ShippingService::ship($order);

        return true;
    }
}

// Start the saga synchronously
$saga = BusinessOrchestration::saga()->startSaga('OrderProcessing', [
    'validate' => ValidateOrderStep::class,
    'charge' => ChargePaymentStep::class,
    'ship' => ShipOrderStep::class,
], ['order_id' => 123]);

// If a step fails, completed steps will be automatically compensated
```

#### Advanced Compensation

[](#advanced-compensation)

Define compensation logic for each step to properly rollback changes:

```
class ChargePaymentStep
{
    public function execute($payload)
    {
        $order = Order::find($payload['order_id']);
        $payment = PaymentGateway::charge($order->total);

        if (!$payment->success) {
            throw new \Exception('Payment failed');
        }

        return true;
    }

    // Define compensation logic
    public function compensate($payload)
    {
        $order = Order::find($payload['order_id']);

        // Refund the payment
        PaymentGateway::refund($order->total);

        // Update order status
        $order->update(['status' => 'payment_refunded']);
    }
}
```

#### Asynchronous Execution

[](#asynchronous-execution)

Execute sagas asynchronously using Laravel queues:

```
// Start saga asynchronously (returns immediately)
$saga = BusinessOrchestration::saga()->startSagaAsync('OrderProcessing', [
    'validate' => ValidateOrderStep::class,
    'charge' => ChargePaymentStep::class,
    'ship' => ShipOrderStep::class,
], ['order_id' => 123]);

// Check saga status later
$status = BusinessOrchestration::saga()->getSagaStatus($saga->id);

echo $status['status']; // PENDING, RUNNING, COMPLETED, COMPENSATED
echo $status['completed_steps'] . '/' . $status['total_steps'];
```

#### Resume After Crash

[](#resume-after-crash)

```
// If your server crashes during execution, resume the saga
$sagaEngine = BusinessOrchestration::saga();
$sagaEngine->resumeSaga($sagaId);
```

#### Cancel Running Saga

[](#cancel-running-saga)

```
// Cancel a saga that's pending or running
$sagaEngine = BusinessOrchestration::saga();
$sagaEngine->cancelSaga($sagaId);
```

#### Saga Status Flow

[](#saga-status-flow)

- `PENDING` - Saga created, not started yet
- `RUNNING` - Saga currently executing
- `COMPLETED` - All steps completed successfully
- `FAILED` - A step failed (before compensation)
- `COMPENSATED` - Completed steps have been rolled back after failure
- `CANCELLED` - Saga was manually cancelled
- `COMPENSATION_FAILED` - Compensation encountered an error (step-level)

---

### 2. Workflow Engine

[](#2-workflow-engine)

**When to use?** When you need a state machine to manage transitions between different business states.

#### Simple Example - Contract Validation

[](#simple-example---contract-validation)

```
use Dimita\BusinessOrchestration\BusinessOrchestration;

$workflow = BusinessOrchestration::workflow();

// Define possible transitions
$workflow->defineTransition('submit', 'draft', 'submitted');
$workflow->defineTransition('review', 'submitted', 'in_review');
$workflow->defineTransition('approve', 'in_review', 'approved');
$workflow->defineTransition('reject', 'in_review', 'rejected');
$workflow->defineTransition('revise', 'rejected', 'draft');

// Use workflow on a model
$contract = Contract::find(1);
$builder = $workflow->for($contract);

// Check if transition is possible
if ($builder->can('approve')) {
    $builder->apply('approve');
}

// Get current state
echo $builder->getState(); // 'approved'
```

#### With Guards (Conditions)

[](#with-guards-conditions)

```
// Define transition with condition
$workflow->defineTransition(
    'auto_approve',
    'submitted',
    'approved',
    'return $context["amount"] < 1000;' // Guard expression
);

// Transition only possible if amount < 1000
```

#### Complex Workflow - Ticket Management

[](#complex-workflow---ticket-management)

```
// Draft -> Open -> In Progress -> (Resolved | Closed)
//                     ↓
//                  On Hold

$workflow->defineTransition('open', 'draft', 'open');
$workflow->defineTransition('start', 'open', 'in_progress');
$workflow->defineTransition('hold', 'in_progress', 'on_hold');
$workflow->defineTransition('resume', 'on_hold', 'in_progress');
$workflow->defineTransition('resolve', 'in_progress', 'resolved');
$workflow->defineTransition('close', 'resolved', 'closed');

$ticket = Ticket::find(1);
$builder = $workflow->for($ticket);

// Apply transitions through lifecycle
$builder->apply('open');
$builder->apply('start');
$builder->apply('hold');
$builder->apply('resume');
$builder->apply('resolve');
$builder->apply('close');
```

#### Advanced Features

[](#advanced-features)

##### Register Workflow Definition

[](#register-workflow-definition)

```
// Define a complete workflow with configuration
$workflow->registerWorkflow('order_approval', [
    'transitions' => [
        ['name' => 'submit', 'from' => 'draft', 'to' => 'pending'],
        ['name' => 'approve', 'from' => 'pending', 'to' => 'approved'],
        ['name' => 'reject', 'from' => 'pending', 'to' => 'rejected'],
    ]
]);
```

##### Event Hooks

[](#event-hooks)

```
// Execute custom logic before transitions
$workflow->beforeTransition('approve', function($instance) {
    Log::info("Approving workflow for {$instance->model_type}");
    // Send notification, update related records, etc.
});

// Execute custom logic after transitions
$workflow->afterTransition('approve', function($instance) {
    Mail::to($user)->send(new ApprovalConfirmation());
});
```

##### Get Available Transitions

[](#get-available-transitions)

```
$builder = $workflow->for($document);

// Get all transitions available from current state
$availableTransitions = $builder->getEnabledTransitions(['amount' => 500]);

// Returns: ['approve', 'reject', 'request_changes']
```

##### Check Workflow State

[](#check-workflow-state)

```
// Check if model is in specific state
if ($workflow->isInState($order, 'approved')) {
    // Process approved order
}

// Get all possible states in the workflow
$allStates = $workflow->getAllStates();
// Returns: ['draft', 'pending', 'approved', 'rejected']
```

##### Force State Change

[](#force-state-change)

```
// Override guards and force a state change (use carefully)
$builder->forceTransition('cancelled', 'Manual cancellation by admin');
```

---

### 3. Event Sourcing

[](#3-event-sourcing)

**When to use?** When you need to keep a complete history of all changes and be able to rebuild state at any point in time.

#### Simple Example - Shopping Cart

[](#simple-example---shopping-cart)

```
use Dimita\BusinessOrchestration\BusinessOrchestration;

$es = BusinessOrchestration::eventSourcing();

// Store events
$es->storeEvent('cart-123', 'CartCreated', [
    'user_id' => 456,
    'created_at' => now()
]);

$es->storeEvent('cart-123', 'ItemAdded', [
    'product_id' => 789,
    'quantity' => 2,
    'price' => 29.99
]);

$es->storeEvent('cart-123', 'ItemAdded', [
    'product_id' => 101,
    'quantity' => 1,
    'price' => 49.99
]);

$es->storeEvent('cart-123', 'CartCheckedOut', [
    'total' => 109.97,
    'payment_method' => 'credit_card'
]);

// Rebuild cart state
$cart = $es->rebuildAggregate('cart-123', function($state, $event) {
    switch ($event['event_type']) {
        case 'CartCreated':
            return [
                'user_id' => $event['payload']['user_id'],
                'items' => [],
                'total' => 0,
                'status' => 'active'
            ];

        case 'ItemAdded':
            $state['items'][] = $event['payload'];
            $state['total'] += $event['payload']['price'] * $event['payload']['quantity'];
            return $state;

        case 'CartCheckedOut':
            $state['status'] => 'checked_out';
            return $state;

        default:
            return $state;
    }
});

print_r($cart);
// Array (
//     'user_id' => 456,
//     'items' => [...],
//     'total' => 109.97,
//     'status' => 'checked_out'
// )
```

#### Retrieve All Events

[](#retrieve-all-events)

```
$events = $es->getEvents('cart-123');

foreach ($events as $event) {
    echo "{$event['event_type']} at version {$event['version']}\n";
}
```

#### Advanced Features

[](#advanced-features-1)

##### Projectors - Create Read Models

[](#projectors---create-read-models)

Projectors listen to events and create read models (projections) for querying:

```
class OrderTotalProjector
{
    // Called when MoneyAdded event is stored
    public function onMoneyAdded($event)
    {
        $account = Account::findOrFail($event->aggregate_id);
        $account->increment('balance', $event->payload['amount']);
    }

    // Called when MoneySubtracted event is stored
    public function onMoneySubtracted($event)
    {
        $account = Account::findOrFail($event->aggregate_id);
        $account->decrement('balance', $event->payload['amount']);
    }
}

// Register the projector
$es->addProjector(OrderTotalProjector::class);

// Now when you store events, projector will automatically update read models
$es->storeEvent('account-123', 'MoneyAdded', ['amount' => 100]);
```

##### Reactors - Handle Side Effects

[](#reactors---handle-side-effects)

Reactors respond to events with side effects (emails, notifications, etc.):

```
class SendEmailReactor
{
    public function onOrderPlaced($event)
    {
        // Send confirmation email
        Mail::to($event->payload['email'])->send(new OrderConfirmation($event));
    }
}

// Register the reactor
$es->addReactor(SendEmailReactor::class);

// Reactor will handle side effects asynchronously
$es->storeEvent('order-456', 'OrderPlaced', ['email' => 'customer@example.com']);
```

##### Event Replay

[](#event-replay)

Rebuild projections by replaying all events:

```
// Replay all events through projectors
$count = $es->replay();
echo "Replayed {$count} events";

// Replay only specific aggregate
$count = $es->replay('account-123');

// Replay through specific projectors only
$count = $es->replay(null, [OrderTotalProjector::class]);
```

##### Snapshots for Performance

[](#snapshots-for-performance)

Create snapshots to avoid replaying thousands of events:

```
// Create a snapshot of current state
$cart = $es->rebuildAggregate('cart-123', $reducer);
$es->snapshot('cart-123', $cart);

// Retrieve latest snapshot instead of rebuilding from all events
$cart = $es->getLatestSnapshot('cart-123');

if (!$cart) {
    // No snapshot exists, rebuild from events
    $cart = $es->rebuildAggregate('cart-123', $reducer);
}
```

##### Metadata and Event Queries

[](#metadata-and-event-queries)

```
// Store event with metadata
$es->storeEvent('order-789', 'OrderShipped',
    ['tracking_number' => 'ABC123'],
    ['user_id' => auth()->id(), 'ip_address' => request()->ip()]
);

// Get events by type
$shippedOrders = $es->getEventsByType('OrderShipped', 10);

// Get latest version number
$latestVersion = $es->getLatestVersion('order-789');

// Get events from specific version
$newEvents = $es->getEvents('order-789', $fromVersion = 5);
```

---

### 4. Versioning

[](#4-versioning)

**When to use?** When you need to keep snapshots of your models to rollback or view history.

#### Simple Example - Document Versioning

[](#simple-example---document-versioning)

```
use Dimita\BusinessOrchestration\BusinessOrchestration;

$version = BusinessOrchestration::version();

$document = Document::find(1);

// Create snapshot before modification
$version->snapshot($document);

// Modify document
$document->content = 'New content';
$document->save();

// Create another snapshot
$version->snapshot($document);

// Modify again
$document->content = 'Even newer content';
$document->save();

// Create third snapshot
$version->snapshot($document);

// View all versions
$versions = $version->getVersions($document);
// 3 versions available

// Restore to version 2
$version->restore($document, 2);

echo $document->content; // 'New content'
```

#### Use Case - Contract Audit Trail

[](#use-case---contract-audit-trail)

```
$contract = Contract::find(1);

// Create snapshot at each important change
$contract->status = 'draft';
$contract->save();
$version->snapshot($contract);

$contract->status = 'submitted';
$contract->save();
$version->snapshot($contract);

$contract->status = 'approved';
$contract->amount = 50000;
$contract->save();
$version->snapshot($contract);

// View complete history
$versions = $version->getVersions($contract);

foreach ($versions as $v) {
    echo "Version {$v['version']}: Status = {$v['snapshot']['status']}\n";
}
```

#### Advanced Versioning Features

[](#advanced-versioning-features)

##### Version Diffing

[](#version-diffing)

Compare differences between two versions:

```
// Create two versions
$document->content = 'First version';
$document->save();
$version->snapshot($document);

$document->content = 'Second version';
$document->price = 100;
$document->save();
$version->snapshot($document);

// Get differences between versions 1 and 2
$diff = $version->diff($document, 1, 2);

/*
Result:
[
    'added' => ['price' => 100],
    'removed' => [],
    'changed' => [
        'content' => [
            'old' => 'First version',
            'new' => 'Second version'
        ]
    ]
]
*/
```

##### Field Exclusion

[](#field-exclusion)

Exclude sensitive or unnecessary fields from versioning:

```
// Exclude timestamps and sensitive data
$version->excludeFields(['password', 'remember_token', 'last_login_at'])
    ->snapshot($user);

// Only critical fields are versioned
```

##### Include Hidden Fields

[](#include-hidden-fields)

Include normally hidden fields in version snapshots:

```
$user->makeHidden(['password']); // Hidden by default

// Include hidden fields in version
$version->includeHiddenFields(['password', 'api_token'])
    ->snapshot($user);
```

##### Revert to Previous Version

[](#revert-to-previous-version)

Quick revert to N versions back:

```
// Revert 1 version back
$version->revert($document);

// Revert 3 versions back
$version->revert($document, 3);

// Latest version is now the restored one
```

##### Version Metadata

[](#version-metadata)

Store contextual information with versions:

```
$version->snapshot($document, [
    'user_id' => auth()->id(),
    'reason' => 'Legal compliance update',
    'ip_address' => request()->ip()
]);
```

##### Version Utilities

[](#version-utilities)

```
// Get latest version number
$latestVersion = $version->getLatestVersion($document); // e.g., 15

// Check if specific version exists
if ($version->hasVersion($document, 5)) {
    // Version 5 exists
}

// Get total version count
$count = $version->getVersionCount($document); // e.g., 15

// Get version by hash
$versionModel = $version->getVersionByHash($document, $hash);

// Delete all versions
$deletedCount = $version->purge($document);
```

---

### 5. Rule Engine

[](#5-rule-engine)

**When to use?** When you have business rules that change frequently and you want to manage them without modifying code.

#### Simple Example - Discount Rules

[](#simple-example---discount-rules)

```
use Dimita\BusinessOrchestration\BusinessOrchestration;

$ruleEngine = BusinessOrchestration::rule();

// Create rule: If amount > 500, apply discount
$discountRule = $ruleEngine->createRule('BigOrderDiscount', [
    'type' => 'comparison',
    'left' => 'amount',
    'op' => '>',
    'right' => 500
], ['type' => 'discount', 'value' => 10]);

// Evaluate rule
$order = ['amount' => 750, 'customer_id' => 123];

if ($ruleEngine->evaluate($discountRule, $order)) {
    echo "Discount applicable!";
    // Apply discount
}
```

#### Rules with Custom Actions

[](#rules-with-custom-actions)

```
// Create rule with callable action
$rule = $ruleEngine->createRule('VIPCustomerRule', [
    'type' => 'comparison',
    'left' => 'customer_tier',
    'op' => '==',
    'right' => 'VIP'
], ['type' => 'action', 'name' => 'apply_vip_benefits']);

// Execute dynamic action
$ruleObject = new stdClass();
$ruleObject->action = function($context) {
    // Send VIP email
    Mail::to($context['email'])->send(new VIPWelcome());

    // Apply discount
    return ['discount' => 20];
};

if ($ruleEngine->evaluate($rule, $customer)) {
    $result = $ruleEngine->executeAction($ruleObject, $customer);
}
```

#### Supported Operators

[](#supported-operators)

```
// Numeric comparisons
'>' // Greater than
'',
    'right' => 18
], ['type' => 'allow']);

$rule2 = $ruleEngine->createRule('StockCheck', [
    'type' => 'comparison',
    'left' => 'stock',
    'op' => '', 1000)
    ->and('customer_type', '==', 'premium')
    ->priority(10)
    ->then(function($context) {
        // Apply free shipping
        return ['free_shipping' => true];
    });

// Rule is automatically saved and can be evaluated
$context = ['total' => 1500, 'customer_type' => 'premium'];
$result = $ruleEngine->evaluate($rule, $context); // true
```

##### Extended Operator Support

[](#extended-operator-support)

```
// All supported operators
'==' '===' '!=' '!==' // Equality
'>' '>=' '',
        'right' => ['type' => 'literal', 'value' => 500]
    ],
    'right' => [
        'type' => 'logical',
        'operator' => 'OR',
        'left' => [
            'type' => 'comparison',
            'left' => ['type' => 'variable', 'name' => 'is_member'],
            'op' => '==',
            'right' => ['type' => 'literal', 'value' => true]
        ],
        'right' => [
            'type' => 'comparison',
            'left' => ['type' => 'variable', 'name' => 'coupon_code'],
            'op' => '!=',
            'right' => ['type' => 'literal', 'value' => null]
        ]
    ]
], ['discount' => 15], 5);
```

##### Rule Macros

[](#rule-macros)

Define reusable rule patterns:

```
// Register a macro for common rule pattern
$ruleEngine->macro('premium_customer', function($ruleEngine) {
    return $ruleEngine->rule('PremiumCustomer')
        ->when('tier', '==', 'premium')
        ->and('active', '==', true);
});

// Use the macro
$premiumRule = $ruleEngine->executeMacro('premium_customer', [$ruleEngine])
    ->then(function($context) {
        return ['special_offer' => true];
    });
```

##### Custom Operators

[](#custom-operators)

Register your own operators:

```
// Register custom operator
$ruleEngine->registerOperator('divisible_by', function($left, $right, $context) {
    return $left % $right === 0;
});

// Use custom operator
$rule = $ruleEngine->createRule('BulkOrder', [
    'type' => 'comparison',
    'left' => ['type' => 'variable', 'name' => 'quantity'],
    'op' => 'divisible_by',
    'right' => ['type' => 'literal', 'value' => 12]
], ['bulk_discount' => 10]);
```

##### Rule Groups

[](#rule-groups)

Organize and evaluate rules in groups:

```
// Create multiple rules
$rule1 = $ruleEngine->rule('FreeShipping')
    ->when('total', '>', 100)
    ->then(fn($ctx) => ['free_shipping' => true]);

$rule2 = $ruleEngine->rule('TenPercentOff')
    ->when('total', '>', 500)
    ->then(fn($ctx) => ['discount' => 10]);

// Add to group
$ruleEngine->addToGroup('checkout_rules', $rule1->id);
$ruleEngine->addToGroup('checkout_rules', $rule2->id);

// Evaluate entire group (AND logic)
$passed = $ruleEngine->evaluateGroup('checkout_rules', $context, 'AND');

// Evaluate with OR logic
$passed = $ruleEngine->evaluateGroup('checkout_rules', $context, 'OR');
```

##### Priority-Based Evaluation

[](#priority-based-evaluation)

Rules with higher priority execute first:

```
// Create rules with priorities
$rule1 = $ruleEngine->rule('CriticalRule')
    ->when('status', '==', 'urgent')
    ->priority(100)
    ->then(fn($ctx) => ['priority' => 'high']);

$rule2 = $ruleEngine->rule('NormalRule')
    ->when('status', '==', 'normal')
    ->priority(10)
    ->then(fn($ctx) => ['priority' => 'normal']);

// Batch evaluate with priority ordering
$results = $ruleEngine->evaluateBatch([1, 2, 3], $context);
// Returns results sorted by priority descending
```

##### Built-in Functions

[](#built-in-functions)

Use built-in functions in rule conditions:

```
// Function-based rules
$rule = $ruleEngine->createRule('EmptyCartCheck', [
    'type' => 'function',
    'name' => 'empty',
    'args' => [['type' => 'variable', 'name' => 'cart_items']]
], ['action' => 'show_empty_message']);

// Other built-in functions:
// - empty, isset, is_null
// - count (with comparison)
```

##### Get Matching Rules

[](#get-matching-rules)

Find all rules that pass for a context:

```
$context = ['amount' => 750, 'customer_type' => 'premium'];

// Get all matching rules
$matchingRules = $ruleEngine->getMatchingRules($context);

foreach ($matchingRules as $rule) {
    echo "Matched rule: {$rule->name}\n";
    $ruleEngine->executeAction($rule, $context);
}
```

---

### 6. Sync Engine

[](#6-sync-engine)

**When to use?** To synchronize data between multiple devices (mobile app, web, etc.) with offline support.

#### Simple Example - Mobile Sync

[](#simple-example---mobile-sync)

```
use Dimita\BusinessOrchestration\BusinessOrchestration;

$sync = BusinessOrchestration::sync();

// On server, log each change
$task = Task::find(1);

$sync->logChange($task, 'INSERT', [
    'title' => 'New task',
    'status' => 'pending'
]);

// Later, modification
$task->status = 'in_progress';
$task->save();

$sync->logChange($task, 'UPDATE', [
    'status' => 'in_progress'
]);

// Another modification
$task->status = 'completed';
$task->save();

$sync->logChange($task, 'UPDATE', [
    'status' => 'completed'
]);
```

#### Retrieving Changes (Mobile Client)

[](#retrieving-changes-mobile-client)

```
// Mobile client requests changes since last sync
$lastSyncVersion = 5; // Version from last sync

$deltas = $sync->getDeltas(
    'App\\Models\\Task',
    $taskId,
    $lastSyncVersion
);

// Client receives only changes after version 5
foreach ($deltas as $delta) {
    echo "Version {$delta['version']}: {$delta['operation']}\n";
    // Apply changes locally
    applyChange($delta);
}
```

#### Offline Scenario

[](#offline-scenario)

```
// 1. Mobile app syncs
$clientVersion = 0;
$deltas = $sync->getDeltas('App\\Models\\Task', 1, $clientVersion);
// Receives all modifications

// 2. Client goes offline and makes local modifications
// Modifications stored locally

// 3. Client comes back online
// Send local modifications to server
foreach ($localChanges as $change) {
    $sync->logChange($model, $change['operation'], $change['fields']);
}

// 4. Get new changes from server
$newClientVersion = 15; // Version after upload
$newDeltas = $sync->getDeltas('App\\Models\\Task', 1, $newClientVersion);
```

#### Advanced Sync Engine Features

[](#advanced-sync-engine-features)

##### Conflict Resolution

[](#conflict-resolution)

Handle conflicts when data changes on both client and server:

```
// Synchronize with conflict detection
$sourceModel = Task::find(1);
$targetModel = Task::find(1); // Simulating different state

$result = $sync->sync($sourceModel, $targetModel);

/*
Result:
[
    'conflicts' => [
        'status' => [
            'source' => 'completed',
            'target' => 'in_progress'
        ]
    ],
    'synced_fields' => ['title', 'status', 'description']
]
*/
```

##### Conflict Strategies

[](#conflict-strategies)

Choose how conflicts are resolved:

```
// Latest wins (default)
$sync->setConflictStrategy('latest_wins')
    ->sync($source, $target);

// Source always wins
$sync->setConflictStrategy('source_wins')
    ->sync($source, $target);

// Target always wins
$sync->setConflictStrategy('target_wins')
    ->sync($source, $target);

// Merge values (for arrays and strings)
$sync->setConflictStrategy('merge')
    ->sync($source, $target);
```

##### Custom Conflict Handlers

[](#custom-conflict-handlers)

Register custom handlers for specific fields:

```
// Register custom handler for 'tags' field
$sync->registerConflictHandler('tags', function($values, $source, $target) {
    // Merge tags from both sources uniquely
    $sourceTags = $values['source'];
    $targetTags = $values['target'];

    return array_unique(array_merge($targetTags, $sourceTags));
});

// Now when syncing, 'tags' conflicts use custom handler
$sync->sync($source, $target);
```

##### Selective Field Sync

[](#selective-field-sync)

Sync only specific fields:

```
// Sync only title and description
$result = $sync->sync($source, $target, ['title', 'description']);

// Other fields are ignored
```

##### Batch Synchronization

[](#batch-synchronization)

Sync multiple model pairs at once:

```
$pairs = [
    ['source' => $task1, 'target' => $task1Remote],
    ['source' => $task2, 'target' => $task2Remote],
    ['source' => $task3, 'target' => $task3Remote],
];

$results = $sync->batchSync($pairs, ['title', 'status']);

foreach ($results as $index => $result) {
    if (isset($result['error'])) {
        echo "Pair {$index} failed: {$result['error']}\n";
    } else {
        echo "Pair {$index} synced: {$result['synced_fields']}\n";
    }
}
```

##### Sync Checkpoints

[](#sync-checkpoints)

Create named checkpoints for restore points:

```
// Create checkpoint before major changes
$sync->checkpoint($task, 'before_bulk_update');

// Make changes
$task->status = 'archived';
$task->save();

// Restore from checkpoint if needed
$sync->restoreCheckpoint($task, 'before_bulk_update');

// List all checkpoints
$checkpoints = $sync->getCheckpoints($task);
/*
[
    [
        'version' => 15,
        'name' => 'before_bulk_update',
        'created_at' => '2025-01-15 10:30:00'
    ],
    ...
]
*/
```

##### Sync Status Monitoring

[](#sync-status-monitoring)

Track synchronization activity:

```
$status = $sync->getSyncStatus($task);

/*
Result:
[
    'total_syncs' => 42,
    'last_sync' => '2025-01-15 14:30:00',
    'current_version' => 42,
    'operations' => [
        'synced' => 35,
        'checkpoint' => 7
    ]
]
*/
```

##### Model Comparison

[](#model-comparison)

Compare two models without syncing:

```
// Detect differences
$differences = $sync->compare($modelA, $modelB);

/*
Result:
[
    'title' => [
        'source' => 'Task A',
        'target' => 'Task B'
    ],
    'status' => [
        'source' => 'completed',
        'target' => 'pending'
    ]
]
*/

// Compare specific fields only
$differences = $sync->compare($modelA, $modelB, ['title', 'status']);
```

##### Apply Deltas

[](#apply-deltas)

Apply a set of changes to a model:

```
$deltas = [
    [
        'operation' => 'update',
        'changed_fields' => ['status' => 'completed', 'completed_at' => now()]
    ],
    [
        'operation' => 'update',
        'changed_fields' => ['priority' => 'high']
    ]
];

$updatedModel = $sync->applyDeltas($task, $deltas);
```

##### Metadata Tracking

[](#metadata-tracking)

Track sync context and metadata:

```
$sync->logChange($task, 'synced', ['status'], [
    'device_id' => 'mobile-123',
    'user_id' => auth()->id(),
    'app_version' => '2.1.0'
]);
```

##### Cleanup Old Logs

[](#cleanup-old-logs)

Purge old synchronization logs to save space:

```
// Keep only last 100 logs per model type
$deletedCount = $sync->purgeOldLogs('App\\Models\\Task', 100);

echo "Deleted {$deletedCount} old sync logs";
```

### 7. Dependency Engine

[](#7-dependency-engine)

**When to use?** To manage business dependencies and prevent deletions that would violate constraints.

#### Simple Example - Prevent Deletion

[](#simple-example---prevent-deletion)

```
use Dimita\BusinessOrchestration\BusinessOrchestration;

$dep = BusinessOrchestration::dependency();

// Define that Category cannot be deleted if Products exist
$dep->addDependency(
    'App\\Models\\Product',
    'App\\Models\\Category',
    'prevent_delete'
);

// Before deleting a category
$categoryId = 5;

if (!$dep->checkDeletion('App\\Models\\Category', $categoryId)) {
    return response()->json([
        'error' => 'Cannot delete category with existing products'
    ], 422);
}

// Otherwise, delete
Category::destroy($categoryId);
```

#### Complex Dependency Graph

[](#complex-dependency-graph)

```
// Define dependency graph
$dep->addDependency('App\\Models\\OrderItem', 'App\\Models\\Order', 'cascade_delete');
$dep->addDependency('App\\Models\\Order', 'App\\Models\\Customer', 'prevent_delete');
$dep->addDependency('App\\Models\\Product', 'App\\Models\\Category', 'prevent_delete');
$dep->addDependency('App\\Models\\OrderItem', 'App\\Models\\Product', 'prevent_delete');

// Get all dependencies for a model
$dependencies = $dep->getDependencies('App\\Models\\Product');

// Before deletion, check all constraints
if (!$dep->checkDeletion('App\\Models\\Customer', $customerId)) {
    throw new \Exception('Customer has active orders');
}
```

#### Dependency Rule Types

[](#dependency-rule-types)

```
// Prevent delete - Block deletion
$dep->addDependency('Child', 'Parent', 'prevent_delete');

// Cascade delete - Delete children
$dep->addDependency('Child', 'Parent', 'cascade_delete');

// Soft delete - Soft delete children
$dep->addDependency('Child', 'Parent', 'soft_delete');

// Custom rule - Custom business rule
$dep->addDependency('Child', 'Parent', 'custom_business_rule');
```

---

Real-World Use Cases
--------------------

[](#real-world-use-cases)

### E-commerce - Complete Order Process

[](#e-commerce---complete-order-process)

```
// 1. Saga for order processing
$saga = BusinessOrchestration::saga()->startSaga('OrderProcessing', [
    'validate_cart' => ValidateCartStep::class,
    'reserve_stock' => ReserveStockStep::class,
    'charge_payment' => ChargePaymentStep::class,
    'create_shipment' => CreateShipmentStep::class,
    'send_confirmation' => SendConfirmationStep::class,
], ['order_id' => $order->id]);

// 2. Workflow for order status
$workflow = BusinessOrchestration::workflow();
$workflow->defineTransition('pay', 'pending', 'paid');
$workflow->defineTransition('ship', 'paid', 'shipped');
$workflow->defineTransition('deliver', 'shipped', 'delivered');

$builder = $workflow->for($order);
$builder->apply('pay');

// 3. Event Sourcing for audit
$es = BusinessOrchestration::eventSourcing();
$es->storeEvent("order-{$order->id}", 'OrderCreated', $order->toArray());
$es->storeEvent("order-{$order->id}", 'PaymentReceived', $payment->toArray());
$es->storeEvent("order-{$order->id}", 'OrderShipped', $shipment->toArray());

// 4. Versioning for order history
$version = BusinessOrchestration::version();
$version->snapshot($order); // At each important step

// 5. Business rules for discounts
$rule = BusinessOrchestration::rule()->createRule('FirstOrderDiscount', [
    'type' => 'comparison',
    'left' => 'order_count',
    'op' => '==',
    'right' => 1
], ['discount' => 15]);

// 6. Sync for customer mobile app
$sync = BusinessOrchestration::sync();
$sync->logChange($order, 'UPDATE', ['status' => 'shipped']);

// 7. Dependencies to prevent invalid deletions
$dep = BusinessOrchestration::dependency();
$dep->addDependency('App\\Models\\OrderItem', 'App\\Models\\Order', 'cascade_delete');
```

### SaaS - Subscription Management

[](#saas---subscription-management)

```
// Subscription workflow
$workflow = BusinessOrchestration::workflow();
$workflow->defineTransition('activate', 'trial', 'active');
$workflow->defineTransition('cancel', 'active', 'cancelled');
$workflow->defineTransition('suspend', 'active', 'suspended');
$workflow->defineTransition('reactivate', 'suspended', 'active');

// Event sourcing for billing history
$es = BusinessOrchestration::eventSourcing();
$es->storeEvent("subscription-{$sub->id}", 'SubscriptionStarted', [...]);
$es->storeEvent("subscription-{$sub->id}", 'PaymentProcessed', [...]);
$es->storeEvent("subscription-{$sub->id}", 'UpgradedToPro', [...]);

// Rules for automatic upgrades
$upgradeRule = $ruleEngine->createRule('AutoUpgrade', [
    'type' => 'comparison',
    'left' => 'usage',
    'op' => '>',
    'right' => 80
], ['action' => 'suggest_upgrade']);
```

Architecture
------------

[](#architecture)

### Package Structure

[](#package-structure)

```
src/
├── Core/                    # Main engines
│   ├── SagaEngine.php
│   ├── WorkflowEngine.php
│   ├── EventSourcingEngine.php
│   ├── VersionEngine.php
│   ├── RuleEngine.php
│   ├── SyncEngine.php
│   └── DependencyEngine.php
├── Models/                  # Eloquent models
│   ├── Saga.php
│   ├── SagaStep.php
│   ├── WorkflowInstance.php
│   ├── WorkflowTransition.php
│   ├── EventStore.php
│   ├── ModelVersion.php
│   ├── SyncLog.php
│   ├── Rule.php
│   └── Dependency.php
├── Drivers/                 # Multi-driver support
│   ├── DatabaseDriver.php
│   ├── RedisDriver.php
│   └── QueueDriver.php
└── BusinessOrchestration.php # Main facade

```

### Design Principles

[](#design-principles)

- **Human-friendly logic**: Clear and intuitive API
- **Production-ready**: Error handling, compensation, crash recovery
- **Persistent**: Everything saved to database
- **Extensible**: Multi-driver support (DB, Redis, Queue)
- **Testable**: 122 tests, 100% coverage

### Architecture Diagrams

[](#architecture-diagrams)

#### 1. Saga Pattern Flow

[](#1-saga-pattern-flow)

```
┌─────────────────────────────────────────────────────────────────┐
│                    SAGA ORCHESTRATION                            │
└─────────────────────────────────────────────────────────────────┘

Success Flow:
┌─────────┐    ┌─────────┐    ┌─────────┐    ┌─────────┐
│ PENDING │ -> │ RUNNING │ -> │ RUNNING │ -> │COMPLETED│
│         │    │ Step 1  │    │ Step 2  │    │         │
└─────────┘    └─────────┘    └─────────┘    └─────────┘

Failure + Compensation Flow:
┌─────────┐    ┌─────────┐    ┌─────────┐    ┌──────────────┐
│ PENDING │ -> │ RUNNING │ -> │ FAILED  │ -> │ COMPENSATED  │
│         │    │ Step 1✓ │    │ Step 2✗ │    │ Rollback 1✓  │
└─────────┘    └─────────┘    └─────────┘    └──────────────┘

Database Schema:
sagas                           saga_steps
├── id                          ├── id
├── name                        ├── saga_id (FK)
├── status                      ├── step_name
├── payload (JSON)              ├── status
├── current_step                ├── executed_at
└── timestamps                  ├── compensated_at
                                ├── error
                                └── timestamps

```

#### 2. Workflow State Machine

[](#2-workflow-state-machine)

```
┌─────────────────────────────────────────────────────────────────┐
│                    WORKFLOW ENGINE                               │
└─────────────────────────────────────────────────────────────────┘

State Transition Graph:
                    submit
    ┌─────────┐ ─────────> ┌───────────┐
    │  draft  │            │ submitted │
    └─────────┘

┌──────────────┐  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐
│OrderCreated  │─>│PaymentCharged│─>│ItemsShipped  │─>│OrderDelivered│
│ v1           │  │ v2           │  │ v3           │  │ v4           │
└──────────────┘  └──────────────┘  └──────────────┘  └──────────────┘

Aggregate Rebuild:
Initial State: {}
  + OrderCreated     -> {status: 'pending', total: 100}
  + PaymentCharged   -> {status: 'paid', total: 100, payment_id: 123}
  + ItemsShipped     -> {status: 'shipped', tracking: 'ABC123'}
  + OrderDelivered   -> {status: 'delivered', delivered_at: '2024-01-01'}

Database Schema:
event_store
├── id
├── aggregate_id
├── event_type
├── event_data (JSON)
├── version
├── metadata (JSON)
└── created_at

```

#### 4. Version Control System

[](#4-version-control-system)

```
┌─────────────────────────────────────────────────────────────────┐
│                    VERSIONING ENGINE                             │
└─────────────────────────────────────────────────────────────────┘

Snapshot Timeline:
Model State: {name: "Doc1", status: "draft"}
     │
     v  snapshot()
Version 1: {name: "Doc1", status: "draft", hash: "abc123"}
     │
     │  model.update({status: "published"})
     v  snapshot()
Version 2: {name: "Doc1", status: "published", hash: "def456"}
     │
     │  model.update({name: "Doc1-Updated"})
     v  snapshot()
Version 3: {name: "Doc1-Updated", status: "published", hash: "ghi789"}
     │
     │  restore(version: 1)
     v
Restored: {name: "Doc1", status: "draft"}

Database Schema:
model_versions
├── id
├── model_type
├── model_id
├── version
├── snapshot_data (JSON)
├── hash
└── created_at

```

#### 5. Rule Engine AST Evaluation

[](#5-rule-engine-ast-evaluation)

```
┌─────────────────────────────────────────────────────────────────┐
│                    RULE ENGINE                                   │
└─────────────────────────────────────────────────────────────────┘

Rule Definition (AST):
Business Rule: "If order total > 100 AND customer_type == 'VIP', apply 20% discount"

AST Structure:
{
  type: "logical",
  operator: "AND",
  left: {
    type: "comparison",
    left: "order_total",
    op: ">",
    right: 100
  },
  right: {
    type: "comparison",
    left: "customer_type",
    op: "==",
    right: "VIP"
  }
}

Evaluation Flow:
Context: {order_total: 150, customer_type: "VIP"}
  ├─> Evaluate left: 150 > 100 = true
  ├─> Evaluate right: "VIP" == "VIP" = true
  └─> AND(true, true) = true -> Execute action

Database Schema:
rules
├── id
├── name
├── condition_ast (JSON)
├── action (JSON)
└── timestamps

```

#### 6. Sync Engine Delta Synchronization

[](#6-sync-engine-delta-synchronization)

```
┌─────────────────────────────────────────────────────────────────┐
│                    SYNC ENGINE                                   │
└─────────────────────────────────────────────────────────────────┘

Multi-Device Sync:
Server                          Client A                    Client B
  │                                │                           │
  │ v1: INSERT {name: "Item1"}     │                           │
  ├────────────────────────────────>│ Sync from v0             │
  │                                │ Receives: [v1]            │
  │                                │                           │
  │ v2: UPDATE {status: "active"}  │                           │
  ├────────────────────────────────>│ Sync from v1             │
  │                                │ Receives: [v2]            │
  │                                │                           │
  │                                │                           ├─> Sync from v0
  │                                │                           │   Receives: [v1, v2]
  │ v3: UPDATE {price: 99}         │                           │
  ├────────────────────────────────>│ Sync from v2             │
  │                                │ Receives: [v3]            │
  ├───────────────────────────────────────────────────────────>│ Sync from v2
  │                                │                           │ Receives: [v3]

Database Schema:
sync_log
├── id
├── model_type
├── model_id
├── operation (INSERT|UPDATE|DELETE)
├── version
├── changed_fields (JSON)
└── created_at

```

#### 7. Dependency Graph System

[](#7-dependency-graph-system)

```
┌─────────────────────────────────────────────────────────────────┐
│                    DEPENDENCY ENGINE                             │
└─────────────────────────────────────────────────────────────────┘

Dependency Graph:
┌──────────┐
│  User    │
└────┬─────┘
     │ has_many (dependency: prevent_delete)
     ├────────────┬────────────┬────────────┐
     v            v            v            v
┌─────────┐  ┌────────┐  ┌─────────┐  ┌─────────┐
│ Order   │  │Profile │  │Comments │  │Payments │
└─────────┘  └────────┘  └─────────┘  └─────────┘

Deletion Check Flow:
canDelete(User #123)?
  ├─> Check Orders: 5 orders exist -> BLOCKED
  ├─> Check Profile: 1 profile exists -> BLOCKED
  ├─> Check Comments: 12 comments exist -> BLOCKED
  └─> Check Payments: 3 payments exist -> BLOCKED

Result: Cannot delete User #123 (has dependencies)

Database Schema:
dependencies
├── id
├── source_model
├── target_model
├── dependency_type
├── created_at
└── updated_at

```

#### Overall System Architecture

[](#overall-system-architecture)

```
┌─────────────────────────────────────────────────────────────────┐
│                     Application Layer                            │
│  (Controllers, Services, Commands)                               │
└──────────────────────┬───────────────────────────────────────────┘
                       │
                       v
┌─────────────────────────────────────────────────────────────────┐
│              BusinessOrchestration Facade                        │
│  ->saga() ->workflow() ->eventSourcing() ->version()             │
│  ->rule() ->sync() ->dependency()                                │
└──────────────────────┬───────────────────────────────────────────┘
                       │
       ┌───────────────┼───────────────┐
       v               v               v
┌────────────┐  ┌────────────┐  ┌────────────┐
│   Saga     │  │  Workflow  │  │   Event    │
│  Engine    │  │  Engine    │  │  Sourcing  │
└─────┬──────┘  └─────┬──────┘  └─────┬──────┘
      │               │               │
┌────────────┐  ┌────────────┐  ┌────────────┐
│  Version   │  │    Rule    │  │    Sync    │
│  Engine    │  │  Engine    │  │   Engine   │
└─────┬──────┘  └─────┬──────┘  └─────┬──────┘
      │               │               │
      └───────────────┼───────────────┘
                      v
┌─────────────────────────────────────────────────────────────────┐
│                    Driver Layer                                  │
│  DatabaseDriver │ RedisDriver │ QueueDriver                      │
└──────────────────────┬───────────────────────────────────────────┘
                       │
                       v
┌─────────────────────────────────────────────────────────────────┐
│                 Persistence Layer                                │
│  MySQL │ PostgreSQL │ SQLite │ Redis │ RabbitMQ                 │
└─────────────────────────────────────────────────────────────────┘

```

Testing
-------

[](#testing)

The package includes 122 tests covering all use cases:

```
# Run all tests
vendor/bin/phpunit

# With details
vendor/bin/phpunit --testdox

# Result
OK (122 tests, 252 assertions)
```

### Test Coverage by Engine

[](#test-coverage-by-engine)

- **SagaEngine**: 16 tests (compensation, resume, states)
- **WorkflowEngine**: 16 tests (transitions, guards, states)
- **RuleEngine**: 18 tests (evaluation, AST, actions)
- **DependencyEngine**: 17 tests (graphs, constraints)
- **EventSourcingEngine**: 16 tests (events, rebuild, versioning)
- **VersionEngine**: 19 tests (snapshots, restore, audit)
- **SyncEngine**: 20 tests (deltas, offline, incremental)

Configuration
-------------

[](#configuration)

Publish the configuration file:

```
php artisan vendor:publish --provider="Dimita\\BusinessOrchestration\\BusinessOrchestrationServiceProvider"
```

Available in `config/business-orchestration.php`:

```
return [
    /*
    |--------------------------------------------------------------------------
    | Enabled Engines
    |--------------------------------------------------------------------------
    |
    | Configure which engines should be loaded and available in your application.
    | Set to false to disable an engine completely and improve performance.
    | By default, all engines are enabled.
    |
    */
    'engines' => [
        'saga' => env('ORCHESTRATION_SAGA_ENABLED', true),
        'workflow' => env('ORCHESTRATION_WORKFLOW_ENABLED', true),
        'sync' => env('ORCHESTRATION_SYNC_ENABLED', true),
        'version' => env('ORCHESTRATION_VERSION_ENABLED', true),
        'event_sourcing' => env('ORCHESTRATION_EVENT_SOURCING_ENABLED', true),
        'rule' => env('ORCHESTRATION_RULE_ENABLED', true),
        'dependency' => env('ORCHESTRATION_DEPENDENCY_ENABLED', true),
    ],

    /*
    |--------------------------------------------------------------------------
    | Storage Drivers
    |--------------------------------------------------------------------------
    |
    | Configure how orchestration data is stored and retrieved.
    | Supports: database, redis, queue
    |
    */
    'drivers' => [
        'default' => env('BUSINESS_ORCHESTRATION_DRIVER', 'database'),

        'database' => [
            'connection' => env('DB_CONNECTION', 'mysql'),
        ],

        'redis' => [
            'connection' => env('REDIS_CONNECTION', 'default'),
        ],

        'queue' => [
            'connection' => env('QUEUE_CONNECTION', 'sync'),
        ],
    ],
];
```

### Configuration Examples

[](#configuration-examples)

**Scenario 1: E-commerce application (needs Saga, Workflow, Versioning)**

```
'engines' => [
    'saga' => true,              // For order processing
    'workflow' => true,          // For order status transitions
    'sync' => false,             // No mobile sync needed
    'version' => true,           // For order audit trail
    'event_sourcing' => false,   // Not needed
    'rule' => true,              // For discount rules
    'dependency' => false,       // Not needed
],
```

**Scenario 2: Mobile-first app with offline support**

```
'engines' => [
    'saga' => false,
    'workflow' => false,
    'sync' => true,              // Critical for mobile sync
    'version' => true,           // Version tracking
    'event_sourcing' => true,    // Event history
    'rule' => false,
    'dependency' => false,
],
```

**Scenario 3: Enterprise workflow system**

```
'engines' => [
    'saga' => true,              // Multi-step processes
    'workflow' => true,          // State machines
    'sync' => false,
    'version' => true,           // Document versioning
    'event_sourcing' => true,    // Complete audit trail
    'rule' => true,              // Business rules
    'dependency' => true,        // Constraint management
],
```

Support
-------

[](#support)

- **Documentation**: This README
- **Issues**: [GitHub Issues](https://github.com/dimita/laravel-business-orchestration-engine/issues)
- **Tests**: 100% coverage, 122 tests

License
-------

[](#license)

MIT License - Free for commercial and open-source projects.

Changelog
---------

[](#changelog)

### v1.0.0 (2025)

[](#v100-2025)

- ✅ Saga Pattern with automatic compensation
- ✅ Workflow Engine with guards
- ✅ Event Sourcing with rebuild
- ✅ Versioning with snapshots
- ✅ Rule Engine with AST
- ✅ Sync Engine for multi-device
- ✅ Dependency Engine for business constraints
- ✅ 122 tests with 100% coverage
- ✅ Production-ready with complete error handling

---

**Made with ❤️ for the Laravel community**

*Based on production-tested patterns I've refined over years of building enterprise applications.*

###  Health Score

34

—

LowBetter than 75% of packages

Maintenance68

Regular maintenance activity

Popularity8

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity43

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 97.9% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Unknown

Total

1

Last Release

186d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/34888823?v=4)[HOUEDANOU wilfried](/maintainers/DIMITA)[@DIMITA](https://github.com/DIMITA)

---

Top Contributors

[![dimi94](https://avatars.githubusercontent.com/u/41617911?v=4)](https://github.com/dimi94 "dimi94 (47 commits)")[![DIMITA](https://avatars.githubusercontent.com/u/34888823?v=4)](https://github.com/DIMITA "DIMITA (1 commits)")

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/dimita-laravel-business-orchestration-engine/health.svg)

```
[![Health](https://phpackages.com/badges/dimita-laravel-business-orchestration-engine/health.svg)](https://phpackages.com/packages/dimita-laravel-business-orchestration-engine)
```

###  Alternatives

[laravel/octane

Supercharge your Laravel application's performance.

4.0k26.6M223](/packages/laravel-octane)[unopim/unopim

UnoPim Laravel PIM

10.5k2.4k](/packages/unopim-unopim)[code16/sharp

Laravel Content Management Framework

79164.7k8](/packages/code16-sharp)[ecotone/laravel

Ecotone for Laravel — CQRS, Event Sourcing, Sagas, Durable Workflows, and Outbox on top of Laravel Queue, via PHP attributes.

21318.6k3](/packages/ecotone-laravel)[codewithdennis/larament

Larament is a time-saving starter kit to quickly launch Laravel 13.x projects. It includes FilamentPHP 5.x pre-installed and configured, along with additional tools and features to streamline your development workflow.

3891.8k](/packages/codewithdennis-larament)[r2luna/brain

Brain: A process-driven architecture alternative for your Laravel Application.

6338.7k1](/packages/r2luna-brain)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
