Taddeus Kroes пре 13 година
родитељ
комит
6c8b446fdd
2 измењених фајлова са 138 додато и 0 уклоњено
  1. 94 0
      router.php
  2. 44 0
      tests/test_router.php

+ 94 - 0
router.php

@@ -0,0 +1,94 @@
+<?php
+/**
+ * Functions for URL routing: given an URL, call the corresponding handler
+ * function (the 'route' to the corresponding output).
+ * 
+ * @author Taddeus Kroes
+ * @version 1.0
+ * @date 14-07-2012
+ */
+
+namespace BasicWeb;
+
+require_once 'base.php';
+
+/**
+ * 
+ * 
+ * <code>
+ * 
+ * </code>
+ * 
+ * @package BasicWeb
+ */
+class Router extends Base {
+	/**
+	 * The regex delimiter that is added to the begin and end of patterns.
+	 * 
+	 * @var string
+	 */
+	const DELIMITER = '%';
+	
+	/**
+	 * An associative array of regex patterns pointing to handler functions.
+	 * 
+	 * @var array
+	 */
+	private $routes = array();
+	
+	/**
+	 * Create a new Router instance.
+	 * 
+	 * @param array $routes An initial list of routes to set.
+	 */
+	function __construct(array $routes=array()) {
+		foreach( $routes as $pattern => $handler )
+			$this->add_route($pattern, $handler);
+	}
+	
+	/**
+	 * Add a route as a (pattern, handler) pair.
+	 * 
+	 * The pattern is regular expression pattern without delimiters. The
+	 * function adds '%^' at the begin and '$%' at the end of the pattern as
+	 * delimiters.
+	 * 
+	 * The handler function must receive no arguments if the regex pattern
+	 * does not contain groups (which are contained in parentheses). If there
+	 * are groups, the matches for these are passed to the handler fucntion in
+	 * an array.
+	 * 
+	 * @param string $pattern A regex pattern to mach URL's against.
+	 * @param mixed $handler The handler function to call when $pattern is matched.
+	 * @throws \InvalidArgumentException If $handler is not callable.
+	 */
+	function add_route($pattern, $handler) {
+		if( !is_callable($handler) )
+			throw new \InvalidArgumentException(sprintf('Handler for patterns "%s" is not callable.', $pattern));
+		
+		$this->routes[self::DELIMITER.'^'.$pattern.'$'.self::DELIMITER] = $handler;
+	}
+	
+	/**
+	 * Call the handler function corresponding to the specified url.
+	 * 
+	 * If any groups are in the matched regex pattern, a list of matches is
+	 * passed to the handler function.
+	 * 
+	 * @param string $url An url to match the saved patterns against.
+	 * @return mixed FALSE if no pattern was matched, the return value of the
+	 *               corresponding handler function otherwise.
+	 */
+	function call_handler($url) {
+		foreach( $this->routes as $pattern => $handler ) {
+			if( preg_match($pattern, $url, $matches) ) {
+				array_shift($matches);
+				return call_user_func_array($handler, $matches);
+			}
+		}
+		
+		return false;
+	}
+}
+
+?>

+ 44 - 0
tests/test_router.php

@@ -0,0 +1,44 @@
+<?php
+
+require_once 'router.php';
+use BasicWeb\Router;
+
+function test_handler_no_args() {
+	return true;
+}
+
+function test_handler_arg($arg) {
+	return $arg;
+}
+
+function test_handler_args($arg0, $arg1) {
+	return $arg1.$arg0;
+}
+
+class RouterTest extends PHPUnit_Framework_TestCase {
+	function setUp() {
+		$this->router = new Router(array(
+			'foo' => 'test_handler_no_args',
+			'(ba[rz])' => 'test_handler_arg',
+			'(ba[rz])(ba[rz])' => 'test_handler_args',
+		));
+	}
+	
+	function test_call_handler_success() {
+		$this->assertEquals($this->router->call_handler('foo'), true);
+		$this->assertEquals($this->router->call_handler('bar'), 'bar');
+		$this->assertEquals($this->router->call_handler('baz'), 'baz');
+		$this->assertEquals($this->router->call_handler('bazbar'), 'barbaz');
+	}
+	
+	function test_call_handler_failure() {
+		$this->assertFalse($this->router->call_handler('barfoo'));
+	}
+	
+	function test_add_route() {
+		$this->router->add_route('(foobar)', 'test_handler_arg');
+		$this->assertEquals($this->router->call_handler('foobar'), 'foobar');
+	}
+}
+
+?>