Skip to main content
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

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

src/Category/Application/Commands/CreateCategoryCommand.php
The command accepts scalars, because callers work with raw input, and converts them into value objects, so validation happens once and early.

A handler

src/Category/Application/CommandHandlers/CreateCategoryCommandHandler.php
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:
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:

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.

Errors

Handlers throw domain exceptions rather than returning error values:
Presentation-layer exceptions are turned into HTTP responses by the exception middleware. See Routing and middleware.

Using the bus from a plugin

Plugins dispatch core commands, and define their own:
Both sides are autowired, so a plugin’s handler can depend on core services and on its own. See Dependency injection.

Conventions

One command, one handler, one responsibility.
Commands hold data and convert it into value objects; they contain no logic.
Handlers dispatch a domain event after a change, so other code can react.
Handlers return entities or iterators, not formatted output. Formatting belongs in a resource.
Nothing is flushed inside a handler unless it genuinely must be.