maxkaemmerer/commands
, (*1)
Description:
This library offers interfaces and implementations for a simple command, command-handler, command-bus structure., (*2)
This is of course not an original idea, but my preferred and fairly simple implementation., (*3)
The code is fully tested, I however do not take responsibility for use in production., (*4)
Use at your own risk., (*5)
Installation:
composer require maxkaemmerer/commands
, (*6)
Usage:
Generally you don't want to register each CommandHandler
by hand. You might want to use dependency injection via a container or service-manager., (*7)
(An example for the Symfony Framework would be using a CompilerPass
), (*8)
You would also want to inject the CommandBus
itself via dependency injection wherever you need it., (*9)
Feel free to create your own implementations of CommandBus
and Payload
if you require something more advanced., (*10)
Register a Command Handler:
Register a CommandHandler
to the CommandBus
. The CommandHandler
's handles()
method returns the name of the Command
that it handles., (*11)
Best practice would be using the fully qualified class name of the command. MyCommand::class
, (*12)
The CommandHandler::handle($command)
method is where your actual domain logic happens., (*13)
Feel free to inject services, a container, or whatever else you need, into your CommandHandler
s., (*14)
$commandBus = new SimpleCommandBus();
$commandBus->registerHandler(new class implements CommandHandler
{
/**
* @param Command $command
*/
public function handle(Command $command): void
{
echo $command->payload()->get('message');
}
/**
* @return string
* The name of the command this handler handles. Command::name()
*/
public function handles(): string
{
return 'commandName';
}
});
Dispatch a Command:
Dispatching a Command
causes the CommandBus
to look for a CommandHandler
who's CommandHandler:handles()
method matches the Command
's name, specified by Command:name()
, and calls it's CommandHandler::handle($command)
method., (*15)
IMPORTANT: CommandHandler
's and the CommandBus
never return anything., (*16)
...
// The CommandHandler was registered
$commandBus->dispatch(new class implements Command
{
/**
* @return CommandPayload
*/
public function payload(): CommandPayload
{
// You would of course set the Payload in the constructor of your Command implementation
return Payload::fromArray(['message' => 'Hello World!']);
}
/**
* @return string
* The name of this command, it is recommended to use the fully qualified class name.
*/
public function name(): string
{
return 'commandName';
}
});
Full Example:
<?php
use MaxKaemmerer\Commands\Command;
use MaxKaemmerer\Commands\CommandHandler;
use MaxKaemmerer\Commands\CommandPayload;
use MaxKaemmerer\Commands\Exception\CommandException;
use MaxKaemmerer\Commands\Implementations\Payload;
use MaxKaemmerer\Commands\Implementations\SimpleCommandBus;
require_once __DIR__ . '/vendor/autoload.php';
try {
$commandBus = new SimpleCommandBus();
$commandBus->registerHandler(new class implements CommandHandler
{
/**
* @param Command $command
*/
public function handle(Command $command): void
{
echo $command->payload()->get('message');
}
/**
* @return string
* The name of the command this handler handles. Command::name()
*/
public function handles(): string
{
return 'commandName';
}
});
$commandBus->dispatch(new class implements Command
{
/**
* @return CommandPayload
*/
public function payload(): CommandPayload
{
// You would of course set the Payload in the constructor of your Command implementation
return Payload::fromArray(['message' => 'Hello World!']);
}
/**
* @return string
* The name of this command, it is recommended to use the fully qualified class name.
*/
public function name(): string
{
return 'commandName';
}
});
} catch (CommandException $exception) {
error_log($exception->getMessage());
}
Result:
Hello World!
, (*17)