PageRenderTime 26ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/Slim/Route.php

https://bitbucket.org/Maxsy/adapi
PHP | 416 lines | 173 code | 46 blank | 197 comment | 13 complexity | a81a415f0a8c8cb0c98601c3fd2f8440 MD5 | raw file
  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.0.0
  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. * Route
  36. * @package Slim
  37. * @author Josh Lockhart, Thomas Bley
  38. * @since 1.0.0
  39. */
  40. class Route
  41. {
  42. /**
  43. * @var string The route pattern (e.g. "/books/:id")
  44. */
  45. protected $pattern;
  46. /**
  47. * @var mixed The route callable
  48. */
  49. protected $callable;
  50. /**
  51. * @var array Conditions for this route's URL parameters
  52. */
  53. protected $conditions = array();
  54. /**
  55. * @var array Default conditions applied to all route instances
  56. */
  57. protected static $defaultConditions = array();
  58. /**
  59. * @var string The name of this route (optional)
  60. */
  61. protected $name;
  62. /**
  63. * @var array Key-value array of URL parameters
  64. */
  65. protected $params = array();
  66. /**
  67. * @var array value array of URL parameter names
  68. */
  69. protected $paramNames = array();
  70. /**
  71. * @var array key array of URL parameter names with + at the end
  72. */
  73. protected $paramNamesPath = array();
  74. /**
  75. * @var array HTTP methods supported by this Route
  76. */
  77. protected $methods = array();
  78. /**
  79. * @var array[Callable] Middleware to be run before only this route instance
  80. */
  81. protected $middleware = array();
  82. /**
  83. * Constructor
  84. * @param string $pattern The URL pattern (e.g. "/books/:id")
  85. * @param mixed $callable Anything that returns TRUE for is_callable()
  86. */
  87. public function __construct($pattern, $callable)
  88. {
  89. $this->setPattern($pattern);
  90. $this->setCallable($callable);
  91. $this->setConditions(self::getDefaultConditions());
  92. }
  93. /**
  94. * Set default route conditions for all instances
  95. * @param array $defaultConditions
  96. */
  97. public static function setDefaultConditions(array $defaultConditions)
  98. {
  99. self::$defaultConditions = $defaultConditions;
  100. }
  101. /**
  102. * Get default route conditions for all instances
  103. * @return array
  104. */
  105. public static function getDefaultConditions()
  106. {
  107. return self::$defaultConditions;
  108. }
  109. /**
  110. * Get route pattern
  111. * @return string
  112. */
  113. public function getPattern()
  114. {
  115. return $this->pattern;
  116. }
  117. /**
  118. * Set route pattern
  119. * @param string $pattern
  120. */
  121. public function setPattern($pattern)
  122. {
  123. $this->pattern = $pattern;
  124. }
  125. /**
  126. * Get route callable
  127. * @return mixed
  128. */
  129. public function getCallable()
  130. {
  131. return $this->callable;
  132. }
  133. /**
  134. * Set route callable
  135. * @param mixed $callable
  136. * @throws \InvalidArgumentException If argument is not callable
  137. */
  138. public function setCallable($callable)
  139. {
  140. if (!is_callable($callable)) {
  141. throw new \InvalidArgumentException('Route callable must be callable');
  142. }
  143. $this->callable = $callable;
  144. }
  145. /**
  146. * Get route conditions
  147. * @return array
  148. */
  149. public function getConditions()
  150. {
  151. return $this->conditions;
  152. }
  153. /**
  154. * Set route conditions
  155. * @param array $conditions
  156. */
  157. public function setConditions(array $conditions)
  158. {
  159. $this->conditions = $conditions;
  160. }
  161. /**
  162. * Get route name
  163. * @return string|null
  164. */
  165. public function getName()
  166. {
  167. return $this->name;
  168. }
  169. /**
  170. * Set route name
  171. * @param string $name
  172. */
  173. public function setName($name)
  174. {
  175. $this->name = (string) $name;
  176. }
  177. /**
  178. * Get route parameters
  179. * @return array
  180. */
  181. public function getParams()
  182. {
  183. return $this->params;
  184. }
  185. /**
  186. * Set route parameters
  187. * @param array $params
  188. */
  189. public function setParams($params)
  190. {
  191. $this->params = $params;
  192. }
  193. /**
  194. * Get route parameter value
  195. * @param string $index Name of URL parameter
  196. * @return string
  197. * @throws \InvalidArgumentException If route parameter does not exist at index
  198. */
  199. public function getParam($index)
  200. {
  201. if (!isset($this->params[$index])) {
  202. throw new \InvalidArgumentException('Route parameter does not exist at specified index');
  203. }
  204. return $this->params[$index];
  205. }
  206. /**
  207. * Set route parameter value
  208. * @param string $index Name of URL parameter
  209. * @param mixed $value The new parameter value
  210. * @throws \InvalidArgumentException If route parameter does not exist at index
  211. */
  212. public function setParam($index, $value)
  213. {
  214. if (!isset($this->params[$index])) {
  215. throw new \InvalidArgumentException('Route parameter does not exist at specified index');
  216. }
  217. $this->params[$index] = $value;
  218. }
  219. /**
  220. * Add supported HTTP method(s)
  221. */
  222. public function setHttpMethods()
  223. {
  224. $args = func_get_args();
  225. $this->methods = $args;
  226. }
  227. /**
  228. * Get supported HTTP methods
  229. * @return array
  230. */
  231. public function getHttpMethods()
  232. {
  233. return $this->methods;
  234. }
  235. /**
  236. * Append supported HTTP methods
  237. */
  238. public function appendHttpMethods()
  239. {
  240. $args = func_get_args();
  241. $this->methods = array_merge($this->methods, $args);
  242. }
  243. /**
  244. * Append supported HTTP methods (alias for Route::appendHttpMethods)
  245. * @return \Slim\Route
  246. */
  247. public function via()
  248. {
  249. $args = func_get_args();
  250. $this->methods = array_merge($this->methods, $args);
  251. return $this;
  252. }
  253. /**
  254. * Detect support for an HTTP method
  255. * @return bool
  256. */
  257. public function supportsHttpMethod($method)
  258. {
  259. return in_array($method, $this->methods);
  260. }
  261. /**
  262. * Get middleware
  263. * @return array[Callable]
  264. */
  265. public function getMiddleware()
  266. {
  267. return $this->middleware;
  268. }
  269. /**
  270. * Set middleware
  271. *
  272. * This method allows middleware to be assigned to a specific Route.
  273. * If the method argument `is_callable` (including callable arrays!),
  274. * we directly append the argument to `$this->middleware`. Else, we
  275. * assume the argument is an array of callables and merge the array
  276. * with `$this->middleware`. Each middleware is checked for is_callable()
  277. * and an InvalidArgumentException is thrown immediately if it isn't.
  278. *
  279. * @param Callable|array[Callable]
  280. * @return \Slim\Route
  281. * @throws \InvalidArgumentException If argument is not callable or not an array of callables.
  282. */
  283. public function setMiddleware($middleware)
  284. {
  285. if (is_callable($middleware)) {
  286. $this->middleware[] = $middleware;
  287. } elseif (is_array($middleware)) {
  288. foreach($middleware as $callable) {
  289. if (!is_callable($callable)) {
  290. throw new \InvalidArgumentException('All Route middleware must be callable');
  291. }
  292. }
  293. $this->middleware = array_merge($this->middleware, $middleware);
  294. } else {
  295. throw new \InvalidArgumentException('Route middleware must be callable or an array of callables');
  296. }
  297. return $this;
  298. }
  299. /**
  300. * Matches URI?
  301. *
  302. * Parse this route's pattern, and then compare it to an HTTP resource URI
  303. * This method was modeled after the techniques demonstrated by Dan Sosedoff at:
  304. *
  305. * http://blog.sosedoff.com/2009/09/20/rails-like-php-url-router/
  306. *
  307. * @param string $resourceUri A Request URI
  308. * @return bool
  309. */
  310. public function matches($resourceUri)
  311. {
  312. //Convert URL params into regex patterns, construct a regex for this route, init params
  313. $patternAsRegex = preg_replace_callback('#:([\w]+)\+?#', array($this, 'matchesCallback'),
  314. str_replace(')', ')?', (string) $this->pattern));
  315. if (substr($this->pattern, -1) === '/') {
  316. $patternAsRegex .= '?';
  317. }
  318. //Cache URL params' names and values if this route matches the current HTTP request
  319. if (!preg_match('#^' . $patternAsRegex . '$#', $resourceUri, $paramValues)) {
  320. return false;
  321. }
  322. foreach ($this->paramNames as $name) {
  323. if (isset($paramValues[$name])) {
  324. if (isset($this->paramNamesPath[ $name ])) {
  325. $this->params[$name] = explode('/', urldecode($paramValues[$name]));
  326. } else {
  327. $this->params[$name] = urldecode($paramValues[$name]);
  328. }
  329. }
  330. }
  331. return true;
  332. }
  333. /**
  334. * Convert a URL parameter (e.g. ":id", ":id+") into a regular expression
  335. * @param array URL parameters
  336. * @return string Regular expression for URL parameter
  337. */
  338. protected function matchesCallback($m)
  339. {
  340. $this->paramNames[] = $m[1];
  341. if (isset($this->conditions[ $m[1] ])) {
  342. return '(?P<' . $m[1] . '>' . $this->conditions[ $m[1] ] . ')';
  343. }
  344. if (substr($m[0], -1) === '+') {
  345. $this->paramNamesPath[ $m[1] ] = 1;
  346. return '(?P<' . $m[1] . '>.+)';
  347. }
  348. return '(?P<' . $m[1] . '>[^/]+)';
  349. }
  350. /**
  351. * Set route name
  352. * @param string $name The name of the route
  353. * @return \Slim\Route
  354. */
  355. public function name($name)
  356. {
  357. $this->setName($name);
  358. return $this;
  359. }
  360. /**
  361. * Merge route conditions
  362. * @param array $conditions Key-value array of URL parameter conditions
  363. * @return \Slim\Route
  364. */
  365. public function conditions(array $conditions)
  366. {
  367. $this->conditions = array_merge($this->conditions, $conditions);
  368. return $this;
  369. }
  370. }