Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Starting refactoring of Route methods into a separate class. Tests ad…

…ded.
  • Loading branch information...
commit fec83abd90863dccceae467c7275f51dde9d76ef 1 parent 2669b61
@markstory markstory authored
Showing with 305 additions and 13 deletions.
  1. +212 −12 cake/libs/router.php
  2. +93 −1 cake/tests/cases/libs/router.test.php
View
224 cake/libs/router.php
@@ -99,18 +99,6 @@ class Router {
var $__currentRoute = array();
/**
- * HTTP header shortcut map. Used for evaluating header-based route expressions.
- *
- * @var array
- * @access private
- */
- var $__headerMap = array(
- 'type' => 'content_type',
- 'method' => 'request_method',
- 'server' => 'server_name'
- );
-
-/**
* Default HTTP request method => controller action map.
*
* @var array
@@ -126,6 +114,18 @@ class Router {
);
/**
+ * HTTP header shortcut map. Used for evaluating header-based route expressions.
+ *
+ * @var array
+ * @access private
+ */
+ var $__headerMap = array(
+ 'type' => 'content_type',
+ 'method' => 'request_method',
+ 'server' => 'server_name'
+ );
+
+/**
* List of resource-mapped controllers
*
* @var array
@@ -1428,4 +1428,204 @@ function getArgs($args, $options = array()) {
return compact('pass', 'named');
}
}
+
+/**
+ * A single Route used by the Router to connect requests to
+ * parameter maps.
+ *
+ * Not normally created as a standalone. Use Router::connect() to create
+ * Routes for your application.
+ *
+ * @package cake.libs
+ * @since 1.3.0
+ * @see Router::connect
+ */
+class RouterRoute {
+/**
+ * An array of named segments in a Route.
+ * `/:controller/:action/:id` has 3 named elements
+ *
+ * @var array
+ **/
+ var $names = array();
+/**
+ * An array of additional parameters for the Route.
+ *
+ * @var array
+ **/
+ var $params = array();
+/**
+ * Default parameters for a Route
+ *
+ * @var array
+ */
+ var $defaults = array();
+/**
+ * The routes pattern string.
+ *
+ * @var string
+ **/
+ var $pattern = null;
+/**
+ * The compiled route regular expresssion
+ *
+ * @var string
+ **/
+ var $_compiledRoute = null;
+/**
+ * HTTP header shortcut map. Used for evaluating header-based route expressions.
+ *
+ * @var array
+ * @access private
+ */
+ var $__headerMap = array(
+ 'type' => 'content_type',
+ 'method' => 'request_method',
+ 'server' => 'server_name'
+ );
+/**
+ * Constructor for a Route
+ *
+ * @param string $pattern Pattern string with parameter placeholders
+ * @param array $defaults Array of defaults for the route.
+ * @param string $params Array of parameters and additional options for the Route
+ * @return void
+ */
+ function RouterRoute($pattern, $defaults = array(), $params = array()) {
+ $this->pattern = $pattern;
+ $this->defaults = (array)$defaults;
+ $this->params = (array)$params;
+ }
+/**
+ * Check if a Route has been compiled into a regular expression.
+ *
+ * @return boolean
+ **/
+ function compiled() {
+ return !empty($this->_compiledRoute);
+ }
+/**
+ * Compiles the routes regular expression. Modifies defaults property so all necessary keys are set
+ * and populates $this->names with the named routing elements.
+ *
+ * @return array Returns a string regular expression of the compiled route.
+ * @access public
+ */
+ function compile() {
+ $this->_writeRoute($this->pattern, $this->defaults, $this->params);
+ $this->defaults += array('plugin' => null, 'controller' => null);
+ return $this->_compiledRoute;
+ }
+/**
+ * Builds a route regular expression
+ *
+ * @param string $route An empty string, or a route string "/"
+ * @param array $default NULL or an array describing the default route
+ * @param array $params An array matching the named elements in the route to regular expressions which that element should match.
+ * @return array
+ * @access protected
+ */
+ function _writeRoute($route, $default, $params) {
+ if (empty($route) || ($route === '/')) {
+ return array('/^[\/]*$/', array());
+ }
+ $names = array();
+ $elements = explode('/', $route);
+
+ foreach ($elements as $element) {
+ if (empty($element)) {
+ continue;
+ }
+ $q = null;
+ $element = trim($element);
+ $namedParam = strpos($element, ':') !== false;
+
+ if ($namedParam && preg_match('/^:([^:]+)$/', $element, $r)) {
+ if (isset($params[$r[1]])) {
+ if ($r[1] != 'plugin' && array_key_exists($r[1], $default)) {
+ $q = '?';
+ }
+ $parsed[] = '(?:/(' . $params[$r[1]] . ')' . $q . ')' . $q;
+ } else {
+ $parsed[] = '(?:/([^\/]+))?';
+ }
+ $names[] = $r[1];
+ } elseif ($element === '*') {
+ $parsed[] = '(?:/(.*))?';
+ } else if ($namedParam && preg_match_all('/(?!\\\\):([a-z_0-9]+)/i', $element, $matches)) {
+ $matchCount = count($matches[1]);
+
+ foreach ($matches[1] as $i => $name) {
+ $pos = strpos($element, ':' . $name);
+ $before = substr($element, 0, $pos);
+ $element = substr($element, $pos + strlen($name) + 1);
+ $after = null;
+
+ if ($i + 1 === $matchCount && $element) {
+ $after = preg_quote($element);
+ }
+
+ if ($i === 0) {
+ $before = '/' . $before;
+ }
+ $before = preg_quote($before, '#');
+
+ if (isset($params[$name])) {
+ if (isset($default[$name]) && $name != 'plugin') {
+ $q = '?';
+ }
+ $parsed[] = '(?:' . $before . '(' . $params[$name] . ')' . $q . $after . ')' . $q;
+ } else {
+ $parsed[] = '(?:' . $before . '([^\/]+)' . $after . ')?';
+ }
+ $names[] = $name;
+ }
+ } else {
+ $parsed[] = '/' . $element;
+ }
+ }
+ $this->_compiledRoute = '#^' . join('', $parsed) . '[\/]*$#';
+ $this->names = $names;
+ }
+
+/**
+ * Checks to see if the given URL matches the given route
+ *
+ * @param array $route
+ * @param string $url
+ * @return mixed Boolean false on failure, otherwise array
+ */
+ function match($url) {
+ if (!$this->compiled()) {
+ $this->compile();
+ }
+
+ if (!preg_match($this->_compiledRoute, $url, $r)) {
+ return false;
+ } else {
+ foreach ($this->defaults as $key => $val) {
+ if ($key{0} === '[' && preg_match('/^\[(\w+)\]$/', $key, $header)) {
+ if (isset($this->__headerMap[$header[1]])) {
+ $header = $this->__headerMap[$header[1]];
+ } else {
+ $header = 'http_' . $header[1];
+ }
+
+ $val = (array)$val;
+ $h = false;
+
+ foreach ($val as $v) {
+ if (env(strtoupper($header)) === $v) {
+ $h = true;
+ }
+ }
+ if (!$h) {
+ return false;
+ }
+ }
+ }
+ }
+ return $r;
+ }
+}
?>
View
94 cake/tests/cases/libs/router.test.php
@@ -1872,7 +1872,7 @@ function testStripPlugin() {
* testCurentRoute
*
* This test needs some improvement and actual requestAction() usage
- *
+ *
* @return void
* @access public
*/
@@ -1938,4 +1938,96 @@ function testGetParams() {
$this->assertEqual(Router::getparams(true), $expected);
}
}
+
+/**
+ * Test case for RouterRoute
+ *
+ * @package cake.tests.cases.libs.
+ **/
+class RouterRouteTestCase extends CakeTestCase {
+/**
+ * setUp method
+ *
+ * @access public
+ * @return void
+ */
+ function setUp() {
+ $this->_routing = Configure::read('Routing');
+ Configure::write('Routing', array('admin' => null, 'prefixes' => array()));
+ Router::reload();
+ }
+
+/**
+ * end the test and reset the environment
+ *
+ * @return void
+ **/
+ function endTest() {
+ Configure::write('Routing', $this->_routing);
+ }
+
+/**
+ * Test the construction of a RouterRoute
+ *
+ * @return void
+ **/
+ function testConstruction() {
+ $route =& new RouterRoute('/:controller/:action/:id', array('controller' => 'posts', 'id' => null), array('id' => '[0-9]+'));
+
+ $this->assertEqual($route->pattern, '/:controller/:action/:id');
+ $this->assertEqual($route->defaults, array('controller' => 'posts', 'id' => null));
+ $this->assertEqual($route->params, array('id' => '[0-9]+'));
+ $this->assertFalse($route->compiled());
+ }
+
+/**
+ * test Route compiling.
+ *
+ * @return void
+ **/
+ function testCompiling() {
+ extract(Router::getNamedExpressions());
+
+ $route =& new RouterRoute('/:controller/:action/:id', array('controller' => 'posts', 'id' => null), array('id' => '[0-9]+'));
+ $result = $route->compile();
+ $expected = '#^(?:/([^\/]+))?(?:/([^\/]+))?(?:/([0-9]+)?)?[\/]*$#';
+ $this->assertEqual($result, $expected);
+
+ $route = new RouterRoute('/:controller/:action/:id', array('controller' => 'testing4', 'id' => null), array('id' => $ID));
+ $result = $route->compile();
+ $expected = '#^(?:/([^\/]+))?(?:/([^\/]+))?(?:/([0-9]+)?)?[\/]*$#';
+ $this->assertEqual($result, $expected);
+
+ $this->assertEqual($route->names, array('controller', 'action', 'id'));
+
+ $route =& new RouterRoute('/:controller/:action/:id', array('controller' => 'testing4'), array('id' => $ID));
+ $result = $route->compile();
+ $expected = '#^(?:/([^\/]+))?(?:/([^\/]+))?(?:/([0-9]+))[\/]*$#';
+ $this->assertEqual($result, $expected);
+
+ $this->assertEqual($route->names, array('controller', 'action', 'id'));
+
+ $route =& new RouterRoute('/posts/foo:id');
+ $result = $route->compile();
+ $expected = '#^/posts(?:/foo([^\/]+))?[\/]*$#';
+ $this->assertEqual($result, $expected);
+
+ $this->assertEqual($route->names, array('id'));
+
+ foreach (array(':', '@', ';', '$', '-') as $delim) {
+ $route =& new RouterRoute('/posts/:id'.$delim.':title');
+ $result = $route->compile();
+ $expected = '#^/posts(?:/([^\/]+))?(?:'.preg_quote($delim, '#').'([^\/]+))?[\/]*$#';
+ $this->assertEqual($result, $expected);
+
+ $this->assertEqual($route->names, array('id', 'title'));
+ }
+
+ $route =& new RouterRoute('/posts/:id::title/:year');
+ $result = $route->compile();
+ $this->assertEqual($result, '#^/posts(?:/([^\/]+))?(?:\\:([^\/]+))?(?:/([^\/]+))?[\/]*$#');
+ $this->assertEqual($route->names, array('id', 'title', 'year'));
+ }
+}
+
?>
Please sign in to comment.
Something went wrong with that request. Please try again.