Skip to content

Commit

Permalink
Throw exception when handler method is missing
Browse files Browse the repository at this point in the history
  • Loading branch information
rosstuck committed Dec 10, 2014
1 parent af6f646 commit ee5493f
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 0 deletions.
6 changes: 6 additions & 0 deletions src/Tactician/CommandBus/ExecutingCommandBus.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,12 @@ public function execute($command)
$handler = $this->handlerLocator->getHandlerForCommand($command);
$methodName = $this->methodNameInflector->inflect($command, $handler);

// is_callable is used here instead of method_exists, as method_exists
// will fail when given a handler that relies on __call.
if (!is_callable([$handler, $methodName])) {
throw CanNotInvokeHandlerException::onObject($command, "Method '{$methodName}' does not exist on handler");
}

return $handler->{$methodName}($command);
}
}
62 changes: 62 additions & 0 deletions tests/Tactician/Tests/CommandBus/ExecutingCommandBusTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@
use Tactician\Handler\MethodNameInflector\MethodNameInflector;
use Tactician\Handler\Locator\HandlerLocator;
use Tactician\Tests\Fixtures\Command\TaskCompletedCommand;
use Tactician\Tests\Fixtures\Handler\DynamicMethodsHandler;
use Tactician\Tests\Fixtures\Handler\TaskCompletedHandler;
use stdClass;
use Mockery;

class ExecutingCommandBusTest extends \PHPUnit_Framework_TestCase
Expand Down Expand Up @@ -60,4 +62,64 @@ public function testHandlerIsExecuted()

$this->assertEquals('a-return-value', $this->commandBus->execute($command));
}

/**
* @expectedException \Tactician\Exception\CanNotInvokeHandlerException
*/
public function testMissingMethodOnHandlerObjectIsDetected()
{
$command = new TaskCompletedCommand();

$this->methodNameInflector
->shouldReceive('inflect')
->andReturn('someMethodThatDoesNotExist');

$this->handlerLocator
->shouldReceive('getHandlerForCommand')
->andReturn(new stdClass);

$this->assertEquals('a-return-value', $this->commandBus->execute($command));
}

public function testDynamicMethodNamesAreSupported()
{
$command = new TaskCompletedCommand();
$handler = new DynamicMethodsHandler();

$this->methodNameInflector
->shouldReceive('inflect')
->andReturn('someHandlerMethod');

$this->handlerLocator
->shouldReceive('getHandlerForCommand')
->andReturn($handler);

$this->commandBus->execute($command);

$this->assertEquals(
['someHandlerMethod'],
$handler->getMethodsInvoked()
);
}

public function testClosuresCanBeInvoked()
{
$command = new TaskCompletedCommand();
$closureWasExecuted = false;
$handler = function () use (&$closureWasExecuted) {
$closureWasExecuted = true;
};

$this->methodNameInflector
->shouldReceive('inflect')
->andReturn('__invoke');

$this->handlerLocator
->shouldReceive('getHandlerForCommand')
->andReturn($handler);

$this->commandBus->execute($command);

$this->assertTrue($closureWasExecuted);
}
}
33 changes: 33 additions & 0 deletions tests/Tactician/Tests/Fixtures/Handler/DynamicMethodsHandler.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php
namespace Tactician\Tests\Fixtures\Handler;

/**
* Some folks prefer to rely on __call to proxy the incoming commands to
* methods, rather than do the routing externally. This test spy can be used to
* verify this works correctly.
*/
class DynamicMethodsHandler
{
/**
* @var string[]
*/
private $methods = [];

/**
* @return string[]
*/
public function getMethodsInvoked()
{
return $this->methods;
}

/**
* @param string $methodName
* @param array $args
*/
public function __call($methodName, $args)
{
$this->methods[] = $methodName;
}
}

0 comments on commit ee5493f

Please sign in to comment.