public function dispatch($query)
{
$deferred = new Deferred();
$promise = $deferred->promise();
$actionEvent = $this->getActionEventEmitter()->getNewActionEvent();
$actionEvent->setTarget($this);
$actionEvent->setParam(self::EVENT_PARAM_DEFERRED, $deferred);
$actionEvent->setParam(self::EVENT_PARAM_PROMISE, $promise);
try {
$this->initialize($query, $actionEvent);
if ($actionEvent->getParam(self::EVENT_PARAM_MESSAGE_HANDLER) === null) {
$actionEvent->setName(self::EVENT_ROUTE);
$this->trigger($actionEvent);
}
if ($actionEvent->getParam(self::EVENT_PARAM_MESSAGE_HANDLER) === null) {
throw new RuntimeException(sprintf("QueryBus was not able to identify a Finder for query %s", $this->getMessageName($query)));
}
$finder = $actionEvent->getParam(self::EVENT_PARAM_MESSAGE_HANDLER);
if (is_string($finder) && !is_callable($finder)) {
$actionEvent->setName(self::EVENT_LOCATE_HANDLER);
$this->trigger($actionEvent);
}
$actionEvent->setName(self::EVENT_INVOKE_FINDER);
$this->trigger($actionEvent);
if (!$actionEvent->getParam(self::EVENT_PARAM_MESSAGE_HANDLED)) {
throw new RuntimeException(sprintf('Query %s was not handled', $this->getMessageName($query)));
}
$this->triggerFinalize($actionEvent);
} catch (\Exception $ex) {
$failedPhase = $actionEvent->getName();
$actionEvent->setParam(self::EVENT_PARAM_EXCEPTION, $ex);
$this->triggerError($actionEvent);
$this->triggerFinalize($actionEvent);
//Check if a listener has removed the exception to indicate that it was able to handle it
if ($ex = $actionEvent->getParam(self::EVENT_PARAM_EXCEPTION)) {
$actionEvent->setName($failedPhase);
$deferred->reject(MessageDispatchException::failed($actionEvent, $ex));
}
}
return $actionEvent->getParam(self::EVENT_PARAM_PROMISE);
}