public function dispatch($module, $controller, $action, $params = [])
{
$this->_moduleName = Text::camelize($module);
$this->_controllerName = Text::camelize($controller);
$this->_actionName = lcfirst(Text::camelize($action));
$this->_params = $params;
if ($this->fireEvent('dispatcher:beforeDispatchLoop') === false) {
return false;
}
$controllerInstance = null;
$numberDispatches = 0;
$this->_finished = false;
while ($this->_finished === false) {
// if the user made a forward in the listener,the $this->_finished will be changed to false.
$this->_finished = true;
if ($numberDispatches++ === 32) {
throw new DispatcherException('dispatcher has detected a cyclic routing causing stability problems');
}
if ($this->fireEvent('dispatcher:beforeDispatch') === false) {
return false;
}
if ($this->_finished === false) {
continue;
}
$controllerClassName = $this->alias->resolve('@ns.controllers\\' . $this->_controllerName . 'Controller');
if (!$this->_dependencyInjector->has($controllerClassName) && !class_exists($controllerClassName)) {
throw new NotFoundControllerException('`:controller` class cannot be loaded', ['controller' => $controllerClassName]);
}
$controllerInstance = $this->_dependencyInjector->getShared($controllerClassName);
$this->_controller = $controllerInstance;
$hasAction = false;
$actionMethod = $this->_actionName . 'Action';
foreach (get_class_methods($controllerInstance) as $method) {
if (strcasecmp($actionMethod, $method) === 0) {
if ($actionMethod !== $method) {
throw new DispatcherException('`:method` of `:controller` is not equal to `:action` ', ['method' => $method, 'action' => $this->_actionName . 'Action', 'controller' => $controllerClassName]);
}
$hasAction = true;
$actionMethod = $method;
break;
}
}
if (!$hasAction) {
throw new NotFoundActionException('`:action` action was not found on `:controller`', ['action' => $actionMethod, 'controller' => $controllerClassName]);
}
if ($this->fireEvent('dispatcher:beforeExecuteRoute') === false) {
return false;
}
if ($this->_finished === false) {
continue;
}
// Calling beforeExecuteRoute as callback
if (method_exists($controllerInstance, 'beforeExecuteRoute')) {
if ($controllerInstance->beforeExecuteRoute($this) === false) {
continue;
}
if ($this->_finished === false) {
continue;
}
}
if (!in_array($controllerClassName, $this->_initializedControllers, true) && method_exists($controllerInstance, 'initialize')) {
$controllerInstance->initialize();
$this->_initializedControllers[] = $controllerClassName;
}
if (isset($this->_params[0])) {
$this->_returnedValue = $controllerInstance->{$actionMethod}($this->_params[0]);
} else {
$this->_returnedValue = $controllerInstance->{$actionMethod}();
}
// Call afterDispatch
$this->fireEvent('dispatcher:afterDispatch');
if ($this->fireEvent('dispatcher:afterExecuteRoute') === false) {
return false;
}
if ($this->_finished === false) {
continue;
}
if (method_exists($controllerInstance, 'afterExecuteRoute')) {
if ($controllerInstance->afterExecuteRoute($this) === false) {
continue;
}
if ($this->_finished === false) {
continue;
}
}
}
$this->fireEvent('dispatcher:afterDispatchLoop');
return true;
}