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 CommandHandlers., (*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)