Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Saga Symfony Laravel Package

brzuchal/saga-symfony

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation

    composer require brzuchal/saga-symfony
    

    Ensure your project uses Symfony 5.4+ (or Laravel with Symfony components).

  2. Register the Bundle Add to config/bundles.php (Symfony) or manually bootstrap in Laravel:

    // config/app.php (Laravel)
    'providers' => [
        // ...
        Brzuchal\SagaSymfony\SagaBundle::class,
    ],
    
  3. First Use Case: Basic Saga Define a saga class (Symfony-style) and register it as a service:

    // src/Saga/ExampleSaga.php
    namespace App\Saga;
    
    use Brzuchal\SagaSymfony\Saga\Saga;
    
    class ExampleSaga extends Saga
    {
        public function doSomething(): void
        {
            // Business logic here
        }
    }
    

    Trigger via command or event listener:

    $saga = $container->get(ExampleSaga::class);
    $saga->execute();
    

Implementation Patterns

Workflow: Event-Driven Sagas

  1. Event Listeners Attach sagas to Symfony events (or Laravel events via EventDispatcher):

    // src/EventListener/SagaListener.php
    use Brzuchal\SagaSymfony\Saga\SagaInterface;
    
    class SagaListener
    {
        public function __construct(private SagaInterface $saga) {}
    
        public function onOrderCreated(): void
        {
            $this->saga->execute();
        }
    }
    
  2. Command-Based Sagas Use Symfony’s Command component to manually trigger sagas:

    // src/Command/RunSagaCommand.php
    namespace App\Command;
    
    use Brzuchal\SagaSymfony\Saga\SagaInterface;
    use Symfony\Component\Console\Command\Command;
    use Symfony\Component\Console\Input\InputInterface;
    use Symfony\Component\Console\Output\OutputInterface;
    
    class RunSagaCommand extends Command
    {
        protected static $defaultName = 'app:run-saga';
    
        public function __construct(private SagaInterface $saga) {}
    
        protected function execute(InputInterface $input, OutputInterface $output): int
        {
            $this->saga->execute();
            return Command::SUCCESS;
        }
    }
    
  3. Dependency Injection Inject services (e.g., repositories, clients) into sagas:

    // src/Saga/PaymentSaga.php
    class PaymentSaga extends Saga
    {
        public function __construct(
            private PaymentRepository $repository,
            private PaymentGateway $gateway
        ) {}
    
        public function processPayment(): void
        {
            $this->repository->find(...);
            $this->gateway->charge(...);
        }
    }
    

Integration Tips

  • Laravel-Specific: Use Symfony\Bridge\Laravel\Container to bridge services.
  • Transaction Management: Combine with Laravel’s DB::transaction() for atomicity.
  • Logging: Decorate sagas with a logger (e.g., Monolog) for observability.

Gotchas and Tips

Pitfalls

  1. No Built-in Persistence The package lacks a default storage layer. Implement your own (e.g., Doctrine, Laravel Eloquent) to track saga state:

    // Example: Store saga state in DB
    class SagaRepository {
        public function save(Saga $saga): void {
            // Custom logic
        }
    }
    
  2. Symfony-Centric Design Assumes Symfony’s EventDispatcher and Container. In Laravel, wrap dependencies manually or use a bridge like symfony/bridge-laravel.

  3. Error Handling Sagas throw exceptions by default. Implement retry logic (e.g., with symfony/messenger) or compensating transactions.

Debugging

  • State Inspection: Add debug methods to sagas to dump current state:
    public function debugState(): array {
        return ['step' => $this->currentStep, 'data' => $this->data];
    }
    
  • Logging: Use monolog to log saga execution:
    $this->logger->info('Saga executed', ['saga' => get_class($this)]);
    

Extension Points

  1. Custom Steps Extend Saga to add lifecycle hooks:

    abstract class CustomSaga extends Saga {
        protected function beforeExecute(): void { /* ... */ }
        protected function afterExecute(): void { /* ... */ }
    }
    
  2. Middleware Use Symfony middleware to intercept saga execution:

    // src/Saga/Middleware/LoggingMiddleware.php
    use Brzuchal\SagaSymfony\Saga\SagaInterface;
    
    class LoggingMiddleware implements SagaMiddlewareInterface {
        public function handle(SagaInterface $saga, callable $next): void {
            $this->logger->info('Saga started');
            $next();
            $this->logger->info('Saga completed');
        }
    }
    
  3. Testing Mock dependencies and use SagaTestCase (if available) or PHPUnit:

    public function testSagaExecution() {
        $saga = $this->createMock(ExampleSaga::class);
        $saga->method('execute')->willReturn(true);
        $this->assertTrue($saga->execute());
    }
    
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
monarobase/country-list
nasirkhan/laravel-sharekit
directorytree/privacy-filter-classifier
directorytree/privacy-filter
datacore/hub-sdk
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony
develia/geo-bundle
dreamzy/livewire-charts
touchestate-sdk/php-sdk
22h/doctrine-garbage-collection-bundle
agtp/agtp-php
agtp/mod-php
splash/sonata-admin
splash/metadata
splash/openapi
splash/scopes
splash/toolkit
testo/output-teamcity