diff --git a/src/Pluf/Dispatcher.php b/src/Pluf/Dispatcher.php index 54f9c49..3ad38d1 100644 --- a/src/Pluf/Dispatcher.php +++ b/src/Pluf/Dispatcher.php @@ -107,55 +107,33 @@ class Pluf_Dispatcher /** * Match a query against the actions controllers. * + * @see Pluf_HTTP_URL_reverse + * * @param Pluf_HTTP_Request Request object * @return Pluf_HTTP_Response Response object */ public static function match($req, $firstpass=true) { - // Order the controllers by priority - foreach ($GLOBALS['_PX_views'] as $key => $control) { - $priority[$key] = $control['priority']; - } - array_multisort($priority, SORT_ASC, $GLOBALS['_PX_views']); try { - foreach ($GLOBALS['_PX_views'] as $key => $ctl) { - $match = array(); - if (preg_match($ctl['regex'], $req->query, $match)) { - $req->view = array($ctl, $match); - $m = new $ctl['model'](); - if (isset($m->{$ctl['method'].'_precond'})) { - // Here we have preconditions to respects. If - // the "answer" is true, then ok go ahead, if - // not then it a response so return it or an - // exception so let it go. - $preconds = $m->{$ctl['method'].'_precond'}; - if (!is_array($preconds)) { - $preconds = array($preconds); - } - foreach ($preconds as $precond) { - if (!is_array($precond)) { - $res = call_user_func_array( - explode('::', $precond), - array(&$req) - ); - } else { - $res = call_user_func_array( - explode('::', $precond[0]), - array_merge(array(&$req), - array_slice($precond, 1)) - ); - } - if ($res !== true) { - return $res; - } - } - } - if (!isset($ctl['params'])) { - return $m->$ctl['method']($req, $match); + $views = $GLOBALS['_PX_views']; + $to_match = $req->query; + $n = count($views); + $i = 0; + while ($i<$n) { + $ctl = $views[$i]; + if (preg_match($ctl['regex'], $to_match, $match)) { + if (!isset($ctl['sub'])) { + return self::send($req, $ctl, $match); } else { - return $m->$ctl['method']($req, $match, $ctl['params']); + // Go in the subtree + $views = $ctl['sub']; + $i = 0; + $n = count($views); + $to_match = substr($to_match, strlen($match[0])); + continue; } } + $i++; } } catch (Pluf_HTTP_Error404 $e) { // Need to add a 404 error handler @@ -177,6 +155,54 @@ class Pluf_Dispatcher } /** + * Call the view found by self::match. + * + * The called view can throw an exception. This is fine and + * normal. + * + * @param Pluf_HTTP_Request Current request + * @param array The url definition matching the request + * @param array The match found by preg_match + * @return Pluf_HTTP_Response Response object + */ + public static function send($req, $ctl, $match) + { + $req->view = array($ctl, $match); + $m = new $ctl['model'](); + if (isset($m->{$ctl['method'].'_precond'})) { + // Here we have preconditions to respects. If the "answer" + // is true, then ok go ahead, if not then it a response so + // return it or an exception so let it go. + $preconds = $m->{$ctl['method'].'_precond'}; + if (!is_array($preconds)) { + $preconds = array($preconds); + } + foreach ($preconds as $precond) { + if (!is_array($precond)) { + $res = call_user_func_array( + explode('::', $precond), + array(&$req) + ); + } else { + $res = call_user_func_array( + explode('::', $precond[0]), + array_merge(array(&$req), + array_slice($precond, 1)) + ); + } + if ($res !== true) { + return $res; + } + } + } + if (!isset($ctl['params'])) { + return $m->$ctl['method']($req, $match); + } else { + return $m->$ctl['method']($req, $match, $ctl['params']); + } + } + + /** * Load the controllers. * * @param string File including the views. diff --git a/src/Pluf/HTTP/URL.php b/src/Pluf/HTTP/URL.php index e94952b..29d4623 100644 --- a/src/Pluf/HTTP/URL.php +++ b/src/Pluf/HTTP/URL.php @@ -105,30 +105,60 @@ function Pluf_HTTP_URL_urlForView($view, $params=array(), */ function Pluf_HTTP_URL_reverse($view, $params=array()) { - $regex = null; $model = ''; $method = ''; if (false !== strpos($view, '::')) { list($model, $method) = split('::', $view); } - foreach ($GLOBALS['_PX_views'] as $dview) { + $vdef = array($model, $method, $view); + $regbase = array('', array()); + $regbase = Pluf_HTTP_URL_find($GLOBALS['_PX_views'], $vdef, $regbase); + if ($regbase === false) { + throw new Exception(sprintf('Error, the view: %s has not been found.', $view)); + } + $url = ''; + foreach ($regbase[1] as $regex) { + $url .= Pluf_HTTP_URL_buildReverseUrl($regex, $params); + } + if (!defined('IN_UNIT_TESTS')) { + $url = $regbase[0].$url; + } + return $url; +} + + +/** + * Go in the list of views to find the matching one. + * + * @param array Views + * @param array View definition array(model, method, name) + * @param array Regex of the view up to now and base + * @return mixed Regex of the view or false + */ +function Pluf_HTTP_URL_find($views, $vdef, $regbase) +{ + foreach ($views as $dview) { if ( - (isset($dview['name']) && $dview['name'] == $view) + (isset($dview['name']) && $dview['name'] == $vdef[2]) or - ($dview['model'] == $model && $dview['method'] == $method) + ($dview['model'] == $vdef[0] && $dview['method'] == $vdef[1]) ) { - $regex = $dview['regex']; - break; + $regbase[1][] = $dview['regex']; + if (!empty($dview['base'])) { + $regbase[0] = $dview['base']; + } + return $regbase; + } + if (isset($dview['sub'])) { + $regbase2 = $regbase; + $regbase2[1][] = $dview['regex']; + $res = Pluf_HTTP_URL_find($dview['sub'], $vdef, $regbase2); + if ($res) { + return $res; + } } } - if ($regex === null) { - throw new Exception(sprintf('Error, the view: %s has not been found.', $view)); - } - $url = Pluf_HTTP_URL_buildReverseUrl($regex, $params); - if (isset($dview['base']) and !defined('IN_UNIT_TESTS')) { - $url = $dview['base'].$url; - } - return $url; + return false; } /** @@ -165,9 +195,6 @@ function Pluf_HTTP_URL_buildReverseUrl($url_regex, $params=array()) 'return $a;'); $url = preg_replace_callback($groups, $func, $url_regex); } - $url = substr(substr($url, 2), 0, -2); - if (substr($url, -1) !== '$') { - return $url; - } - return substr($url, 0, -1); + preg_match('/^#\^?([^#\$]+)/', $url, $matches); + return $matches[1]; } diff --git a/src/Pluf/Tests/Dispatch/Dispatcher.php b/src/Pluf/Tests/Dispatch/Dispatcher.php new file mode 100644 index 0000000..e68513d --- /dev/null +++ b/src/Pluf/Tests/Dispatch/Dispatcher.php @@ -0,0 +1,97 @@ +views = $GLOBALS['_PX_views']; + } + + function tearDown() + { + $GLOBALS['_PX_views'] = $this->views; + } + + function hello() + { + return true; + } + + function testSimple() + { + $GLOBALS['_PX_views'] = array( + array( + 'regex' => '#^/hello/$#', + 'base' => '', + 'model' => 'Pluf_Tests_Dispatch_Dispatcher', + 'method' => 'hello' + ) + ); + $req1 = (object) array('query' => '/hello/'); // match + $req2 = (object) array('query' => '/hello'); // match second pass + $req3 = (object) array('query' => '/hello/you/'); // no match + $this->assertIdentical(true, Pluf_Dispatcher::match($req1)); + $this->assertIsA(Pluf_Dispatcher::match($req2), + 'Pluf_HTTP_Response_Redirect'); + $this->assertIsA(Pluf_Dispatcher::match($req3), + 'Pluf_HTTP_Response_NotFound'); + } + + function testRecursif() + { + $GLOBALS['_PX_views'] = array( + array( + 'regex' => '#^/hello/#', + 'base' => '', + 'sub' => array( + array( + 'regex' => '#^world/$#', + 'base' => '', + 'model' => 'Pluf_Tests_Dispatch_Dispatcher', + 'method' => 'hello' + ) + ) + )); + $req1 = (object) array('query' => '/hello/world/'); // match + $req2 = (object) array('query' => '/hello/world'); // match second pass + $req3 = (object) array('query' => '/hello/you/'); // no match + $this->assertIdentical(true, Pluf_Dispatcher::match($req1)); + $this->assertIsA(Pluf_Dispatcher::match($req2), + 'Pluf_HTTP_Response_Redirect'); + $this->assertIsA(Pluf_Dispatcher::match($req3), + 'Pluf_HTTP_Response_NotFound'); + Pluf::loadFunction('Pluf_HTTP_URL_reverse'); + $this->assertEqual('/hello/world/', + Pluf_HTTP_URL_reverse('Pluf_Tests_Dispatch_Dispatcher::hello')); + } + + +} \ No newline at end of file diff --git a/src/Pluf/conf/pluf.test.php b/src/Pluf/conf/pluf.test.php index b04d7a1..3bcadf8 100644 --- a/src/Pluf/conf/pluf.test.php +++ b/src/Pluf/conf/pluf.test.php @@ -36,7 +36,7 @@ $cfg['installed_apps'] = array('Pluf'); $cfg['tmp_folder'] = '/tmp'; // The folder in which the templates of the application are located. -$cfg['templates_folder'] = array(dirname(__FILE__).'/../templates'); +$cfg['template_folders'] = array(dirname(__FILE__).'/../templates'); $cfg['pluf_use_rowpermission'] = true;