Compare commits

..

No commits in common. "master" and "0.1.1.3" have entirely different histories.

8 changed files with 17 additions and 206 deletions

View File

@ -2,8 +2,6 @@
namespace NoccyLabs\React\CommandBus; namespace NoccyLabs\React\CommandBus;
use ReflectionFunction;
use ReflectionNamedType;
use React\Promise\Deferred; use React\Promise\Deferred;
use React\Promise\Promise; use React\Promise\Promise;
use React\Promise\PromiseInterface; use React\Promise\PromiseInterface;
@ -19,13 +17,10 @@ class Command
/** @var callable $handler The handler */ /** @var callable $handler The handler */
private $handler; private $handler;
private ?array $signature; public function __construct(string $name, callable $handler)
public function __construct(string $name, callable $handler, ?array $signature = null)
{ {
$this->name = $name; $this->name = $name;
$this->handler = $handler; $this->handler = $handler;
$this->signature = $signature;
} }
public function getName(): string public function getName(): string
@ -43,36 +38,5 @@ class Command
}); });
} }
public function parameters(): array
{
$refl = new ReflectionFunction($this->handler);
$args = [];
foreach ($refl->getParameters() as $parameter) {
$name = $parameter->getName();
$type = null;
if (!$parameter->hasType()) {
$type = 'any';
} else {
$type = $parameter->getType();
if ($type instanceof ReflectionNamedType && $type->isBuiltin()) {
$type = ($type->allowsNull() ? "?" : "") . $type->getName();
} else {
$type = null;
}
}
if ($parameter->isDefaultValueAvailable()) $type = "{$type}=".\json_encode($parameter->getDefaultValue(),\JSON_UNESCAPED_SLASHES);
if ($type !== null) $args[$name] = $type;
}
return $args;
}
public function getSignature(): array
{
return $this->signature ?? $this->parameters();
}
} }

View File

