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

Bdev Cqrs Bundle Laravel Package

boltconcepts/bdev-cqrs-bundle

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation

    composer require boltconcepts/bdev-cqrs-bundle
    

    Add to config/bundles.php:

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

    namespace App\Command;
    
    use BoltConcepts\BDevCQRSBundle\Command\CommandInterface;
    
    class CreateUserCommand implements CommandInterface {
        public $email;
        public $name;
    }
    

    Create a handler (e.g., src/CommandHandler/CreateUserCommandHandler.php):

    namespace App\CommandHandler;
    
    use App\Command\CreateUserCommand;
    use BoltConcepts\BDevCQRSBundle\Command\CommandHandlerInterface;
    
    class CreateUserCommandHandler implements CommandHandlerInterface {
        public function handle(CreateUserCommand $command) {
            // Business logic here
            return true;
        }
    }
    
  3. Dispatching Commands Inject CommandBus into a controller/service:

    use BoltConcepts\BDevCQRSBundle\Command\CommandBus;
    
    class UserController {
        public function __construct(private CommandBus $commandBus) {}
    
        public function createUser() {
            $command = new CreateUserCommand();
            $command->email = 'user@example.com';
            $command->name = 'John Doe';
    
            $this->commandBus->dispatch($command);
        }
    }
    
  4. Query Handling (Optional) Define a query (e.g., src/Query/GetUserQuery.php):

    namespace App\Query;
    
    use BoltConcepts\BDevCQRSBundle\Query\QueryInterface;
    
    class GetUserQuery implements QueryInterface {
        public $userId;
    }
    

    Create a query handler (e.g., src/QueryHandler/GetUserQueryHandler.php):

    namespace App\QueryHandler;
    
    use App\Query\GetUserQuery;
    use BoltConcepts\BDevCQRSBundle\Query\QueryHandlerInterface;
    
    class GetUserQueryHandler implements QueryHandlerInterface {
        public function handle(GetUserQuery $query) {
            // Fetch user data
            return ['id' => $query->userId, 'name' => 'John Doe'];
        }
    }
    
  5. Dispatching Queries Inject QueryBus into a controller/service:

    use BoltConcepts\BDevCQRSBundle\Query\QueryBus;
    
    class UserController {
        public function __construct(private QueryBus $queryBus) {}
    
        public function getUser($id) {
            $query = new GetUserQuery();
            $query->userId = $id;
            return $this->queryBus->ask($query);
        }
    }
    

Implementation Patterns

Command-Query Separation

  • Commands: Use for state-changing operations (e.g., CreateUserCommand, UpdateUserCommand).
  • Queries: Use for read operations (e.g., GetUserByEmailQuery, ListActiveUsersQuery).
  • Workflow: Always dispatch commands via CommandBus and queries via QueryBus. Avoid mixing logic in controllers.

Event-Driven Architecture (Optional)

The bundle supports events for side effects (e.g., logging, notifications). Extend BoltConcepts\BDevCQRSBundle\Event\EventInterface and configure listeners in config.yml:

bolt_concepts_bdev_cqrs:
    event_listeners:
        App\EventListener\UserCreatedListener: ['onUserCreated']

Middleware for Commands/Queries

Add middleware to pre/post-process commands or queries. Implement BoltConcepts\BDevCQRSBundle\Command\CommandMiddlewareInterface or BoltConcepts\BDevCQRSBundle\Query\QueryMiddlewareInterface:

class LoggingMiddleware implements CommandMiddlewareInterface {
    public function handle(CommandInterface $command, callable $next) {
        \Log::info('Command dispatched: ' . get_class($command));
        return $next($command);
    }
}

Register in services.yml:

services:
    App\Middleware\LoggingMiddleware:
        tags:
            - { name: bolt_concepts_bdev_cqrs.command_middleware }

Transaction Management

Wrap command handling in transactions for data consistency:

use Doctrine\DBAL\Connection;

class CreateUserCommandHandler implements CommandHandlerInterface {
    public function __construct(private Connection $connection) {}

    public function handle(CreateUserCommand $command) {
        $this->connection->beginTransaction();
        try {
            // Business logic
            $this->connection->commit();
        } catch (\Exception $e) {
            $this->connection->rollBack();
            throw $e;
        }
    }
}

