Updated Route, adding get/set/all methods to act as a singleton location for Route storage. Created initial Request class, the replacement for Router/Input.
This commit is contained in:
parent
020a5dde44
commit
12271c68dc
107
system/classes/request.php
Normal file
107
system/classes/request.php
Normal file
|
@ -0,0 +1,107 @@
|
|||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
|
||||
class Request_Core {
|
||||
|
||||
public static $routes = array();
|
||||
|
||||
public static function factory($uri)
|
||||
{
|
||||
return new Requst($uri);
|
||||
}
|
||||
|
||||
protected static $_instance;
|
||||
|
||||
public static function instance($uri = NULL)
|
||||
{
|
||||
if (Request::$_instance === NULL)
|
||||
{
|
||||
// Create the instance singleton
|
||||
Request::$_instance = new Request($uri);
|
||||
}
|
||||
|
||||
return Request::$_instance;
|
||||
}
|
||||
|
||||
public $route;
|
||||
|
||||
public $status = 200;
|
||||
public $response = '';
|
||||
|
||||
public $abort = FALSE;
|
||||
|
||||
protected $_uri;
|
||||
protected $_params;
|
||||
protected $_get;
|
||||
protected $_post;
|
||||
|
||||
public function __construct($uri, array $get = NULL, array $post = NULL)
|
||||
{
|
||||
// Remove trailing slashes from the URI
|
||||
$uri = trim($uri, '/');
|
||||
|
||||
// Load routes
|
||||
$routes = Route::all();
|
||||
|
||||
foreach ($routes as $name => $route)
|
||||
{
|
||||
if ($params = $route->matches($uri))
|
||||
{
|
||||
$this->route = $route;
|
||||
|
||||
$this->_uri = $uri;
|
||||
$this->_params = $params;
|
||||
|
||||
$this->_get = ($get === NULL) ? $_GET : $get;
|
||||
$this->_post = ($post === NULL) ? $_POST : $get;
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
throw new Exception('Unable to find a route to handle '.$uri);
|
||||
}
|
||||
|
||||
public function get($key, $default = NULL)
|
||||
{
|
||||
return isset($this->_get[$key]) ? $this->_get[$key] : $default;
|
||||
}
|
||||
|
||||
public function post($key, $default = NULL)
|
||||
{
|
||||
return isset($this->_post[$key]) ? $this->_post[$key] : $default;
|
||||
}
|
||||
|
||||
public function param($key, $default = NULL)
|
||||
{
|
||||
return isset($this->_params[$key]) ? $this->_params[$key] : $default;
|
||||
}
|
||||
|
||||
public function process()
|
||||
{
|
||||
$params = $this->_params;
|
||||
|
||||
$controller = 'controller_'.$params['controller'];
|
||||
$action = 'action_'.$params['action'];
|
||||
|
||||
// Remove the controller and action from the params
|
||||
unset($params['controller'], $params['action']);
|
||||
|
||||
// Load the controller
|
||||
$controller = new $controller($this);
|
||||
|
||||
// A new action is about to be run
|
||||
$controller->before();
|
||||
|
||||
if ($this->status === 200)
|
||||
{
|
||||
// Execute the action
|
||||
$controller->$action();
|
||||
|
||||
// The action has been run
|
||||
$controller->after();
|
||||
}
|
||||
|
||||
echo $this->response;
|
||||
}
|
||||
|
||||
} // End Request
|
|
@ -36,26 +36,15 @@
|
|||
*/
|
||||
class Route_Core {
|
||||
|
||||
const REGEX_KEY = ':[a-zA-Z0-9_]++';
|
||||
const REGEX_KEY = '<([a-zA-Z0-9_]++)>';
|
||||
const REGEX_SEGMENT = '[^/.,;?]++';
|
||||
const REGEX_ESCAPE = '[.\\+*?[^\\]${}=!<>|]';
|
||||
const REGEX_ESCAPE = '[.\\+*?[^\\]${}=!|]';
|
||||
|
||||
/**
|
||||
* Returns a new Route object.
|
||||
*
|
||||
* @chainable
|
||||
* @param string route URI
|
||||
* @param array regular expressions for keys
|
||||
* @return Route
|
||||
*/
|
||||
public static function factory($uri, array $regex = array())
|
||||
{
|
||||
return new Route($uri, $regex);
|
||||
}
|
||||
protected static $_routes = array();
|
||||
|
||||
/**
|
||||
* Called when the object is re-constructed from the cache.
|
||||
*
|
||||
*
|
||||
* @param array cached values
|
||||
* @return Route
|
||||
*/
|
||||
|
@ -70,17 +59,52 @@ class Route_Core {
|
|||
return $route;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores a named route and returns it.
|
||||
*
|
||||
* @param string route name
|
||||
* @param string URI pattern
|
||||
* @param array regex patterns for route keys
|
||||
* @return Route
|
||||
*/
|
||||
public static function set($name, $uri, array $regex = NULL)
|
||||
{
|
||||
return Route::$_routes[$name] = new Route($uri, $regex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a named route.
|
||||
*
|
||||
* @param string route name
|
||||
* @return Route
|
||||
* @return FALSE when no route is found
|
||||
*/
|
||||
public static function get($name)
|
||||
{
|
||||
return isset(Route::$_routes[$name]) ? Route::$_routes[$name] : FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves all named routes, with the default route last.
|
||||
*
|
||||
* @return array named routes
|
||||
*/
|
||||
public function all()
|
||||
{
|
||||
return Route::$_routes;
|
||||
}
|
||||
|
||||
// Route URI string
|
||||
protected $uri = '';
|
||||
protected $_uri = '';
|
||||
|
||||
// Regular expressions for route keys
|
||||
protected $regex = array();
|
||||
protected $_regex = array();
|
||||
|
||||
// Default values for route keys
|
||||
protected $defaults = array('method' => 'index');
|
||||
protected $_defaults = array('method' => 'index');
|
||||
|
||||
// Compiled regex cache
|
||||
protected $compiled;
|
||||
protected $_route_regex;
|
||||
|
||||
/**
|
||||
* Creates a new route. Sets the URI and regular expressions for keys.
|
||||
|
@ -88,27 +112,25 @@ class Route_Core {
|
|||
* @param string route URI pattern
|
||||
* @param array key patterns
|
||||
*/
|
||||
public function __construct($uri, array $regex = array())
|
||||
public function __construct($uri, array $regex = NULL)
|
||||
{
|
||||
if ( ! empty($regex))
|
||||
{
|
||||
$this->regex = $regex;
|
||||
}
|
||||
$this->_regex = $regex;
|
||||
|
||||
// Store the routed URI
|
||||
$this->uri = $uri;
|
||||
// Store the URI that this route will match
|
||||
$this->_uri = $uri;
|
||||
|
||||
if (($regex = Kohana::cache('kohana_route_regex_'.$uri)) === NULL)
|
||||
if (($regex = Kohana::cache('kohana_route:'.$uri)) === NULL)
|
||||
{
|
||||
// Compile the complete regex for this uri
|
||||
$regex = $this->compile();
|
||||
$regex = $this->_compile();
|
||||
|
||||
// Cache the compiled regex
|
||||
Kohana::cache('kohana_route_regex_'.$uri, $regex);
|
||||
Kohana::cache('kohana_route:'.$uri, $regex);
|
||||
}
|
||||
|
||||
// Store the compiled regex locally
|
||||
$this->compiled = $regex;
|
||||
$this->_route_regex = $regex;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -121,14 +143,14 @@ class Route_Core {
|
|||
* @param array key values
|
||||
* @return Route
|
||||
*/
|
||||
public function defaults(array $defaults)
|
||||
public function defaults(array $defaults = NULL)
|
||||
{
|
||||
if (empty($defaults['method']))
|
||||
if (empty($defaults['action']))
|
||||
{
|
||||
$defaults['method'] = 'index';
|
||||
$defaults['action'] = 'index';
|
||||
}
|
||||
|
||||
$this->defaults = $defaults;
|
||||
$this->_defaults = $defaults;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
@ -139,7 +161,7 @@ class Route_Core {
|
|||
* boolean FALSE.
|
||||
*
|
||||
* // This route will only match if the :controller, :method, and :id exist
|
||||
* $params = Route::factory(':controller/:method/:id', array('id' => '\d+'))
|
||||
* $params = Route::factory('<controller>/<method>/<id>', array('id' => '\d+'))
|
||||
* ->match('users/edit/10');
|
||||
* // The parameters are now:
|
||||
* // controller = users
|
||||
|
@ -159,36 +181,83 @@ class Route_Core {
|
|||
*/
|
||||
public function matches($uri)
|
||||
{
|
||||
if (preg_match('#'.$this->compiled.'#', $uri, $matches))
|
||||
{
|
||||
$params = array();
|
||||
foreach ($matches as $key => $value)
|
||||
{
|
||||
if (is_int($key))
|
||||
{
|
||||
// Skip all unnamed keys
|
||||
continue;
|
||||
}
|
||||
if ( ! preg_match($this->_route_regex, $uri, $matches))
|
||||
return FALSE;
|
||||
|
||||
// Set the value for all matched keys
|
||||
$params = array();
|
||||
foreach ($matches as $key => $value)
|
||||
{
|
||||
if (is_int($key))
|
||||
{
|
||||
// Skip all unnamed keys
|
||||
continue;
|
||||
}
|
||||
|
||||
// Set the value for all matched keys
|
||||
$params[$key] = $value;
|
||||
}
|
||||
|
||||
foreach ($this->_defaults as $key => $value)
|
||||
{
|
||||
if ( ! isset($params[$key]))
|
||||
{
|
||||
// Set default values for any key that was not matched
|
||||
$params[$key] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($this->defaults as $key => $value)
|
||||
return $params;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a URI for the current route based on the parameters given.
|
||||
*
|
||||
* @param array URI parameters
|
||||
* @return string
|
||||
* @throws Kohana_Exception when the URI will not match the current route
|
||||
*/
|
||||
public function uri(array $params = NULL)
|
||||
{
|
||||
if ($params === NULL)
|
||||
$params = $this->_defaults;
|
||||
|
||||
// Start with the routed URI
|
||||
$uri = $this->_uri;
|
||||
|
||||
if (strpos($uri, '<') === FALSE AND strpos('(', $this->uri) === FALSE)
|
||||
{
|
||||
// This is a static route, no need to replace anything
|
||||
return $uri;
|
||||
}
|
||||
|
||||
if (preg_match_all('#'.Route::REGEX_KEY.'#', $uri, $keys))
|
||||
{
|
||||
foreach ($keys[1] as $key)
|
||||
{
|
||||
if ( ! isset($params[$key]))
|
||||
{
|
||||
// Set default values for any key that was not matched
|
||||
$params[$key] = $value;
|
||||
}
|
||||
$search[] = "<$key>";
|
||||
$replace[] = isset($params[$key]) ? $params[$key] : '';
|
||||
}
|
||||
|
||||
return $params;
|
||||
// Replace all the variable keys in the URI
|
||||
$uri = str_replace($search, $replace, $uri);
|
||||
}
|
||||
else
|
||||
|
||||
if (strpos($uri, '(') !== FALSE)
|
||||
{
|
||||
return FALSE;
|
||||
// Remove all groupings from the URI
|
||||
$uri = str_replace(array('(', ')'), '', $uri);
|
||||
}
|
||||
|
||||
// Trim off extra slashes
|
||||
$uri = rtrim($uri, '/');
|
||||
|
||||
if ( ! preg_match($this->_route_regex, $uri))
|
||||
{
|
||||
// This will generally happen with the user supplies invalid parameters
|
||||
throw new Exception('The generated URI "'.$uri.'" will not be matched by "'.$this->_uri.'"');
|
||||
}
|
||||
|
||||
return $uri;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -197,39 +266,35 @@ class Route_Core {
|
|||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function compile()
|
||||
protected function _compile()
|
||||
{
|
||||
// The URI should be considered literal except for keys and optional parts
|
||||
// Escape everything preg_quote would escape except for : ( )
|
||||
$this->uri = preg_replace('#'.Route::REGEX_ESCAPE.'#', '\\\\$0', $this->uri);
|
||||
// Escape everything preg_quote would escape except for : ( ) < >
|
||||
$regex = preg_replace('#'.Route::REGEX_ESCAPE.'#', '\\\\$0', $this->_uri);
|
||||
|
||||
if (strpos($this->uri, '(') === FALSE)
|
||||
{
|
||||
// No optional parts of the URI
|
||||
$regex = $this->uri;
|
||||
}
|
||||
else
|
||||
if (strpos($regex, '(') !== FALSE)
|
||||
{
|
||||
// Make optional parts of the URI non-capturing and optional
|
||||
$regex = str_replace(array('(', ')'), array('(?:', ')?'), $this->uri);
|
||||
$regex = str_replace(array('(', ')'), array('(?:', ')?'), $regex);
|
||||
}
|
||||
|
||||
// Insert default regex for keys
|
||||
$regex = str_replace(array('<', '>'), array('(?P<', '>'.self::REGEX_SEGMENT.')'), $regex);
|
||||
$regex = str_replace(array('<', '>'), array('(?P<', '>'.Route::REGEX_SEGMENT.')'), $regex);
|
||||
|
||||
// Replace default regex patterns with user-specified patterns
|
||||
if (count($this->regex))
|
||||
if ( ! empty($this->_regex))
|
||||
{
|
||||
$replace = array();
|
||||
foreach ($this->regex as $key => $value)
|
||||
$search = $replace = array();
|
||||
foreach ($this->_regex as $key => $value)
|
||||
{
|
||||
$search = "<$key>".self::REGEX_SEGMENT;
|
||||
$replace[$search] = "<$key>$value";
|
||||
$search[] = "<$key>".Route::REGEX_SEGMENT;
|
||||
$replace[] = "<$key>$value";
|
||||
}
|
||||
$regex = strtr($regex, $replace);
|
||||
|
||||
// Replace the default regex with the user-specified regex
|
||||
$regex = str_replace($search, $replace, $regex);
|
||||
}
|
||||
|
||||
return '^'.$regex.'$';
|
||||
return '#^'.$regex.'$#';
|
||||
}
|
||||
|
||||
} // End Kohana_Route
|
||||
|
|
Loading…
Reference in a new issue