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

Dbal Laravel Package

ecotone/dbal

Ecotone Doctrine DBAL integration: use your relational database for durable async message transport, outbox, dead letter queue, saga state storage, and JSON document store. Provides transactional message handling and declarative DBAL query “business methods”.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps to First Use

  1. Installation:

    composer require ecotone/ecotone
    

    For Laravel, use the Ecotone Lite integration:

    composer require ecotone/ecotone-laravel
    
  2. Configure DBAL Connection: Add to config/ecotone.php (or publish the config):

    'connections' => [
        'default' => [
            'dbal' => [
                'connection' => 'mysql', // or 'pgsql', 'sqlite'
                'table_prefix' => 'ecotone_',
            ],
        ],
    ],
    

    Ensure your .env has the correct database credentials.

  3. First Command Handler: Create a simple command and handler:

    // app/Commands/ProcessOrder.php
    namespace App\Commands;
    
    #[CommandHandler]
    class ProcessOrder
    {
        public function __invoke(ProcessOrderCommand $command)
        {
            // Business logic here
            return new OrderProcessedEvent($command->orderId);
        }
    }
    
  4. Dispatch a Command: In a controller or service:

    use Ecotone\CommandBus;
    
    public function __construct(private CommandBus $commandBus) {}
    
    public function handleOrder(OrderRequest $request)
    {
        $command = new ProcessOrderCommand($request->orderId);
        $this->commandBus->dispatch($command);
    }
    
  5. Run the Consumer: Start the Ecotone consumer in a terminal:

    php artisan ecotone:consume
    

    This replaces queue:work for processing commands.


Where to Look First

  • Quickstart Guide: Covers installation, basic setup, and first command handler.
  • Laravel Module Docs: Laravel-specific integration details.
  • #[CommandHandler] Attribute: The core entry point for message handling. Explore how it replaces Laravel’s ShouldQueue jobs.
  • Outbox Pattern Example: Check the unreliable async processing docs for atomic event publishing.

First Use Case: Replace a Laravel Queue Job

Problem: You have a SendWelcomeEmail job that fails intermittently due to SMTP issues. Solution: Use Ecotone’s outbox pattern to ensure the email is sent atomically with the user creation.

  1. Create a Command:

    #[CommandHandler]
    class SendWelcomeEmailHandler
    {
        public function __invoke(SendWelcomeEmailCommand $command)
        {
            Mail::to($command->email)->send(new WelcomeEmail($command->userId));
            return new EmailSentEvent($command->userId);
        }
    }
    
  2. Dispatch in User Creation:

    public function createUser(UserRequest $request)
    {
        $user = User::create($request->validated());
        $this->commandBus->dispatch(new SendWelcomeEmailCommand(
            $user->email,
            $user->id
        ));
    }
    
  3. Configure Outbox: Ensure your database has the ecotone_messages table (migrated automatically or manually via schema).

  4. Verify Atomicity: If the system crashes after user creation but before the email is sent, the outbox ensures the email is retried on the next ecotone:consume run.


Implementation Patterns

Core Workflows

1. Command-Handler Pattern (Replaces Jobs)

  • Use Case: Replace Laravel’s ShouldQueue jobs with Ecotone’s #[CommandHandler].
  • Pattern:
    #[CommandHandler]
    class UpdateInventoryHandler
    {
        public function __invoke(UpdateInventoryCommand $command)
        {
            // Update inventory in DB
            Inventory::where('product_id', $command->productId)
                     ->decrement('stock', $command->quantity);
    
            // Publish an event (optional)
            return new InventoryUpdatedEvent($command->productId);
        }
    }
    
  • Integration Tip: Use dependency injection for services (e.g., Repository, Mailer) just like in Laravel controllers.

