Router.php (7934B)
1 <?php 2 /** 3 * Slim - a micro PHP 5 framework 4 * 5 * @author Josh Lockhart <info@slimframework.com> 6 * @copyright 2011 Josh Lockhart 7 * @link http://www.slimframework.com 8 * @license http://www.slimframework.com/license 9 * @version 2.4.2 10 * @package Slim 11 * 12 * MIT LICENSE 13 * 14 * Permission is hereby granted, free of charge, to any person obtaining 15 * a copy of this software and associated documentation files (the 16 * "Software"), to deal in the Software without restriction, including 17 * without limitation the rights to use, copy, modify, merge, publish, 18 * distribute, sublicense, and/or sell copies of the Software, and to 19 * permit persons to whom the Software is furnished to do so, subject to 20 * the following conditions: 21 * 22 * The above copyright notice and this permission notice shall be 23 * included in all copies or substantial portions of the Software. 24 * 25 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 27 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 29 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 30 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 31 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 32 */ 33 namespace Slim; 34 35 /** 36 * Router 37 * 38 * This class organizes, iterates, and dispatches \Slim\Route objects. 39 * 40 * @package Slim 41 * @author Josh Lockhart 42 * @since 1.0.0 43 */ 44 class Router 45 { 46 /** 47 * @var Route The current route (most recently dispatched) 48 */ 49 protected $currentRoute; 50 51 /** 52 * @var array Lookup hash of all route objects 53 */ 54 protected $routes; 55 56 /** 57 * @var array Lookup hash of named route objects, keyed by route name (lazy-loaded) 58 */ 59 protected $namedRoutes; 60 61 /** 62 * @var array Array of route objects that match the request URI (lazy-loaded) 63 */ 64 protected $matchedRoutes; 65 66 /** 67 * @var array Array containing all route groups 68 */ 69 protected $routeGroups; 70 71 /** 72 * Constructor 73 */ 74 public function __construct() 75 { 76 $this->routes = array(); 77 $this->routeGroups = array(); 78 } 79 80 /** 81 * Get Current Route object or the first matched one if matching has been performed 82 * @return \Slim\Route|null 83 */ 84 public function getCurrentRoute() 85 { 86 if ($this->currentRoute !== null) { 87 return $this->currentRoute; 88 } 89 90 if (is_array($this->matchedRoutes) && count($this->matchedRoutes) > 0) { 91 return $this->matchedRoutes[0]; 92 } 93 94 return null; 95 } 96 97 /** 98 * Return route objects that match the given HTTP method and URI 99 * @param string $httpMethod The HTTP method to match against 100 * @param string $resourceUri The resource URI to match against 101 * @param bool $reload Should matching routes be re-parsed? 102 * @return array[\Slim\Route] 103 */ 104 public function getMatchedRoutes($httpMethod, $resourceUri, $reload = false) 105 { 106 if ($reload || is_null($this->matchedRoutes)) { 107 $this->matchedRoutes = array(); 108 foreach ($this->routes as $route) { 109 if (!$route->supportsHttpMethod($httpMethod) && !$route->supportsHttpMethod("ANY")) { 110 continue; 111 } 112 113 if ($route->matches($resourceUri)) { 114 $this->matchedRoutes[] = $route; 115 } 116 } 117 } 118 119 return $this->matchedRoutes; 120 } 121 122 /** 123 * Add a route object to the router 124 * @param \Slim\Route $route The Slim Route 125 */ 126 public function map(\Slim\Route $route) 127 { 128 list($groupPattern, $groupMiddleware) = $this->processGroups(); 129 130 $route->setPattern($groupPattern . $route->getPattern()); 131 $this->routes[] = $route; 132 133 134 foreach ($groupMiddleware as $middleware) { 135 $route->setMiddleware($middleware); 136 } 137 } 138 139 /** 140 * A helper function for processing the group's pattern and middleware 141 * @return array Returns an array with the elements: pattern, middlewareArr 142 */ 143 protected function processGroups() 144 { 145 $pattern = ""; 146 $middleware = array(); 147 foreach ($this->routeGroups as $group) { 148 $k = key($group); 149 $pattern .= $k; 150 if (is_array($group[$k])) { 151 $middleware = array_merge($middleware, $group[$k]); 152 } 153 } 154 return array($pattern, $middleware); 155 } 156 157 /** 158 * Add a route group to the array 159 * @param string $group The group pattern (ie. "/books/:id") 160 * @param array|null $middleware Optional parameter array of middleware 161 * @return int The index of the new group 162 */ 163 public function pushGroup($group, $middleware = array()) 164 { 165 return array_push($this->routeGroups, array($group => $middleware)); 166 } 167 168 /** 169 * Removes the last route group from the array 170 * @return bool True if successful, else False 171 */ 172 public function popGroup() 173 { 174 return (array_pop($this->routeGroups) !== null); 175 } 176 177 /** 178 * Get URL for named route 179 * @param string $name The name of the route 180 * @param array $params Associative array of URL parameter names and replacement values 181 * @throws \RuntimeException If named route not found 182 * @return string The URL for the given route populated with provided replacement values 183 */ 184 public function urlFor($name, $params = array()) 185 { 186 if (!$this->hasNamedRoute($name)) { 187 throw new \RuntimeException('Named route not found for name: ' . $name); 188 } 189 $search = array(); 190 foreach ($params as $key => $value) { 191 $search[] = '#:' . preg_quote($key, '#') . '\+?(?!\w)#'; 192 } 193 $pattern = preg_replace($search, $params, $this->getNamedRoute($name)->getPattern()); 194 195 //Remove remnants of unpopulated, trailing optional pattern segments, escaped special characters 196 return preg_replace('#\(/?:.+\)|\(|\)|\\\\#', '', $pattern); 197 } 198 199 /** 200 * Add named route 201 * @param string $name The route name 202 * @param \Slim\Route $route The route object 203 * @throws \RuntimeException If a named route already exists with the same name 204 */ 205 public function addNamedRoute($name, \Slim\Route $route) 206 { 207 if ($this->hasNamedRoute($name)) { 208 throw new \RuntimeException('Named route already exists with name: ' . $name); 209 } 210 $this->namedRoutes[(string) $name] = $route; 211 } 212 213 /** 214 * Has named route 215 * @param string $name The route name 216 * @return bool 217 */ 218 public function hasNamedRoute($name) 219 { 220 $this->getNamedRoutes(); 221 222 return isset($this->namedRoutes[(string) $name]); 223 } 224 225 /** 226 * Get named route 227 * @param string $name 228 * @return \Slim\Route|null 229 */ 230 public function getNamedRoute($name) 231 { 232 $this->getNamedRoutes(); 233 if ($this->hasNamedRoute($name)) { 234 return $this->namedRoutes[(string) $name]; 235 } else { 236 return null; 237 } 238 } 239 240 /** 241 * Get named routes 242 * @return \ArrayIterator 243 */ 244 public function getNamedRoutes() 245 { 246 if (is_null($this->namedRoutes)) { 247 $this->namedRoutes = array(); 248 foreach ($this->routes as $route) { 249 if ($route->getName() !== null) { 250 $this->addNamedRoute($route->getName(), $route); 251 } 252 } 253 } 254 255 return new \ArrayIterator($this->namedRoutes); 256 } 257 }