| 1 |
<?php |
|---|
| 2 |
|
|---|
| 3 |
|
|---|
| 4 |
|
|---|
| 5 |
|
|---|
| 6 |
|
|---|
| 7 |
|
|---|
| 8 |
|
|---|
| 9 |
|
|---|
| 10 |
|
|---|
| 11 |
|
|---|
| 12 |
|
|---|
| 13 |
|
|---|
| 14 |
|
|---|
| 15 |
|
|---|
| 16 |
|
|---|
| 17 |
|
|---|
| 18 |
|
|---|
| 19 |
|
|---|
| 20 |
|
|---|
| 21 |
|
|---|
| 22 |
|
|---|
| 23 |
|
|---|
| 24 |
|
|---|
| 25 |
|
|---|
| 26 |
|
|---|
| 27 |
|
|---|
| 28 |
|
|---|
| 29 |
|
|---|
| 30 |
|
|---|
| 31 |
|
|---|
| 32 |
|
|---|
| 33 |
|
|---|
| 34 |
|
|---|
| 35 |
class Router { |
|---|
| 36 |
|
|---|
| 37 |
|
|---|
| 38 |
* Route table |
|---|
| 39 |
* |
|---|
| 40 |
* For a description of the structure, see |
|---|
| 41 |
* {@tutorial PHPonTrax/Router.cls#table the Router tutorial}. |
|---|
| 42 |
* Routes are added by calling {@link connect()} and looked up |
|---|
| 43 |
* by calling {@link find_route()}. |
|---|
| 44 |
* <b>FIXME:</b> Should we have a Route class to describe an |
|---|
| 45 |
* entry in the route table? |
|---|
| 46 |
* @var string[][] |
|---|
| 47 |
*/ |
|---|
| 48 |
private $routes = array(); |
|---|
| 49 |
|
|---|
| 50 |
|
|---|
| 51 |
* Last route found by a call to find_route() |
|---|
| 52 |
* @var string[] |
|---|
| 53 |
*/ |
|---|
| 54 |
private $selected_route = null; |
|---|
| 55 |
|
|---|
| 56 |
|
|---|
| 57 |
* Default route path |
|---|
| 58 |
* |
|---|
| 59 |
* This route path is added to the route table if the table is |
|---|
| 60 |
* empty when find_route() is called. |
|---|
| 61 |
* @var string constant |
|---|
| 62 |
*/ |
|---|
| 63 |
private $default_route_path = ":controller/:action/:id"; |
|---|
| 64 |
|
|---|
| 65 |
|
|---|
| 66 |
* Count of the number of elements in $routes |
|---|
| 67 |
* @var integer |
|---|
| 68 |
*/ |
|---|
| 69 |
public $routes_count = 0; |
|---|
| 70 |
|
|---|
| 71 |
|
|---|
| 72 |
* Accessor method to return contents of $selected_route |
|---|
| 73 |
* @return string[] Contents of $selected_route |
|---|
| 74 |
* @uses $selected_route |
|---|
| 75 |
*/ |
|---|
| 76 |
function get_selected_route() { |
|---|
| 77 |
return $this->selected_route; |
|---|
| 78 |
} |
|---|
| 79 |
|
|---|
| 80 |
|
|---|
| 81 |
* Accessor method to add a route to the route table |
|---|
| 82 |
* |
|---|
| 83 |
* The route is added to the end of |
|---|
| 84 |
* {@link $routes the route table}. If $params is not an array, |
|---|
| 85 |
* NULL is stored in the route parameter area. |
|---|
| 86 |
* @param string $path |
|---|
| 87 |
* @param mixed[] $params |
|---|
| 88 |
* @uses $routes |
|---|
| 89 |
* @uses $routes_count |
|---|
| 90 |
*/ |
|---|
| 91 |
function connect($path, $params = null) { |
|---|
| 92 |
if(!is_array($params)) $params = null; |
|---|
| 93 |
$this->routes[$this->routes_count]['path'] = $path; |
|---|
| 94 |
$this->routes[$this->routes_count]['params'] = $params; |
|---|
| 95 |
$this->routes_count = count($this->routes); |
|---|
| 96 |
} |
|---|
| 97 |
|
|---|
| 98 |
|
|---|
| 99 |
* Find first route in route table with path that matches argument |
|---|
| 100 |
* |
|---|
| 101 |
* First, assure that the route table {@link $routes} has at |
|---|
| 102 |
* least one route by adding |
|---|
| 103 |
* {@link $default_route_path the default route} if the table is |
|---|
| 104 |
* empty. Then search the table to find the first route in the |
|---|
| 105 |
* table whose path matches the argument $url. If $url is an |
|---|
| 106 |
* empty string, it matches a path that is an empty string. |
|---|
| 107 |
* Otherwise, try to match $url to the path part of the table |
|---|
| 108 |
* entry according to |
|---|
| 109 |
* {@link http://www.php.net/manual/en/ref.pcre.php Perl regular expression} |
|---|
| 110 |
* rules. If a matching route is found, return it any to the caller, and |
|---|
| 111 |
* also save a copy in {@link $selected_route}; if no matching |
|---|
| 112 |
* route is found return null. |
|---|
| 113 |
* @param string $url |
|---|
| 114 |
* @uses build_route_regexp() |
|---|
| 115 |
* @uses $default_route_path |
|---|
| 116 |
* @uses $routes |
|---|
| 117 |
* @uses $routes_count |
|---|
| 118 |
* @uses $selected_route |
|---|
| 119 |
* @return mixed Matching route or null. Path is in return['path'], |
|---|
| 120 |
* params in return['params'], |
|---|
| 121 |
*/ |
|---|
| 122 |
function find_route($url) { |
|---|
| 123 |
|
|---|
| 124 |
// ensure at least one route (the default route) exists |
|---|
| 125 |
if($this->routes_count == 0) { |
|---|
| 126 |
$this->connect($this->default_route_path); |
|---|
| 127 |
} |
|---|
| 128 |
|
|---|
| 129 |
$this->selected_route = null; |
|---|
| 130 |
|
|---|
| 131 |
foreach($this->routes as $route) { |
|---|
| 132 |
unset($route_regexp); |
|---|
| 133 |
unset($reg_exp); |
|---|
| 134 |
$route_regexp = $this->build_route_regexp($route['path']); |
|---|
| 135 |
|
|---|
| 136 |
if($url == "" && $route_regexp == "") { |
|---|
| 137 |
|
|---|
| 138 |
$this->selected_route = $route; |
|---|
| 139 |
break; |
|---|
| 140 |
} elseif(preg_match("/$route_regexp/",$url) && $route_regexp != "") { |
|---|
| 141 |
|
|---|
| 142 |
$this->selected_route = $route; |
|---|
| 143 |
break; |
|---|
| 144 |
} elseif($route['path'] == $this->default_route_path) { |
|---|
| 145 |
|
|---|
| 146 |
$this->selected_route = $route; |
|---|
| 147 |
break; |
|---|
| 148 |
} |
|---|
| 149 |
} |
|---|
| 150 |
|
|---|
| 151 |
return $this->selected_route; |
|---|
| 152 |
} |
|---|
| 153 |
|
|---|
| 154 |
/** |
|---|
| 155 |
* Build a regular expression that matches a route |
|---|
| 156 |
* |
|---|
| 157 |
* @todo <b>FIXME:</b> Should this method be private? |
|---|
| 158 |
* @todo <b>FIXME:</b> Shouldn't the regexp match be the same as |
|---|
| 159 |
* for a PHP variable name? '[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*' |
|---|
| 160 |
* @param string $route_path A route path. |
|---|
| 161 |
* @return string Regular expression that matches the route in |
|---|
| 162 |
* $route_path |
|---|
| 163 |
*/ |
|---|
| 164 |
function build_route_regexp($route_path) { |
|---|
| 165 |
|
|---|
| 166 |
|
|---|
| 167 |
$route_regexp = null; |
|---|
| 168 |
|
|---|
| 169 |
if(!is_array($route_path)) { |
|---|
| 170 |
$route_path = explode("/",$route_path); |
|---|
| 171 |
} |
|---|
| 172 |
|
|---|
| 173 |
if(count($route_path) > 0) { |
|---|
| 174 |
foreach($route_path as $path_element) { |
|---|
| 175 |
if(preg_match('/:[a-z0-9_\-]+/',$path_element)) { |
|---|
| 176 |
$reg_exp[] = '[a-z0-9_\-]+'; |
|---|
| 177 |
} else { |
|---|
| 178 |
$reg_exp[] = $path_element; |
|---|
| 179 |
} |
|---|
| 180 |
} |
|---|
| 181 |
if(is_array($reg_exp)) { |
|---|
| 182 |
$route_regexp = "^".implode("\/",$reg_exp)."$"; |
|---|
| 183 |
} |
|---|
| 184 |
} |
|---|
| 185 |
return $route_regexp; |
|---|
| 186 |
} |
|---|
| 187 |
|
|---|
| 188 |
} |
|---|
| 189 |
|
|---|
| 190 |
|
|---|
| 191 |
|
|---|
| 192 |
|
|---|
| 193 |
|
|---|
| 194 |
|
|---|
| 195 |
|
|---|
| 196 |
|
|---|
| 197 |
?> |
|---|