> ## Documentation Index
> Fetch the complete documentation index at: https://docs.aikeedo.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Command bus

> How Aikeedo dispatches commands and queries to their handlers, and how to define your own.

Behavior in Aikeedo is expressed as a command and a handler. A request handler builds a command, dispatches it, and turns the result into a response. The same mechanism serves reads and writes.

## Dispatching

```php theme={null}
use Shared\Infrastructure\CommandBus\Dispatcher;

public function __construct(
    private Dispatcher $dispatcher,
) {}

$category = $this->dispatcher->dispatch(new CreateCategoryCommand('Marketing'));
```

`Dispatcher::dispatch(object $cmd): mixed` reads the `#[Handler]` attribute from the command's class, walking up to parent classes if needed, resolves that handler from the container, and calls `handle()`. A command with no handler throws `Shared\Infrastructure\CommandBus\Exception\NoHandlerFoundException`.

There is no queue and no middleware: the handler runs synchronously, in the current request.

## A command

```php src/Category/Application/Commands/CreateCategoryCommand.php theme={null}
<?php

declare(strict_types=1);

namespace Category\Application\Commands;

use Category\Application\CommandHandlers\CreateCategoryCommandHandler;
use Category\Domain\ValueObjects\Title;
use Shared\Infrastructure\CommandBus\Attributes\Handler;

#[Handler(CreateCategoryCommandHandler::class)]
class CreateCategoryCommand
{
    public Title $title;

    public function __construct(string $title)
    {
        $this->title = new Title($title);
    }
}
```

The command accepts scalars, because callers work with raw input, and converts them into value objects, so validation happens once and early.

## A handler

```php src/Category/Application/CommandHandlers/CreateCategoryCommandHandler.php theme={null}
class CreateCategoryCommandHandler
{
    public function __construct(
        private CategoryRepositoryInterface $repo,
        private EventDispatcherInterface $ed,
    ) {}

    public function handle(CreateCategoryCommand $cmd): CategoryEntity
    {
        $category = new CategoryEntity(title: $cmd->title);
        $this->repo->add($category);

        $event = new CategoryCreatedEvent($category);
        $this->ed->dispatch($event);

        return $category;
    }
}
```

Handlers are resolved from the container, so their dependencies are autowired. They persist through a repository and let the end-of-request flush write the change.

## Commands and queries

Both use the bus. The naming convention makes the intent clear:

| Prefix                          | Returns                                     |
| ------------------------------- | ------------------------------------------- |
| `Create*`, `Update*`, `Delete*` | The affected entity, or nothing             |
| `Read*`                         | One entity, or throws a not-found exception |
| `List*`                         | An iterator of entities                     |
| `Count*`                        | An integer                                  |

```php theme={null}
$plan = $this->dispatcher->dispatch(new ReadPlanCommand($id));

$cmd = new ListPlansCommand();
$cmd->setStatus(1);
$cmd->setOrderBy('price', 'ASC');

foreach ($this->dispatcher->dispatch($cmd) as $plan) {
    // …
}
```

List commands usually expose setters for filters, sorting, limits and cursors, rather than a long constructor.

## Named constructors

Some commands offer alternative constructors for lookups by something other than an ID:

```php theme={null}
$cmd = ReadSubscriptionCommand::createByExternalId('demo-pay', $providerId);
$subscription = $this->dispatcher->dispatch($cmd);
```

## Generators

A handler may return a `Generator`, which is how streamed AI responses work: the handler yields parts as the provider produces them, and the request handler streams them to the client. See [Streaming responses](/development/plugins/streaming-responses).

## Errors

Handlers throw domain exceptions rather than returning error values:

```php theme={null}
try {
    $cmd = new PayOrderCommand($id, $gateway, $reference);
    $this->dispatcher->dispatch($cmd);
} catch (AlreadyPaidException) {
    // Someone else completed it first.
}
```

Presentation-layer exceptions are turned into HTTP responses by the exception middleware. See [Routing and middleware](/development/core/routing-and-middleware).

## Using the bus from a plugin

Plugins dispatch core commands, and define their own:

```php theme={null}
#[Handler(SendGreetingCommandHandler::class)]
class SendGreetingCommand
{
    public function __construct(
        public readonly string $email,
    ) {}
}
```

Both sides are autowired, so a plugin's handler can depend on core services and on its own. See [Dependency injection](/development/plugins/dependency-injection-and-services).

## Conventions

<div className="flex flex-col gap-2">
  <div className="flex gap-2 items-start"><span className="flex h-[1lh] shrink-0 items-center"><Icon icon="square-rounded-check" size="18" /></span><span>One command, one handler, one responsibility.</span></div>
  <div className="flex gap-2 items-start"><span className="flex h-[1lh] shrink-0 items-center"><Icon icon="square-rounded-check" size="18" /></span><span>Commands hold data and convert it into value objects; they contain no logic.</span></div>
  <div className="flex gap-2 items-start"><span className="flex h-[1lh] shrink-0 items-center"><Icon icon="square-rounded-check" size="18" /></span><span>Handlers dispatch a domain event after a change, so other code can react.</span></div>
  <div className="flex gap-2 items-start"><span className="flex h-[1lh] shrink-0 items-center"><Icon icon="square-rounded-check" size="18" /></span><span>Handlers return entities or iterators, not formatted output. Formatting belongs in a resource.</span></div>
  <div className="flex gap-2 items-start"><span className="flex h-[1lh] shrink-0 items-center"><Icon icon="square-rounded-check" size="18" /></span><span>Nothing is flushed inside a handler unless it genuinely must be.</span></div>
</div>

## Related

* [Modules and layers](/development/core/modules-and-layers)
* [Events](/development/core/events)
* [Dependency injection](/development/core/dependency-injection)
