more refactoring for 2.0

This commit is contained in:
Taylor Otwell
2011-09-19 21:33:25 -05:00
parent 7898094e25
commit a8dbe777df
13 changed files with 505 additions and 136 deletions

View File

@@ -4,6 +4,28 @@ use Closure;
use Laravel\Response;
use Laravel\Container;
class Delegate {
/**
* The destination of the route delegate.
*
* @var string
*/
public $destination;
/**
* Create a new route delegate instance.
*
* @param string $destination
* @return void
*/
public function __construct($destination)
{
$this->destination = $destination;
}
}
class Caller {
/**
@@ -60,10 +82,10 @@ class Caller {
if ( ! is_null($response = $route->call()))
{
// If a route returns a string, it also means the route is delegating the
// handling of the request to a controller method. So, we will pass the
// string to the route delegator, exploding on "@".
if (is_string($response)) $response = $this->delegate($route, $response);
// If a route returns a Delegate, it also means the route is delegating the
// handling of the request to a controller method. So, we will pass the string
// to the route delegator, exploding on "@".
if ($response instanceof Delegate) $response = $this->delegate($route, $response->destination);
return $this->finish($route, $response);
}
@@ -98,6 +120,11 @@ class Caller {
*/
protected function delegate(Route $route, $delegate)
{
if (strpos($delegate, '@') === false)
{
throw new \Exception("Route delegate [$delegate] has an invalid format.");
}
list($controller, $method) = explode('@', $delegate);
$controller = $this->resolve($controller);

107
laravel/routing/loader.php Normal file
View File

@@ -0,0 +1,107 @@
<?php namespace Laravel\Routing;
use Laravel\Arr;
class Loader {
/**
* The location of the base routes file.
*
* @var string
*/
protected $base;
/**
* The directory containing nested route files.
*
* @var string
*/
protected $nest;
/**
* A cache for all of the routes defined for the entire application.
*
* @var array
*/
protected $everything;
/**
* Create a new route loader instance.
*
* @param string $base
* @param string $nest
* @return void
*/
public function __construct($base, $nest)
{
$this->base = $base;
$this->nest = $nest;
}
/**
* Load the applicable routes for a given URI.
*
* @param string $uri
* @return array
*/
public function load($uri)
{
$routes = (file_exists($path = $this->base.'routes'.EXT)) ? require $path : array();
return array_merge($this->nested(Arr::without(explode('/', $uri), array(''))), $routes);
}
/**
* Get the appropriate routes from the routes directory for a given URI.
*
* @param array $segments
* @return array
*/
protected function nested($segments)
{
// Work backwards through the URI segments until we find the deepest possible
// matching route directory. Once we find it, we will return those routes.
foreach (array_reverse($segments, true) as $key => $value)
{
if (file_exists($path = $this->nest.implode('/', array_slice($segments, 0, $key + 1)).EXT))
{
return require $path;
}
elseif (file_exists($path = str_replace('.php', '/routes.php', $path)))
{
return require $path;
}
}
return array();
}
/**
* Get every route defined for the application.
*
* @return array
*/
public function everything()
{
if ( ! is_null($this->everything)) return $this->everything;
$routes = array();
// Since route files can be nested deep within the route directory, we need to
// recursively spin through the directory to find every file.
$directoryIterator = new \RecursiveDirectoryIterator($this->nest);
$recursiveIterator = new \RecursiveIteratorIterator($directoryIterator, \RecursiveIteratorIterator::SELF_FIRST);
foreach ($recursiveIterator as $file)
{
if (filetype($file) === 'file')
{
$routes = array_merge(require $file, $routes);
}
}
return $this->everything = $routes;
}
}

View File

@@ -95,11 +95,13 @@ class Route {
}
// Otherwise, we will assume the route is an array and will return the first value with
// a key of "do", or the first instance of a Closure. If the value is a string, the route
// is delegating the responsibility for handling the request to a controller.
// a key of "delegate", or the first instance of a Closure. If the value is a string, the
// route is delegating the responsibility for handling the request to a controller.
elseif (is_array($this->callback))
{
return Arr::first($this->callback, function($key, $value) {return $key == 'do' or $value instanceof Closure;});
$callback = Arr::first($this->callback, function($key, $value) {return $key == 'delegate' or $value instanceof Closure;});
return ($callback instanceof Closure) ? call_user_func_array($callback, $this->parameters) : new Delegate($callback);
}
// If a value defined for a route is a string, it means the route is delegating control
@@ -107,7 +109,7 @@ class Route {
// for the route caller to parse and delegate.
elseif (is_string($this->callback))
{
return $this->callback;
return new Delegate($this->callback);
}
}

View File

@@ -5,11 +5,11 @@ use Laravel\Request;
class Router {
/**
* All of the routes available to the router.
* The route loader instance.
*
* @var array
* @var Loader
*/
public $routes;
public $loader;
/**
* The named routes that have been found so far.
@@ -28,13 +28,13 @@ class Router {
/**
* Create a new router for a request method and URI.
*
* @param array $routes
* @param Loader $loader
* @param string $controllers
* @return void
*/
public function __construct($routes, $controllers)
public function __construct(Loader $loader, $controllers)
{
$this->routes = $routes;
$this->loader = $loader;
$this->controllers = $controllers;
}
@@ -50,7 +50,7 @@ class Router {
{
if (array_key_exists($name, $this->names)) return $this->names[$name];
$arrayIterator = new \RecursiveArrayIterator($this->routes);
$arrayIterator = new \RecursiveArrayIterator($this->loader->everything());
$recursiveIterator = new \RecursiveIteratorIterator($arrayIterator);
@@ -75,18 +75,20 @@ class Router {
*/
public function route(Request $request)
{
$routes = $this->loader->load($request->uri());
// Put the request method and URI in route form. Routes begin with
// the request method and a forward slash.
$destination = $request->method().' /'.trim($request->uri(), '/');
// 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[$destination]))
if (isset($routes[$destination]))
{
return $request->route = new Route($destination, $this->routes[$destination], array());
return $request->route = new Route($destination, $routes[$destination], array());
}
foreach ($this->routes as $keys => $callback)
foreach ($routes as $keys => $callback)
{
// Only check routes that have multiple URIs or wildcards.
// Other routes would have been caught by the check for literal matches.