diff --git a/public/index.php b/public/index.php index 0f477cc7..edc83edc 100644 --- a/public/index.php +++ b/public/index.php @@ -135,6 +135,11 @@ System\Session::load(System\Cookie::get('laravel_session')); } +// -------------------------------------------------------------- +// Register the route filters. +// -------------------------------------------------------------- +System\Routing\Filter::register(require APP_PATH.'filters'.EXT); + // -------------------------------------------------------------- // Execute the global "before" filter. // -------------------------------------------------------------- @@ -145,7 +150,7 @@ // ---------------------------------------------------------- if (is_null($response)) { - $route = System\Routing\Router::make(Request::method(), Request::uri())->route(); + $route = System\Routing\Router::make(Request::method(), Request::uri(), new System\Routing\Loader)->route(); $response = (is_null($route)) ? System\Response::make(System\View::make('error/404'), 404) : $route->call(); } diff --git a/system/routing/filter.php b/system/routing/filter.php index 2286bd42..3fad2a81 100644 --- a/system/routing/filter.php +++ b/system/routing/filter.php @@ -7,7 +7,28 @@ class Filter { * * @var array */ - public static $filters; + private static $filters = array(); + + /** + * Register a set of route filters. + * + * @param array $filters + * @return void + */ + public static function register($filters) + { + static::$filters = array_merge(static::$filters, $filters); + } + + /** + * Clear all of the registered route filters. + * + * @return void + */ + public static function clear() + { + static::$filters = array(); + } /** * Call a set of route filters. @@ -19,11 +40,6 @@ class Filter { */ public static function call($filters, $parameters = array(), $override = false) { - if (is_null(static::$filters)) - { - static::$filters = require APP_PATH.'filters'.EXT; - } - foreach (explode(', ', $filters) as $filter) { if ( ! isset(static::$filters[$filter])) @@ -33,6 +49,9 @@ public static function call($filters, $parameters = array(), $override = false) $response = call_user_func_array(static::$filters[$filter], $parameters); + // "Before" filters may override the request cycle. For example, an authentication + // filter may redirect a user to a login view if they are not logged in. Because of + // this, we will return the first filter response if overriding is enabled. if ( ! is_null($response) and $override) { return $response; diff --git a/system/routing/loader.php b/system/routing/loader.php index b1c502a2..9de6c905 100644 --- a/system/routing/loader.php +++ b/system/routing/loader.php @@ -8,28 +8,35 @@ class Loader { * @param string * @return array */ - public static function load($uri) + public function load($uri) { $base = require APP_PATH.'routes'.EXT; - if ( ! is_dir(APP_PATH.'routes') or $uri == '') - { - return $base; - } + return (is_dir(APP_PATH.'routes') and $uri != '') ? array_merge($this->load_nested_routes($uri), $base) : $base; + } - list($routes, $segments) = array(array(), explode('/', $uri)); + /** + * Load the appropriate routes from the routes directory. + * + * This is done by working down the URI until we find the deepest + * possible matching route file. + * + * @param string $uri + * @return array + */ + private function load_nested_routes($uri) + { + $segments = explode('/', $uri); foreach (array_reverse($segments, true) as $key => $value) { if (file_exists($path = ROUTE_PATH.implode('/', array_slice($segments, 0, $key + 1)).EXT)) { - $routes = require $path; - - break; + return require $path; } } - return array_merge($routes, $base); - } + return array(); + } } \ No newline at end of file diff --git a/system/routing/route.php b/system/routing/route.php index 97710159..c5dd283b 100644 --- a/system/routing/route.php +++ b/system/routing/route.php @@ -51,6 +51,10 @@ public function call() { $response = null; + // The callback may be in array form, meaning it has attached filters or is named. + // However, the callback may also simply be a closure. If it is just a closure, + // we can execute it here. Otherwise, we will need to evaluate the route for any + // filters that need to be called. if (is_callable($this->callback)) { $response = call_user_func_array($this->callback, $this->parameters); diff --git a/system/routing/router.php b/system/routing/router.php index bfabc18d..89257e5b 100644 --- a/system/routing/router.php +++ b/system/routing/router.php @@ -23,16 +23,16 @@ class Router { * * @param string $method * @param string $uri - * @param array $routes + * @param Loader $loader * @return void */ - public function __construct($method, $uri, $routes = null) + public function __construct($method, $uri, $loader) { // Put the request method and URI in route form. Routes begin with // the request method and a forward slash. $this->request = $method.' /'.trim($uri, '/'); - $this->routes = (is_null($routes)) ? Loader::load($uri) : $routes; + $this->routes = $loader->load($uri); } /** @@ -55,6 +55,8 @@ public static function make($method, $uri, $routes = null) */ public function route() { + // Check for a literal route match first. If we find one, there is + // no need to spin through all of the routes. if (isset($this->routes[$this->request])) { return Request::$route = new Route($this->request, $this->routes[$this->request]); diff --git a/system/url.php b/system/url.php index c5d52020..4738a045 100644 --- a/system/url.php +++ b/system/url.php @@ -71,7 +71,7 @@ public static function to_asset($url) */ public static function to_route($name, $parameters = array(), $https = false) { - if ( ! is_null($route = Route_Finder::find($name))) + if ( ! is_null($route = Routing\Finder::find($name))) { $uris = explode(', ', key($route));