Files
lgp-admin-plus-api/laravel/routing/router.php

304 lines
8.8 KiB
PHP
Raw Normal View History

<?php namespace Laravel\Routing; use Closure, Laravel\Str, Laravel\Bundle;
2011-06-08 23:45:08 -05:00
class Router {
/**
2012-01-16 13:59:24 -06:00
* All of the routes that have been registered.
2011-08-23 21:04:40 -05:00
*
* @var array
2011-08-23 21:04:40 -05:00
*/
2012-01-16 13:59:24 -06:00
public static $routes = array();
2011-08-23 21:04:40 -05:00
2011-08-26 21:42:04 -05:00
/**
2012-01-16 13:59:24 -06:00
* All of the route names that have been matched with URIs.
2011-08-26 21:42:04 -05:00
*
2012-01-16 13:59:24 -06:00
* @var array
2011-08-26 21:42:04 -05:00
*/
2012-01-16 13:59:24 -06:00
public static $names = array();
2011-08-26 21:42:04 -05:00
/**
* The wildcard patterns supported by the router.
*
* @var array
*/
2012-01-16 13:59:24 -06:00
public static $patterns = array(
2011-10-26 21:21:31 -05:00
'(:num)' => '([0-9]+)',
'(:any)' => '([a-zA-Z0-9\.\-_]+)',
);
/**
* The optional wildcard patterns supported by the router.
*
* @var array
*/
2012-01-16 13:59:24 -06:00
public static $optional = array(
'/(:num?)' => '(?:/([0-9]+)',
'/(:any?)' => '(?:/([a-zA-Z0-9\.\-_]+)',
);
/**
2012-01-16 13:59:24 -06:00
* Register a route with the router.
2011-06-08 23:45:08 -05:00
*
2012-01-16 13:59:24 -06:00
* <code>
* // Register a route with the router
* Router::register('GET /', function() {return 'Home!';});
*
* // Register a route that handles multiple URIs with the router
* Router::register(array('GET /', 'GET /home'), function() {return 'Home!';});
* </code>
*
* @param string|array $route
* @param string $action
* @return void
2011-06-08 23:45:08 -05:00
*/
2012-01-16 13:59:24 -06:00
public static function register($route, $action)
2011-06-08 23:45:08 -05:00
{
2012-01-16 13:59:24 -06:00
foreach ((array) $route as $uri)
{
// If the action is a string, it is a pointer to a controller, so we
// need to add it to the action array as a "uses" clause, which will
// indicate to the route to call the controller when the route is
// executed by the application.
if (is_string($action))
{
static::$routes[$uri]['uses'] = $action;
}
// If the action is not a string, we can just simply cast it as an
// array, then we will add all of the URIs to the action array as
// the "handes" clause so we can easily check which URIs are
// handled by the route instance.
else
{
if ($action instanceof Closure) $action = array($action);
static::$routes[$uri] = (array) $action;
}
static::$routes[$uri]['handles'] = (array) $route;
}
2011-06-08 23:45:08 -05:00
}
/**
2012-01-26 13:35:29 -06:00
* Find a route by the route's assigned name.
*
* @param string $name
* @return array
*/
2012-01-16 13:59:24 -06:00
public static function find($name)
{
2012-01-16 13:59:24 -06:00
if (isset(static::$names[$name])) return static::$names[$name];
2012-01-16 13:59:24 -06:00
// If no route names have been found at all, we will assume no reverse
// routing has been done, and we will load the routes file for all of
// the bundle that are installed for the application.
if (count(static::$names) == 0)
{
2012-01-26 17:01:17 -06:00
foreach (Bundle::names() as $bundle)
{
2012-01-16 13:59:24 -06:00
Bundle::routes($bundle);
}
}
// To find a named route, we will iterate through every route defined
// for the application. We will cache the routes by name so we can
// load them very quickly if we need to find them a second time.
foreach (static::$routes as $key => $value)
{
if (isset($value['name']) and $value['name'] == $name)
{
return static::$names[$name] = array($key => $value);
}
}
2011-07-09 23:41:27 -05:00
}
/**
2012-01-26 17:01:17 -06:00
* Search the routes for the route matching a method and URI.
*
2011-10-29 22:31:50 -05:00
* @param string $method
* @param string $uri
* @return Route
*/
2012-01-16 13:59:24 -06:00
public static function route($method, $uri)
{
// First we will make sure the bundle that handles the given URI has
// been started for the current request. Bundles may handle any URI
// as long as it begins with the string in the "handles" item of
// the bundle's registration array.
Bundle::start($bundle = Bundle::handles($uri));
// All route URIs begin with the request method and have a leading
2012-01-16 13:59:24 -06:00
// slash before the URI. We'll put the request method and URI in
// that format so we can easily check for literal matches.
$destination = $method.' /'.trim($uri, '/');
2011-08-23 21:04:40 -05:00
2012-01-16 13:59:24 -06:00
if (array_key_exists($destination, static::$routes))
{
2012-01-16 13:59:24 -06:00
return new Route($destination, static::$routes[$destination], array());
}
2012-01-16 13:59:24 -06:00
// If we can't find a literal match, we'll iterate through all of
// the registered routes to find a matching route that uses some
// regular expressions or wildcards.
if ( ! is_null($route = static::match($destination)))
{
return $route;
}
// If the bundle handling the request is not the default bundle,
// we want to remove the root "handles" string from the URI so
// it will not interfere with searching for a controller.
//
// If we left it on the URI, the root controller for the bundle
// would need to be nested in directories matching the clause.
// This will not intefere with the Route::handles method
// as the destination is used to set the route's URIs.
if ($bundle !== DEFAULT_BUNDLE)
{
$uri = str_replace(Bundle::get($bundle)->handles, '', $uri);
$uri = ltrim($uri, '/');
}
2012-01-27 08:47:12 -06:00
$segments = Str::segments($uri);
return static::controller($bundle, $method, $destination, $segments);
}
/**
* Iterate through every route to find a matching route.
*
* @param string $destination
* @return Route
*/
protected static function match($destination)
{
2012-01-16 13:59:24 -06:00
foreach (static::$routes as $route => $action)
2011-10-15 14:04:11 -05:00
{
// We only need to check routes with regular expressions since
// all other routes would have been able to be caught by the
// check for literal matches we just did.
2012-01-16 13:59:24 -06:00
if (strpos($route, '(') !== false)
2011-10-15 14:04:11 -05:00
{
2012-01-26 13:35:29 -06:00
$pattern = '#^'.static::wildcards($route).'$#';
// If we get a match, we'll return the route and slice off
// the first parameter match, as preg_match sets the first
// array item to the full-text match.
2012-01-26 13:35:29 -06:00
if (preg_match($pattern, $destination, $parameters))
2012-01-16 13:59:24 -06:00
{
return new Route($route, $action, array_slice($parameters, 1));
}
2011-10-15 14:04:11 -05:00
}
}
}
/**
* Attempt to find a controller for the incoming request.
*
2012-01-16 13:59:24 -06:00
* @param string $bundle
* @param string $method
* @param string $destination
2012-01-16 13:59:24 -06:00
* @param array $segments
* @return Route
*/
2012-01-16 13:59:24 -06:00
protected static function controller($bundle, $method, $destination, $segments)
{
2012-01-16 13:59:24 -06:00
if (count($segments) == 0)
{
2012-01-26 17:01:17 -06:00
$uri = '/';
2012-01-16 13:59:24 -06:00
2012-01-26 17:01:17 -06:00
// If the bundle is not the default bundle for the application, we'll
// set the root URI as the root URI registered with the bundle in the
// bundle configuration file for the application. It's registered in
// the bundle configuration using the "handles" clause.
if ($bundle !== DEFAULT_BUNDLE)
{
$uri = '/'.Bundle::get($bundle)->handles;
}
// We'll generate a default "uses" clause for the route action that
// points to the default controller and method for the bundle so
2012-01-27 09:31:16 -06:00
// that the route will execute the default.
2012-01-16 13:59:24 -06:00
$action = array('uses' => Bundle::prefix($bundle).'home@index');
return new Route($method.' '.$uri, $action);
}
$directory = Bundle::path($bundle).'controllers/';
2012-01-27 09:31:16 -06:00
if ( ! is_null($key = static::locate($segments, $directory)))
{
2011-11-21 19:09:48 -06:00
// First, we'll extract the controller name, then, since we need
// to extract the method and parameters, we will remove the name
// of the controller from the URI. Then we can shift the method
// off of the array of segments. Any remaining segments are the
2012-01-27 09:31:16 -06:00
// parameters for the method.
$controller = implode('.', array_slice($segments, 0, $key));
$segments = array_slice($segments, $key);
$method = (count($segments) > 0) ? array_shift($segments) : 'index';
2012-01-16 13:59:24 -06:00
// We need to grab the prefix to the bundle so we can prefix
// the route identifier with it. This informs the controller
// class out of which bundle the controller instance should
// be resolved when it is needed by the application.
$prefix = Bundle::prefix($bundle);
$action = array('uses' => $prefix.$controller.'@'.$method);
return new Route($destination, $action, $segments);
}
}
/**
2012-01-27 09:31:16 -06:00
* Locate the URI segment matching a controller name.
*
2012-01-16 13:59:24 -06:00
* @param string $directory
* @param array $segments
* @return int
*/
2012-01-27 09:31:16 -06:00
protected static function locate($segments, $directory)
{
for ($i = count($segments) - 1; $i >= 0; $i--)
{
// To find the proper controller, we need to iterate backwards through
// the URI segments and take the first file that matches. That file
// should be the deepest possible controller matched by the URI.
if (file_exists($directory.implode('/', $segments).EXT))
{
return $i + 1;
}
// If a controller did not exist for the segments, we will pop
// the last segment off of the array so that on the next run
// through the loop we'll check one folder up from the one
// we checked on this iteration.
array_pop($segments);
}
}
/**
2012-01-27 08:47:12 -06:00
* Translate route URI wildcards into regular expressions.
*
* @param string $key
* @return string
*/
2012-01-16 13:59:24 -06:00
protected static function wildcards($key)
{
2012-01-27 08:47:12 -06:00
list($search, $replace) = array_divide(static::$optional);
2011-07-29 22:56:18 -05:00
// For optional parameters, first translate the wildcards to their
2012-01-16 13:59:24 -06:00
// regex equivalent, sans the ")?" ending. We'll add the endings
2011-07-29 22:56:18 -05:00
// back on after we know how many replacements we made.
2012-01-27 08:47:12 -06:00
$key = str_replace($search, $replace, $key, $count);
2012-01-27 09:31:16 -06:00
if ($count > 0)
{
$key .= str_repeat(')?', $count);
}
2012-01-27 08:47:12 -06:00
return strtr($key, static::$patterns);
}
2011-06-08 23:45:08 -05:00
}