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 Sf Bundle Laravel Package

dmp/cqrs-sf-bundle

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation

    composer require dmp/cqrs-sf-bundle
    

    Add to config/bundles.php:

    return [
        // ...
        Dmp\CqrsBundle\DmpCqrsBundle::class => ['all' => true],
    ];
    
  2. First Use Case: Command Handling Define a command class (e.g., src/Command/CreateUserCommand.php):

    namespace App\Command;
    
    class CreateUserCommand
    {
        public function __construct(
            public string $name,
            public string $email
        ) {}
    }
    

    Register the command in config/packages/dmp_cqrs.yaml:

    dmp_cqrs:
        commands:
            App\Command\CreateUserCommand: App\CommandHandler\CreateUserCommandHandler
    
  3. Dispatching a Command

    use Dmp\CqrsBundle\CommandBus;
    
    class UserController
    {
        public function __construct(private CommandBus $commandBus) {}
    
        public function createUser(string $name, string $email)
        {
            $command = new CreateUserCommand($name, $email);
            $this->commandBus->dispatch($command);
        }
    }
    
  4. Query Handling (Optional) Define a query (e.g., src/Query/GetUserQuery.php):

    namespace App\Query;
    
    class GetUserQuery
    {
        public function __construct(public int $id) {}
    }
    

    Register in dmp_cqrs.yaml:

    dmp_cqrs:
        queries:
            App\Query\GetUserQuery: App\QueryHandler\GetUserQueryHandler
    

Implementation Patterns

Command-Query Separation

  • Commands: Use for state-changing operations (e.g., CreateUserCommand, UpdateOrderCommand).
  • Queries: Use for read operations (e.g., GetUserByEmailQuery, ListActiveOrdersQuery).
  • Workflow: Always dispatch commands via CommandBus; resolve queries via QueryBus (if implemented).

Command Handlers

  • Structure:
    namespace App\CommandHandler;
    
    use App\Command\CreateUserCommand;
    use App\Repository\UserRepository;
    
    class CreateUserCommandHandler
    {
        public function __construct(private UserRepository $userRepository) {}
    
        public function __invoke(CreateUserCommand $command)
        {
            $this->userRepository->save(
                new User($command->name, $command->email)
            );
        }
    }
    
  • Dependencies: Inject services (repositories, managers) via constructor.

Middleware Pipeline

  • Add middleware in dmp_cqrs.yaml:
    dmp_cqrs:
        command_middleware:
            - App\Middleware\LoggingMiddleware
            - App\Middleware\ValidationMiddleware
    
  • Create middleware:
    namespace App\Middleware;
    
    use Dmp\CqrsBundle\Middleware\CommandMiddlewareInterface;
    
    class LoggingMiddleware implements CommandMiddlewareInterface
    {
        public function handle($command, callable $next)
        {
            \Log::info("Handling command: " . get_class($command));
            return $next($command);
        }
    }
    

Event Dispatching (Optional)

  • Publish events in command handlers:
    public function __invoke(CreateUserCommand $command)
    {
        $user = $this->userRepository->save(new User(...));
        $this->eventDispatcher->dispatch(new UserCreatedEvent($user));
    }
    
  • Register event listeners in Symfony’s EventSubscriber or dmp_cqrs.yaml (if supported).

Testing

  • Unit Test Handlers:
    public function testCreateUserCommand()
    {
        $handler = new CreateUserCommandHandler($this->createMock(UserRepository::class));
        $command = new CreateUserCommand('John', 'john@example.com');
        $handler($command);
        // Assert repository interactions
    }
    
  • Integration Test Bus:
    $commandBus = $this->container->get(CommandBus::class);
    $commandBus->dispatch(new CreateUserCommand(...));
    $this->assertDatabaseHas('users', [...]);
    

Gotchas and Tips

Configuration Quirks

  1. YAML Overrides:

    • Use !import in config/packages/dmp_cqrs.yaml to override defaults:
      imports:
          - { resource: "@AppConfig/config/cqrs.yaml" }
      
    • Ensure paths are correct (Symfony 5+ uses config/packages/ by default).
  2. Autowiring Conflicts:

    • If handlers aren’t autowired, manually bind them in services.yaml:
      services:
          App\CommandHandler\CreateUserCommandHandler:
              tags: ['dmp_cqrs.command_handler']
      

Debugging

  1. Missing Handlers:

    • Check dmp_cqrs.yaml for typos in command/query mappings.
    • Enable debug mode to see unhandled commands:
      $this->commandBus->setDebug(true);
      
  2. Middleware Order:

    • Middleware runs in the order defined in dmp_cqrs.yaml. Reorder as needed:
      command_middleware:
          - App\Middleware\ValidationMiddleware  # Runs first
          - App\Middleware\LoggingMiddleware    # Runs second
      
  3. Circular Dependencies:

    • Avoid injecting CommandBus into handlers (leads to circular references). Use services directly.

Extension Points

  1. Custom Bus:

    • Extend Dmp\CqrsBundle\CommandBus to add features (e.g., retry logic):
      class RetryCommandBus extends CommandBus
      {
          public function dispatch($command, int $retries = 3)
          {
              try {
                  parent::dispatch($command);
              } catch (Exception $e) {
                  if ($retries > 0) {
                      sleep(1);
                      $this->dispatch($command, $retries - 1);
                  }
                  throw $e;
              }
          }
      }
      
    • Bind it in services.yaml:
      services:
          Dmp\CqrsBundle\CommandBus: '@App\Service\RetryCommandBus'
      
  2. Async Commands:

    • Use Symfony Messenger for async processing:
      dmp_cqrs:
          commands:
              App\Command\SendEmailCommand: ~  # Mark as async
      
    • Configure Messenger transport in framework/messenger.yaml.
  3. Query Support:

    • The bundle lacks built-in query handling. Implement a QueryBus by extending the bundle or using a separate package like symfony/messenger with query commands.

Performance Tips

  1. Batch Commands:

    • For bulk operations, use a BatchCommand pattern:
      class BatchCreateUserCommand
      {
          public function __construct(public array $users) {}
      }
      
    • Process in chunks in the handler to avoid memory issues.
  2. Caching Queries:

    • Cache query results in handlers:
      public function __invoke(GetUserQuery $query)
      {
          return Cache::remember(
              "user_{$query->id}",
              3600,
              fn() => $this->userRepository->find($query->id)
          );
      }
      

Common Pitfalls

  1. Overusing Commands:

    • Avoid using commands for simple CRUD. Reserve for complex workflows (e.g., PlaceOrderCommand with validation/transactions).
  2. Tight Coupling:

    • Avoid passing repositories directly to commands. Use domain services or DTOs instead:
      // Bad: Command knows about UserRepository
      class CreateUserCommand { public function __construct(public UserRepository $repo) {} }
      
      // Good: Command is a DTO; handler uses repository
      class CreateUserCommand { public function __construct(public string $name) {} }
      
  3. Error Handling:

    • Wrap command dispatching in try-catch to avoid exposing internal errors:
      try {
          $this->commandBus->dispatch($command);
      } catch (CommandException $e) {
          $this->addFlash('error', $e->getMessage());
      }
      
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