Newer
Older
<?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
*/
* A Router is used to call a handler function with corresponding to an URL.
* Simple example: a website with the pages 'home' and 'contact'.
* <code>
* function home() {
* return 'This is the home page.';
* }
*
* function contact() {
* return 'This is the contact page.';
* }
*
* $router = new Router(array(
* '/home' => 'home',
* '/contact' => 'contact'
* ));
* $response = $router->call_handler('/home'); // 'This is the home page.'
* $response = $router->call_handler('/contact'); // 'This is the contact page.'
* </code>
* You can use regular expression patterns to specify an URL. Any matches are
* function page($pagename) {
* return "This is the $pagename page.";
* }
* $router = new Router(array(
* '/(home|contact)' => 'page'
* ));
* $response = $router->call_handler('/home'); // 'This is the home page.'
* $response = $router->call_handler('/contact'); // 'This is the contact page.'
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
*/
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
Taddeus Kroes
committed
* passed to the handler function. If the handler function returns FALSE,
* the url has not been 'handled' and the next pattern will be checked for
* a match. Otherwise, the return value of the handler function is
* returned as the result.
*
* @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);
Taddeus Kroes
committed
$result = call_user_func_array($handler, $matches);
if( $result !== false )
return $result;
}
}
return false;
}
}
?>