PageRenderTime 171ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/myCore/lib/Slim/Route.php

https://gitlab.com/fabian.morales/marlon_becerra
PHP | 471 lines | 208 code | 52 blank | 211 comment | 21 complexity | ee9beb2b99098545950eda726abb27f2 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.6.1
  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. * @var bool Whether or not this route should be matched in a case-sensitive manner
  84. */
  85. protected $caseSensitive;
  86. /**
  87. * Constructor
  88. * @param string $pattern The URL pattern (e.g. "/books/:id")
  89. * @param mixed $callable Anything that returns TRUE for is_callable()
  90. * @param bool $caseSensitive Whether or not this route should be matched in a case-sensitive manner
  91. */
  92. public function __construct($pattern, $callable, $caseSensitive = true)
  93. {
  94. $this->setPattern($pattern);
  95. $this->setCallable($callable);
  96. $this->setConditions(self::getDefaultConditions());
  97. $this->caseSensitive = $caseSensitive;
  98. }
  99. /**
  100. * Set default route conditions for all instances
  101. * @param array $defaultConditions
  102. */
  103. public static function setDefaultConditions(array $defaultConditions)
  104. {
  105. self::$defaultConditions = $defaultConditions;
  106. }
  107. /**
  108. * Get default route conditions for all instances
  109. * @return array
  110. */
  111. public static function getDefaultConditions()
  112. {
  113. return self::$defaultConditions;
  114. }
  115. /**
  116. * Get route pattern
  117. * @return string
  118. */
  119. public function getPattern()
  120. {
  121. return $this->pattern;
  122. }
  123. /**
  124. * Set route pattern
  125. * @param string $pattern
  126. */
  127. public function setPattern($pattern)
  128. {
  129. $this->pattern = $pattern;
  130. }
  131. /**
  132. * Get route callable
  133. * @return mixed
  134. */
  135. public function getCallable()
  136. {
  137. return $this->callable;
  138. }
  139. /**
  140. * Set route callable
  141. * @param mixed $callable
  142. * @throws \InvalidArgumentException If argument is not callable
  143. */
  144. public function setCallable($callable)
  145. {
  146. $matches = array();
  147. if (is_string($callable) && preg_match('!^([^\:]+)\:([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)$!', $callable, $matches)) {
  148. $class = $matches[1];
  149. $method = $matches[2];
  150. $callable = function() use ($class, $method) {
  151. static $obj = null;
  152. if ($obj === null) {
  153. $obj = new $class;
  154. }
  155. return call_user_func_array(array($obj, $method), func_get_args());
  156. };
  157. }
  158. if (!is_callable($callable)) {
  159. throw new \InvalidArgumentException('Route callable must be callable');
  160. }
  161. $this->callable = $callable;
  162. }
  163. /**
  164. * Get route conditions
  165. * @return array
  166. */
  167. public function getConditions()
  168. {
  169. return $this->conditions;
  170. }
  171. /**
  172. * Set route conditions
  173. * @param array $conditions
  174. */
  175. public function setConditions(array $conditions)
  176. {
  177. $this->conditions = $conditions;
  178. }
  179. /**
  180. * Get route name
  181. * @return string|null
  182. */
  183. public function getName()
  184. {
  185. return $this->name;
  186. }
  187. /**
  188. * Set route name
  189. * @param string $name
  190. */
  191. public function setName($name)
  192. {
  193. $this->name = (string)$name;
  194. }
  195. /**
  196. * Get route parameters
  197. * @return array
  198. */
  199. public function getParams()
  200. {
  201. return $this->params;
  202. }
  203. /**
  204. * Set route parameters
  205. * @param array $params
  206. */
  207. public function setParams($params)
  208. {
  209. $this->params = $params;
  210. }
  211. /**
  212. * Get route parameter value
  213. * @param string $index Name of URL parameter
  214. * @return string
  215. * @throws \InvalidArgumentException If route parameter does not exist at index
  216. */
  217. public function getParam($index)
  218. {
  219. if (!isset($this->params[$index])) {
  220. throw new \InvalidArgumentException('Route parameter does not exist at specified index');
  221. }
  222. return $this->params[$index];
  223. }
  224. /**
  225. * Set route parameter value
  226. * @param string $index Name of URL parameter
  227. * @param mixed $value The new parameter value
  228. * @throws \InvalidArgumentException If route parameter does not exist at index
  229. */
  230. public function setParam($index, $value)
  231. {
  232. if (!isset($this->params[$index])) {
  233. throw new \InvalidArgumentException('Route parameter does not exist at specified index');
  234. }
  235. $this->params[$index] = $value;
  236. }
  237. /**
  238. * Add supported HTTP method(s)
  239. */
  240. public function setHttpMethods()
  241. {
  242. $args = func_get_args();
  243. $this->methods = $args;
  244. }
  245. /**
  246. * Get supported HTTP methods
  247. * @return array
  248. */
  249. public function getHttpMethods()
  250. {
  251. return $this->methods;
  252. }
  253. /**
  254. * Append supported HTTP methods
  255. */
  256. public function appendHttpMethods()
  257. {
  258. $args = func_get_args();
  259. if(count($args) && is_array($args[0])){
  260. $args = $args[0];
  261. }
  262. $this->methods = array_merge($this->methods, $args);
  263. }
  264. /**
  265. * Append supported HTTP methods (alias for Route::appendHttpMethods)
  266. * @return \Slim\Route
  267. */
  268. public function via()
  269. {
  270. $args = func_get_args();
  271. if(count($args) && is_array($args[0])){
  272. $args = $args[0];
  273. }
  274. $this->methods = array_merge($this->methods, $args);
  275. return $this;
  276. }
  277. /**
  278. * Detect support for an HTTP method
  279. * @param string $method
  280. * @return bool
  281. */
  282. public function supportsHttpMethod($method)
  283. {
  284. return in_array($method, $this->methods);
  285. }
  286. /**
  287. * Get middleware
  288. * @return array[Callable]
  289. */
  290. public function getMiddleware()
  291. {
  292. return $this->middleware;
  293. }
  294. /**
  295. * Set middleware
  296. *
  297. * This method allows middleware to be assigned to a specific Route.
  298. * If the method argument `is_callable` (including callable arrays!),
  299. * we directly append the argument to `$this->middleware`. Else, we
  300. * assume the argument is an array of callables and merge the array
  301. * with `$this->middleware`. Each middleware is checked for is_callable()
  302. * and an InvalidArgumentException is thrown immediately if it isn't.
  303. *
  304. * @param Callable|array[Callable]
  305. * @return \Slim\Route
  306. * @throws \InvalidArgumentException If argument is not callable or not an array of callables.
  307. */
  308. public function setMiddleware($middleware)
  309. {
  310. if (is_callable($middleware)) {
  311. $this->middleware[] = $middleware;
  312. } elseif (is_array($middleware)) {
  313. foreach ($middleware as $callable) {
  314. if (!is_callable($callable)) {
  315. throw new \InvalidArgumentException('All Route middleware must be callable');
  316. }
  317. }
  318. $this->middleware = array_merge($this->middleware, $middleware);
  319. } else {
  320. throw new \InvalidArgumentException('Route middleware must be callable or an array of callables');
  321. }
  322. return $this;
  323. }
  324. /**
  325. * Matches URI?
  326. *
  327. * Parse this route's pattern, and then compare it to an HTTP resource URI
  328. * This method was modeled after the techniques demonstrated by Dan Sosedoff at:
  329. *
  330. * http://blog.sosedoff.com/2009/09/20/rails-like-php-url-router/
  331. *
  332. * @param string $resourceUri A Request URI
  333. * @return bool
  334. */
  335. public function matches($resourceUri)
  336. {
  337. //Convert URL params into regex patterns, construct a regex for this route, init params
  338. $patternAsRegex = preg_replace_callback(
  339. '#:([\w]+)\+?#',
  340. array($this, 'matchesCallback'),
  341. str_replace(')', ')?', (string)$this->pattern)
  342. );
  343. if (substr($this->pattern, -1) === '/') {
  344. $patternAsRegex .= '?';
  345. }
  346. $regex = '#^' . $patternAsRegex . '$#';
  347. if ($this->caseSensitive === false) {
  348. $regex .= 'i';
  349. }
  350. //Cache URL params' names and values if this route matches the current HTTP request
  351. if (!preg_match($regex, $resourceUri, $paramValues)) {
  352. return false;
  353. }
  354. foreach ($this->paramNames as $name) {
  355. if (isset($paramValues[$name])) {
  356. if (isset($this->paramNamesPath[$name])) {
  357. $this->params[$name] = explode('/', urldecode($paramValues[$name]));
  358. } else {
  359. $this->params[$name] = urldecode($paramValues[$name]);
  360. }
  361. }
  362. }
  363. return true;
  364. }
  365. /**
  366. * Convert a URL parameter (e.g. ":id", ":id+") into a regular expression
  367. * @param array $m URL parameters
  368. * @return string Regular expression for URL parameter
  369. */
  370. protected function matchesCallback($m)
  371. {
  372. $this->paramNames[] = $m[1];
  373. if (isset($this->conditions[$m[1]])) {
  374. return '(?P<' . $m[1] . '>' . $this->conditions[$m[1]] . ')';
  375. }
  376. if (substr($m[0], -1) === '+') {
  377. $this->paramNamesPath[$m[1]] = 1;
  378. return '(?P<' . $m[1] . '>.+)';
  379. }
  380. return '(?P<' . $m[1] . '>[^/]+)';
  381. }
  382. /**
  383. * Set route name
  384. * @param string $name The name of the route
  385. * @return \Slim\Route
  386. */
  387. public function name($name)
  388. {
  389. $this->setName($name);
  390. return $this;
  391. }
  392. /**
  393. * Merge route conditions
  394. * @param array $conditions Key-value array of URL parameter conditions
  395. * @return \Slim\Route
  396. */
  397. public function conditions(array $conditions)
  398. {
  399. $this->conditions = array_merge($this->conditions, $conditions);
  400. return $this;
  401. }
  402. /**
  403. * Dispatch route
  404. *
  405. * This method invokes the route object's callable. If middleware is
  406. * registered for the route, each callable middleware is invoked in
  407. * the order specified.
  408. *
  409. * @return bool
  410. */
  411. public function dispatch()
  412. {
  413. foreach ($this->middleware as $mw) {
  414. call_user_func_array($mw, array($this));
  415. }
  416. $return = call_user_func_array($this->getCallable(), array_values($this->getParams()));
  417. return ($return === false) ? false : true;
  418. }
  419. }