@ -13,97 +13,30 @@ class CommandBus implements CommandBusInterface
{ {
use EventEmitterTrait; use EventEmitterTrait;
/** @var array<CommandResolverInterface> */ private CommandRegistry $commandRegistry;
private $resolvers = [];
private SplObjectStorage $connections; private SplObjectStorage $connections;
private SplObjectStorage $servers; private SplObjectStorage $servers;
public function __construct(?CommandResolverInterface $commands=null) public function __construct(CommandRegistry $commandRegistry)
{ {
if ($commands) { $this->commandRegistry = $commandRegistry;
$this->resolvers[] = $commands;
}
$this->connections = new SplObjectStorage(); $this->connections = new SplObjectStorage();
$this->servers = new SplObjectStorage(); $this->servers = new SplObjectStorage();
} }
/** public function getRegistry(): CommandRegistry
* Get the command registry
*
* @deprecated Use getCommandNames() instead
* @return null
*/
public function getRegistry(): ?CommandRegistry
{ {
return null; // $this->commandRegistry; return $this->commandRegistry;
} }
/**
* Add a CommandResolver
*
* @param CommandResolverInterface $resolver
* @return void
*/
public function addResolver(CommandResolverInterface $resolver): void
{
$this->resolvers[] = $resolver;
}
public function removeResolver(CommandResolverInterface $resolver): void
{
// FIXME implement
}
/**
* Get the names of defined commands
*
* @return array
*/
public function getCommandNames(): array
{
$commands = [];
foreach ($this->resolvers as $resolver) {
$commands = array_merge($commands, $resolver->getCommandNames());
}
sort($commands);
return array_unique($commands);
}
/**
* Find a command by searching through the resolvers
*
* @param string $command
* @return Command|null
*/
public function findCommand(string $command): ?Command
{
foreach ($this->resolvers as $resolver) {
if ($found = $resolver->findCommand($command))
return $found;
}
return null;
}
/**
* Add a server listener
*
* @param ServerInterface $server
* @return void
*/
public function addServer(ServerInterface $server): void public function addServer(ServerInterface $server): void
{ {
$this->servers->attach($server); $this->servers->attach($server);
$server->on('connection', $this->onServerConnection(...)); $server->on('connection', $this->onServerConnection(...));
} }
/**
* Remove a server listener
*
* @param ServerInterface $server
* @return void
*/
public function removeServer(ServerInterface $server): void public function removeServer(ServerInterface $server): void
{ {
$server->close(); $server->close();
@ -111,11 +44,6 @@ class CommandBus implements CommandBusInterface
$this->servers->detach($server); $this->servers->detach($server);
} }
/**
* Close and shutdown the servers
*
* @return void
*/
public function close(): void public function close(): void
{ {
foreach ($this->servers as $server) { foreach ($this->servers as $server) {
@ -178,7 +106,7 @@ class CommandBus implements CommandBusInterface
private function executeContext(Context $context): PromiseInterface private function executeContext(Context $context): PromiseInterface
{ {
$command = $this->findCommand($context->getCommandName()); $command = $this->commandRegistry->find($context->getCommandName());
if (!$command) return new Promise(function (callable $resolve) use ($context) { if (!$command) return new Promise(function (callable $resolve) use ($context) {
throw new \RuntimeException("Unable to resolve command: ".$context->getCommandName()); throw new \RuntimeException("Unable to resolve command: ".$context->getCommandName());
}); });

View File

@ -38,8 +38,8 @@ class CommandBusClient implements CommandBusInterface
{ {
$this->commandRegistry = $commandRegistry; $this->commandRegistry = $commandRegistry;
if ($commandRegistry) { if ($commandRegistry) {
$this->commandRegistry->on(CommandRegistry::EVENT_REGISTERED, $this->onCommandRegistered(...)); $commandRegistry->on(CommandRegistry::EVENT_REGISTERED, $this->onCommandRegistered(...));
$this->commandRegistry->on(CommandRegistry::EVENT_UNREGISTERED, $this->onCommandUnregistered(...)); $commandRegistry->on(CommandRegistry::EVENT_UNREGISTERED, $this->onCommandUnregistered(...));
} }
$this->connector = $connector??new TcpConnector(); $this->connector = $connector??new TcpConnector();
} }

View File

@ -8,7 +8,7 @@ use Evenement\EventEmitterTrait;
* A collection of commands that can be executed via CommandBusInterface * A collection of commands that can be executed via CommandBusInterface
* *
*/ */
class CommandRegistry implements CommandResolverInterface, EventEmitterInterface class CommandRegistry implements EventEmitterInterface
{ {
use EventEmitterTrait; use EventEmitterTrait;
@ -40,12 +40,12 @@ class CommandRegistry implements CommandResolverInterface, EventEmitterInterface
$this->emit(self::EVENT_UNREGISTERED, [ $command ]); $this->emit(self::EVENT_UNREGISTERED, [ $command ]);
} }
public function findCommand(string $command): ?Command public function find(string $command): ?Command
{ {
return $this->commands[$command] ?? null; return $this->commands[$command] ?? null;
} }
public function getCommandNames(): array public function getNames(): array
{ {
return array_keys($this->commands); return array_keys($this->commands);
} }

View File

@ -1,19 +0,0 @@
<?php
namespace NoccyLabs\React\CommandBus;
use Evenement\EventEmitterInterface;
use Evenement\EventEmitterTrait;
/**
* A collection of commands that can be executed via CommandBusInterface
*
*/
interface CommandResolverInterface
{
public function findCommand(string $command): ?Command;
public function getCommandNames(): array;
}

View File

@ -1,52 +0,0 @@
<?php
namespace NoccyLabs\React\CommandBus;
use Evenement\EventEmitterInterface;
use Evenement\EventEmitterTrait;
/**
* A collection of commands that can be executed via CommandBusInterface
*
*/
trait CommandResolverTrait
{
const EVENT_REGISTERED = 'registered';
const EVENT_UNREGISTERED = 'unregistered';
/** @var array<string,Command> */
private array $commands = [];
public function registerCommand(string $command, callable $handler): void
{
$isNew = !array_key_exists($command, $this->commands);
$this->commands[$command] = new Command($command, $handler);
if ($isNew) {
$this->emit(self::EVENT_REGISTERED, [ $command ]);
}
}
public function unregisterCommand(string $command): void
{
if (!array_key_exists($command, $this->commands)) {
return;
}
unset($this->commands[$command]);
$this->emit(self::EVENT_UNREGISTERED, [ $command ]);
}
public function findCommand(string $command): ?Command
{
return $this->commands[$command] ?? null;
}
public function getCommandNames(): array
{
return array_keys($this->commands);
}
}

View File

@ -48,8 +48,8 @@ class CommandRegistryTest extends \PHPUnit\Framework\TestCase
$reg->register('a', $cmda); $reg->register('a', $cmda);
$reg->register('b', $cmdb); $reg->register('b', $cmdb);
$this->assertEquals('a', $reg->findCommand('a')?->getName()); $this->assertEquals('a', $reg->find('a')?->getName());
$this->assertEquals('b', $reg->findCommand('b')?->getName()); $this->assertEquals('b', $reg->find('b')?->getName());
} }
public function testGettingCommandNames() public function testGettingCommandNames()
@ -61,7 +61,7 @@ class CommandRegistryTest extends \PHPUnit\Framework\TestCase
$reg->register('a', $cmda); $reg->register('a', $cmda);
$reg->register('b', $cmdb); $reg->register('b', $cmdb);
$this->assertEquals(['a','b'], $reg->getCommandNames()); $this->assertEquals(['a','b'], $reg->getNames());
} }
} }

View File

@ -26,14 +26,4 @@ class CommandTest extends \PHPUnit\Framework\TestCase
$this->assertEquals(true, $hit); $this->assertEquals(true, $hit);
} }
public function testCommandReflection() }
{
$command = new Command("test", function (string $a, ?int $b, bool $c = false) { });
$expect = [
'a' => 'string',
'b' => '?int',
'c' => 'bool=false'
];
$this->assertEquals($expect, $command->parameters());
}
}