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

Cqrs Php Laravel Package

black/cqrs-php

Minimal CQRS command bus for PHP/DDD without event sourcing. Define Command and CommandHandler, register handlers to commands, then dispatch via a single Bus. Includes optional Symfony bundle integration with service tags for handler registration.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require black/cqrs-php
    
    • Prefer explicit versions (e.g., "black/cqrs-php": "1.0.0") over @stable to avoid surprises.
  2. Basic Command/Handler:

    // Command
    class CreateUserCommand implements \Black\DDD\CQRSinPHP\Infrastructure\CQRS\Command {
        public $name;
        public $email;
        public function __construct(string $name, string $email) {
            $this->name = $name;
            $this->email = $email;
        }
    }
    
    // Handler
    class CreateUserHandler implements \Black\DDD\CQRSinPHP\Infrastructure\CQRS\CommandHandler {
        public function handle(CreateUserCommand $command) {
            // Business logic here
            return new User($command->name, $command->email);
        }
    }
    
  3. Register and Dispatch:

    $bus = new \Black\DDD\CQRSinPHP\Infrastructure\CQRS\Bus;
    $bus->register(CreateUserCommand::class, new CreateUserHandler());
    $bus->handle(new CreateUserCommand('John', 'john@example.com'));
    

First Use Case

  • Use Case: Trigger a user creation workflow.
  • Steps:
    1. Define a CreateUserCommand with required fields.
    2. Implement CreateUserHandler to process the command (e.g., save to DB).
    3. Register the handler with the bus and dispatch the command from a controller/service.

Implementation Patterns

Core Workflow

  1. Command Design:

    • Commands are immutable data objects (no methods, only properties).
    • Example:
      class UpdateProductStockCommand implements Command {
          public $productId;
          public $quantity;
          public function __construct(int $productId, int $quantity) {
              $this->productId = $productId;
              $this->quantity = $quantity;
          }
      }
      
  2. Handler Registration:

    • Manual Registration (for testing/CLI):
      $bus->register(UpdateProductStockCommand::class, new UpdateStockHandler());
      
    • Symfony Service Tagging (for production):
      services:
          App\Handler\UpdateStockHandler:
              tags:
                  - { name: black_cqrs.handler, command: "App\Command\UpdateProductStockCommand" }
      
  3. Dependency Injection:

    • Inject the bus into services/controllers:
      public function __construct(private Bus $bus) {}
      public function execute(CreateOrderCommand $command) {
          $this->bus->handle($command);
      }
      
  4. Error Handling:

    • Wrap handle() calls in try-catch:
      try {
          $bus->handle($command);
      } catch (CommandException $e) {
          // Log or rethrow
      }
      

Integration Tips

  • Laravel Integration:

    • Bind the bus to the container in AppServiceProvider:
      $this->app->singleton(Bus::class, function () {
          $bus = new Bus();
          // Register handlers manually or via tags (if using SymfonyBundle)
          return $bus;
      });
      
    • Use facades for cleaner code:
      use App\Facades\CQRS;
      
      CQRS::handle(new CreateUserCommand(...));
      
  • Testing:

    • Mock the bus to test handlers in isolation:
      $bus = $this->createMock(Bus::class);
      $bus->expects($this->once())->method('handle');
      $handler = new CreateUserHandler($bus);
      
  • Logging:

    • Decorate the bus to log commands/handlers:
      class LoggingBus implements Bus {
          public function handle(Command $command) {
              \Log::info("Handling command: " . get_class($command));
              $this->bus->handle($command);
          }
      }
      

Gotchas and Tips

Pitfalls

  1. Handler Registration:

    • Issue: Forgetting to register handlers leads to CommandNotRegisteredException.
    • Fix: Use Symfony’s black_cqrs.handler tag or manually register in a service provider.
  2. Command Immutability:

    • Issue: Modifying command properties after creation can cause inconsistent state.
    • Fix: Enforce immutability by making properties private and only accessible via constructor.
  3. Circular Dependencies:

    • Issue: Handlers depending on other handlers can create tight coupling.
    • Fix: Use interfaces for handlers and inject dependencies via constructor.
  4. SymfonyBundle Limitation:

    • Issue: The SymfonyBundle is archived and may not work with newer Symfony versions.
    • Fix: Use manual registration or fork the bundle for updates.

Debugging

  • Command Not Found:

    • Verify the fully qualified class name matches exactly (e.g., App\Command\CreateUserCommand vs. App\Command\CreateUserCommand).
    • Check for typos in handler registration.
  • Handler Not Invoked:

    • Ensure the handler implements CommandHandler and is properly registered.
    • Use dd($bus->getHandlers()) to inspect registered handlers.

Configuration Quirks

  • Bus Singleton:

    • The bus is stateless but should be a singleton to avoid duplicate handler registrations.
    • In Laravel, bind it as a singleton in the container.
  • No Event Sourcing:

    • This package does not support event sourcing—only CQRS commands.
    • For event-driven workflows, consider pairing with a library like spatie/laravel-event-sourcing.

Extension Points

  1. Custom Bus:

    • Extend Bus to add middleware (e.g., logging, validation):
      class MiddlewareBus implements Bus {
          public function handle(Command $command) {
              $this->validate($command);
              $this->log($command);
              $this->bus->handle($command);
          }
      }
      
  2. Command Validation:

    • Add validation middleware:
      class ValidateCommandMiddleware {
          public function __invoke(Command $command, callable $next) {
              if (!$command instanceof ValidatableCommand) return $next($command);
              if (!$command->isValid()) {
                  throw new InvalidCommandException();
              }
              return $next($command);
          }
      }
      
  3. Async Handling:

    • Dispatch commands to a queue (e.g., Laravel Queues):
      $bus->handle(new SendEmailCommand(...)); // Sync
      dispatch(new HandleCommandJob($command)); // Async
      
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.
craftcms/url-validator
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
testo/bridge-symfony