1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 123: 124: 125: 126: 127: 128: 129: 130: 131: 132: 133: 134: 135: 136: 137: 138: 139: 140: 141: 142: 143: 144: 145: 146: 147: 148: 149: 150: 151: 152: 153: 154: 155: 156: 157: 158: 159: 160: 161: 162: 163: 164: 165: 166: 167: 168: 169: 170: 171: 172: 173: 174: 175: 176: 177: 178: 179: 180: 181: 182: 183: 184: 185: 186: 187: 188: 189: 190: 191: 192: 193: 194: 195: 196: 197: 198: 199: 200: 201: 202: 203:
<?php
namespace Coast;
use Coast;
class Controller implements \Coast\App\Access, \Coast\Router\Routable
{
use \Coast\App\Access\Implementation;
protected $_nspaces = [];
protected $_stack = [];
protected $_history = [];
protected $_actions = [];
protected $_all;
public function __construct(array $options = array())
{
foreach ($options as $name => $value) {
if ($name[0] == '_') {
throw new \Coast\Exception("Access to '{$name}' is prohibited");
}
$this->$name($value);
}
}
public function nspace($name, $nspace = null)
{
if (func_num_args() > 0) {
$this->_nspaces[$name] = $nspace;
return $this;
}
return isset($this->_nspaces[$name])
? $this->_nspaces[$name]
: null;
}
public function nspaces(array $nspaces = null)
{
if (func_num_args() > 0) {
foreach ($nspaces as $name => $nspace) {
$this->nspace($name, $nspace);
}
return $this;
}
return $this->_nspaces;
}
public function all($all = null)
{
if (func_num_args() > 0) {
$this->_all = $all;
return $this;
}
return $this->_all;
}
public function forward($action, $controller = null, $group = null)
{
if (count($this->_history) > 0) {
$item = $this->_history[count($this->_history) - 1];
$controller = isset($controller)
? $controller
: $item[0];
$params = $item[2];
$group = isset($group)
? $group
: $item[3];
} else {
$params = [];
}
if (isset($params['req'])) {
$params['req']->param('dispatch', [
'controller' => $controller,
'action' => $action,
'group' => $group
]);
}
$this->_stack = [];
$this->_queue($controller, $action, $params, $group);
}
public function stop()
{
$this->_stack = [];
}
public function dispatch($controller, $action, $params = array(), $group = null)
{
if (!isset($group)) {
reset($this->_nspaces);
$group = key($this->_nspaces);
}
if (isset($params['req'])) {
$params['req']->param('dispatch', [
'controller' => $controller,
'action' => $action,
'group' => $group
]);
}
$this->_history = [];
$this->_stack = [];
$this->_queue($controller, $action, $params, $group);
$result = null;
while (count($this->_stack) > 0) {
$item = array_shift($this->_stack);
$this->_history[] = $item;
list($controller, $action, $params, $group) = $item;
$nspace = str_camel_lower($group);
if (!isset($this->_nspaces[$nspace])) {
throw new Controller\Exception("Controller group '{$nspace}' does not exist");
}
$class = $this->_nspaces[$nspace] . '\\' . implode('\\', array_map('Coast\str_camel_upper', explode('/', $controller)));
if (!isset($this->_actions[$class])) {
if (!class_exists($class)) {
throw new Controller\Failure("Controller class '{$class}' does not exist");
}
$object = new $class($this);
if (!$object instanceof \Coast\Controller\Action) {
throw new Controller\Exception("Controller class '{$class}' is not an instance of \Coast\Controller\Action");
}
$this->_actions[$class] = $object;
} else {
$object = $this->_actions[$class];
}
$method = str_camel_lower($action);
if (!method_exists($object, $method)) {
throw new Controller\Failure("Controller action '{$class}::{$method}' does not exist");
}
$result = call_user_func_array([$object, $method], $params);
if (isset($result)) {
$this->_stack = [];
}
}
return $result;
}
protected function _queue($controller, $action, $params, $group)
{
$parts = explode('_', $controller);
$path = [];
$controllers = [];
while (count($parts) > 0) {
$path[] = array_shift($parts);
$controllers[] = implode('_', $path);
}
$final = $controllers[count($controllers) - 1];
$stack = [];
foreach ($controllers as $controller) {
array_push($stack, [$controller, 'preDispatch', $params, $group]);
}
array_push($stack, [$final, $action, $params, $group]);
foreach (array_reverse($controllers) as $controller) {
array_push($stack, [$controller, 'postDispatch', $params, $group]);
}
if (isset($this->_all)) {
array_unshift($stack, [$this->_all[0], 'preDispatch', $params, $this->_all[1]]);
array_push($stack, [$this->_all[0], 'postDispatch', $params, $this->_all[1]]);
}
foreach ($stack as $item) {
$this->_stack[] = $item;
}
}
public function route(\Coast\Request $req, \Coast\Response $res, array $route)
{
$controller = str_replace('_', '/', $route['params']['controller']);
$action = $route['params']['action'];
$group = isset($route['params']['group'])
? $route['params']['group']
: null;
try {
return $this->dispatch(
$controller,
$action,
['req' => $req, 'res' => $res],
$group
);
} catch (Controller\Failure $e) {
return;
}
}
}