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

Tactician Bundle Laravel Package

league/tactician-bundle

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require league/tactician-bundle
    

    Add to config/bundles.php (Symfony 4+):

    return [
        // ...
        League\Tactician\Bundle\TacticianBundle::class => ['all' => true],
    ];
    
  2. First Command: Define a command class (e.g., app/Commands/SendWelcomeEmail.php):

    namespace App\Commands;
    
    class SendWelcomeEmail implements Command
    {
        public $email;
        public $userId;
    
        public function __construct(string $email, int $userId)
        {
            $this->email = $email;
            $this->userId = $userId;
        }
    }
    
  3. Dispatch via Controller:

    use League\Tactician\CommandBus;
    
    class UserController
    {
        public function __construct(private CommandBus $commandBus) {}
    
        public function register(Request $request)
        {
            $this->commandBus->handle(new SendWelcomeEmail(
                $request->get('email'),
                $request->get('user_id')
            ));
        }
    }
    
  4. Register Command Handler:

    services:
        League\Tactician\Bundle\TacticianBundle\Handler\CommandHandler:
            arguments:
                - ['App\Commands\SendWelcomeEmail']
            tags: ['tactician.command_handler']
    

First Use Case: Command-Handler Pair

  • Scenario: Process a user registration with email validation.
  • Workflow:
    1. Dispatch RegisterUser command from controller.
    2. Use middleware (e.g., ValidateEmail) to check validity.
    3. Handle with RegisterUserHandler to persist data.

Implementation Patterns

1. Command Bus Integration

  • Dependency Injection: Inject CommandBus into services/controllers:

    public function __construct(private CommandBus $bus) {}
    

    Dispatch commands:

    $this->bus->handle(new YourCommand($data));
    
  • Async Dispatch (Symfony Messenger): Combine with symfony/messenger for async processing:

    services:
        League\Tactician\Bundle\TacticianBundle\Messenger\TacticianMiddleware:
            arguments:
                - '@command_bus'
            tags: ['messenger.middleware']
    

2. Middleware Chains

  • Common Middleware:

    • LogCommand (logging)
    • Validate (input validation)
    • Authorize (permission checks)
    • Retry (for transient failures)
  • Custom Middleware:

    use League\Tactician\Middleware;
    
    class LogExecutionTime implements Middleware
    {
        public function execute($command, callable $next)
        {
            $start = microtime(true);
            $result = $next($command);
            $time = microtime(true) - $start;
            // Log $time...
            return $result;
        }
    }
    

    Register in config:

    tactician:
        command_bus:
            middleware:
                - League\Tactician\Middleware\Chain
                - App\Middleware\LogExecutionTime
    

3. Event-Driven Workflows

  • Post-Command Events: Use League\Tactician\Event\Handling\EventDispatcher to trigger events after command execution. Example:

    $dispatcher->dispatch(new CommandHandled($command, $result));
    
  • Integration with Symfony Events:

    $eventDispatcher->addListener(
        CommandHandled::class,
        [$this, 'onCommandHandled']
    );
    

4. Testing Strategies

  • Mock Command Bus:

    $bus = $this->createMock(CommandBus::class);
    $bus->expects($this->once())
        ->method('handle')
        ->with($this->isInstanceOf(YourCommand::class));
    
  • Isolated Handler Tests:

    $handler = new YourCommandHandler($service);
    $result = $handler->handle(new YourCommand($data));
    $this->assertEquals($expected, $result);
    

Gotchas and Tips

Pitfalls

  1. Circular Dependencies:

    • Avoid injecting CommandBus into command handlers (handlers should be stateless).
    • Fix: Use services or repositories passed to handlers.
  2. Middleware Order Matters:

    • Middleware runs in the order defined. Place Authorize before Validate to fail fast.
    • Tip: Use League\Tactician\Middleware\Chain to group related middleware.
  3. Command Bus Not Found:

    • Ensure TacticianBundle is enabled and command_bus is configured in config/packages/tactician.yaml.
    • Debug: Run php bin/console debug:container command_bus to verify.
  4. Handler Not Registered:

    • Tag handlers with tactician.command_handler or manually bind them in DI.
    • Fix:
      services:
          App\Handler\YourHandler:
              tags: ['tactician.command_handler']
      

Debugging Tips

  1. Log Command Execution: Add League\Tactician\Middleware\LogCommand to middleware chain:

    tactician:
        command_bus:
            middleware:
                - League\Tactician\Middleware\LogCommand
    
  2. Inspect Middleware: Use League\Tactician\Middleware\DebugMiddleware for verbose logging:

    tactician:
        command_bus:
            middleware:
                - League\Tactician\Middleware\DebugMiddleware
    
  3. Symfony Profiler: Enable tactician.profiler in config to track commands in the profiler toolbar.


Extension Points

  1. Custom Command Bus: Extend League\Tactician\CommandBus for specialized behavior (e.g., priority queues):

    class PriorityCommandBus extends CommandBus
    {
        protected function getMiddleware(): Middleware
        {
            return new Chain([
                new PrioritizeMiddleware(),
                parent::getMiddleware(),
            ]);
        }
    }
    
  2. Dynamic Handler Mapping: Use League\Tactician\Handler\Locator\MethodNameInflectorHandlerLocator for dynamic handler resolution:

    tactician:
        command_bus:
            handler_locator: League\Tactician\Handler\Locator\MethodNameInflectorHandlerLocator
    
  3. Integrate with Doctrine: Use League\Tactician\Doctrine\ORM\TransactionMiddleware for transactional commands:

    tactician:
        command_bus:
            middleware:
                - League\Tactician\Doctrine\ORM\TransactionMiddleware
    

Performance Tips

  1. Batch Commands: Use League\Tactician\CommandBus::handleMultiple() for bulk operations:

    $this->bus->handleMultiple([
        new Command1(),
        new Command2(),
    ]);
    
  2. Lazy-Load Handlers: For heavy handlers, lazy-load dependencies:

    class LazyHandler implements CommandHandler
    {
        private $service;
    
        public function handle(Command $command)
        {
            if (!$this->service) {
                $this->service = new HeavyService();
            }
            // ...
        }
    }
    
  3. Cache Middleware: Cache results of idempotent commands using League\Tactician\Middleware\CacheCommandResultMiddleware.

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.
emuniq/filament-browser-notifications
syriable/filament-translator
hungnm28/livewire-form
wenprise/eloquent
crudly/encrypted
fadion/bouncy
cuci/prototurk-sdk
gos/pubsub-router-bundle
cuci/prototurk-sdk-symfony
clementtalleu/easyadmin-markdown-bundle
codeflextech/permission-manager
karnoweb/livewire-datepicker
sayedenam/sayed-dashboard
milito/query-filter
apiboxsym/user-bundle
apiboxsym/health-check-bundle
jayeshmepani/jpl-moshier-ephemeris-php
elnasnato/laraliveui
labrodev/rest-sdk
sampaui/sampaui