Dependency Injection

Leverage Symfony’s DI to inject services into command/query handlers:

class CreateUserCommandHandler implements CommandHandlerInterface {
    public function __construct(
        private UserRepository $userRepository,
        private MailerInterface $mailer
    ) {}

    public function handle(CreateUserCommand $command) {
        $user = $this->userRepository->save($command);
        $this->mailer->sendWelcomeEmail($user);
    }
}

Validation

Use Symfony’s Validator for command/query validation:

use Symfony\Component\Validator\Constraints as Assert;

class CreateUserCommand implements CommandInterface {
    /**
     * @Assert\NotBlank
     * @Assert\Email
     */
    public $email;

    /**
     * @Assert\NotBlank
     * @Assert\Length(min: 2)
     */
    public $name;
}

Configure validation in config.yml:

bolt_concepts_bdev_cqrs:
    command_validators: true
    query_validators: false

Gotchas and Tips

Configuration Quirks

  1. Bundle Enablement Ensure the bundle is enabled in config/bundles.php. Without this, services (CommandBus, QueryBus) won’t be autowired.

  2. Service Naming The bundle uses bolt_concepts_bdev_cqrs as the root config key. Typos here will cause silent failures.

  3. Command/Query Naming Avoid naming conflicts with Symfony’s built-in services. Prefix custom commands/queries (e.g., App\Command\CreateUserCommand).

Debugging

  1. Unhandled Commands/Queries If a command/query has no handler, the bundle throws a CommandNotFoundException or QueryNotFoundException. Verify:

    • The handler implements CommandHandlerInterface or QueryHandlerInterface.
    • The handler is tagged as a service (automatically handled if using autowiring).
  2. Circular Dependencies Avoid circular dependencies between command/query handlers. Use interfaces and abstract classes to decouple logic.

  3. Transaction Deadlocks Long-running commands may cause deadlocks. Keep transactions short and avoid nested transactions.

Performance Tips

  1. Batch Processing For bulk operations, dispatch commands in batches to avoid overwhelming the event system:
    foreach ($users as $user) {
       $this->commandBus->dispatch(new CreateUserCommand($user));
    

}

Consider using a queue system (e.g., Symfony Messenger) for high-throughput scenarios.

2. **Query Caching**
Cache frequent queries (e.g., `GetUserQuery`) using Symfony’s cache component:
```php
use Symfony\Contracts\Cache\CacheInterface;

class GetUserQueryHandler implements QueryHandlerInterface {
    public function __construct(private CacheInterface $cache) {}

    public function handle(GetUserQuery $query) {
        return $this->cache->get($query->userId, function() use ($query) {
            return $this->userRepository->find($query->userId);
        });
    }
}
  1. Lazy Loading Handlers For rarely used commands/queries, lazy-load handlers to reduce memory usage:
    # config/services.yaml
    App\CommandHandler\RareCommandHandler:
        autowire: true
        lazy: true
    

Extension Points

  1. Custom Command/Query Buses Extend the default CommandBus or QueryBus to add custom logic:

    class CustomCommandBus extends CommandBus {
        public function dispatch(CommandInterface $command) {
            // Pre-processing
            parent::dispatch($command);
            // Post-processing
        }
    }
    

    Register as a service and override the default bus.

  2. Dynamic Handlers Use Symfony’s compiler passes to dynamically register handlers based on runtime conditions (advanced use case).

  3. Event Dispatching Extend the bundle’s event system to trigger custom events after command/query execution:

    class CreateUserCommandHandler implements CommandHandlerInterface {
        public function __construct(private EventDispatcherInterface $dispatcher) {}
    
        public function handle(CreateUserCommand $command) {
            $user = $this->userRepository->save($command);
            $this->dispatcher->dispatch(new UserCreatedEvent($user));
    
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.
jayeshmepani/jpl-moshier-ephemeris-php
elnasnato/laraliveui
labrodev/rest-sdk
sampaui/sampaui
babelqueue/php-sdk
facebook/capi-param-builder-php
babelqueue/symfony
hamzi/corewatch
minionfactory/raw-hydrator
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed
zedmagdy/filament-business-hours
renatovdemoura/blade-elements-ui
devgeek/beacon-admin
benjamin-rqt/data-watcher-bundle