2. Outbox Pattern (Atomic Event Publishing)

  • Use Case: Ensure events are published only if the database transaction succeeds.
  • Pattern:
    public function createOrder(OrderRequest $request)
    {
        DB::transaction(function () use ($request) {
            $order = Order::create($request->validated());
            $this->commandBus->dispatch(new PublishOrderCreatedEventCommand(
                $order->id,
                $order->items
            ));
        });
    }
    
  • Handler:
    #[CommandHandler]
    class PublishOrderCreatedEventHandler
    {
        public function __invoke(PublishOrderCreatedEventCommand $command)
        {
            event(new OrderCreated($command->orderId, $command->items));
        }
    }
    
  • Integration Tip: Combine with Laravel’s dispatch() for events or use Ecotone’s event bus for consistency.

3. Dead Letter Queue (DLQ)

  • Use Case: Handle failed commands (e.g., external API failures).
  • Pattern:
    • Configure DLQ in config/ecotone.php:
      'dead_letter' => [
          'enabled' => true,
          'table' => 'ecotone_dead_letters',
      ],
      
    • Throw exceptions in handlers to trigger DLQ:
      #[CommandHandler]
      class ProcessPaymentHandler
      {
          public function __invoke(ProcessPaymentCommand $command)
          {
              if (!$this->paymentGateway->charge($command->amount)) {
                  throw new PaymentFailedException("Gateway error: " . $this->paymentGateway->getLastError());
              }
          }
      }
      
  • Replay Failed Commands: Use the ecotone:replay artisan command or manually inspect the ecotone_dead_letters table.

4. Sagas (Long-Running Transactions)

  • Use Case: Coordinate multiple services (e.g., order + payment + shipping).
  • Pattern:
    #[Saga]
    class OrderFulfillmentSaga
    {
        #[StartSaga]
        public function start(OrderCreated $event)
        {
            return new ReserveInventoryCommand($event->orderId, $event->items);
        }
    
        #[SagaMethod]
        public function reserveInventory(ReserveInventoryCommand $command, ReserveInventoryResult $result)
        {
            if (!$result->success) {
                throw new InventoryUnavailableException();
            }
            return new ProcessPaymentCommand($command->orderId, $command->total);
        }
    
        #[SagaMethod]
        public function processPayment(ProcessPaymentCommand $command, PaymentProcessed $event)
        {
            return new ShipOrderCommand($command->orderId);
        }
    }
    
  • Integration Tip: Store saga state in the database via #[Identifier] (e.g., order_id).

5. Document Store (JSON Aggregates)

  • Use Case: Persist complex aggregates without ORM (e.g., user profiles, settings).
  • Pattern:
    #[DocumentStore]
    class UserProfile
    {
        public function __construct(
            public string $userId,
            public array $preferences,
            public ?array $addresses = null
        ) {}
    }
    
    • Query via #[DbalBusinessMethod]:
      #[DbalBusinessMethod]
      public function findByUserId(string $userId): ?UserProfile
      {
          return $this->findOneBy(['user_id' => $userId]);
      }
      

Integration Tips

Laravel-Specific

  1. Service Provider Setup: Add to AppServiceProvider:

    public function boot()
    {
        $this->app->register(\Ecotone\Laravel\EcotoneServiceProvider::class);
    }
    
  2. Artisan Commands:

    • php artisan ecotone:consume: Start the message consumer (replaces queue:work).
    • php artisan ecotone:install: Set up DB tables (run once).
    • php artisan ecotone:replay: Replay dead-lettered commands.
  3. Queue Workers: Replace queue:work in your supervisor.conf or queue:listen with:

    php artisan ecotone:consume --daemon
    

Testing

  • Unit Testing Handlers: Use Ecotone’s CommandBus mock:
    $commandBus = new CommandBus();
    $handler = new ProcessOrderHandler();
    $result = $commandBus->dispatch(new ProcessOrderCommand('123'));
    
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.
terminal42/code-quality-tools
codifyo/ts-generator-bundle
andydefer/laravel-cluster
testo/fiber
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity
christhompsontldr/laravel-inky