PageRenderTime 36ms CodeModel.GetById 14ms RepoModel.GetById 1ms app.codeStats 0ms

/PHP-E4/gsbslim/server/slim/vendor/slim/slim/Slim/Router.php

https://gitlab.com/mlassabe/LASSABE
PHP | 455 lines | 197 code | 53 blank | 205 comment | 20 complexity | 2845c32cc7c1ee53fd3ecb8134c6542d MD5 | raw file
  1. <?php
  2. /**
  3. * Slim Framework (http://slimframework.com)
  4. *
  5. * @link https://github.com/slimphp/Slim
  6. * @copyright Copyright (c) 2011-2016 Josh Lockhart
  7. * @license https://github.com/slimphp/Slim/blob/3.x/LICENSE.md (MIT License)
  8. */
  9. namespace Slim;
  10. use FastRoute\Dispatcher;
  11. use Interop\Container\ContainerInterface;
  12. use InvalidArgumentException;
  13. use RuntimeException;
  14. use Psr\Http\Message\ServerRequestInterface;
  15. use FastRoute\RouteCollector;
  16. use FastRoute\RouteParser;
  17. use FastRoute\RouteParser\Std as StdParser;
  18. use Slim\Interfaces\RouteGroupInterface;
  19. use Slim\Interfaces\RouterInterface;
  20. use Slim\Interfaces\RouteInterface;
  21. /**
  22. * Router
  23. *
  24. * This class organizes Slim application route objects. It is responsible
  25. * for registering route objects, assigning names to route objects,
  26. * finding routes that match the current HTTP request, and creating
  27. * URLs for a named route.
  28. */
  29. class Router implements RouterInterface
  30. {
  31. /**
  32. * Container Interface
  33. *
  34. * @var ContainerInterface
  35. */
  36. protected $container;
  37. /**
  38. * Parser
  39. *
  40. * @var \FastRoute\RouteParser
  41. */
  42. protected $routeParser;
  43. /**
  44. * Base path used in pathFor()
  45. *
  46. * @var string
  47. */
  48. protected $basePath = '';
  49. /**
  50. * Path to fast route cache file. Set to false to disable route caching
  51. *
  52. * @var string|False
  53. */
  54. protected $cacheFile = false;
  55. /**
  56. * Routes
  57. *
  58. * @var Route[]
  59. */
  60. protected $routes = [];
  61. /**
  62. * Route counter incrementer
  63. * @var int
  64. */
  65. protected $routeCounter = 0;
  66. /**
  67. * Route groups
  68. *
  69. * @var RouteGroup[]
  70. */
  71. protected $routeGroups = [];
  72. /**
  73. * @var \FastRoute\Dispatcher
  74. */
  75. protected $dispatcher;
  76. /**
  77. * Create new router
  78. *
  79. * @param RouteParser $parser
  80. */
  81. public function __construct(RouteParser $parser = null)
  82. {
  83. $this->routeParser = $parser ?: new StdParser;
  84. }
  85. /**
  86. * Set the base path used in pathFor()
  87. *
  88. * @param string $basePath
  89. *
  90. * @return self
  91. */
  92. public function setBasePath($basePath)
  93. {
  94. if (!is_string($basePath)) {
  95. throw new InvalidArgumentException('Router basePath must be a string');
  96. }
  97. $this->basePath = $basePath;
  98. return $this;
  99. }
  100. /**
  101. * Set path to fast route cache file. If this is false then route caching is disabled.
  102. *
  103. * @param string|false $cacheFile
  104. *
  105. * @return self
  106. */
  107. public function setCacheFile($cacheFile)
  108. {
  109. if (!is_string($cacheFile) && $cacheFile !== false) {
  110. throw new InvalidArgumentException('Router cacheFile must be a string or false');
  111. }
  112. $this->cacheFile = $cacheFile;
  113. if ($cacheFile !== false && !is_writable(dirname($cacheFile))) {
  114. throw new RuntimeException('Router cacheFile directory must be writable');
  115. }
  116. return $this;
  117. }
  118. /**
  119. * @param ContainerInterface $container
  120. */
  121. public function setContainer(ContainerInterface $container)
  122. {
  123. $this->container = $container;
  124. }
  125. /**
  126. * Add route
  127. *
  128. * @param string[] $methods Array of HTTP methods
  129. * @param string $pattern The route pattern
  130. * @param callable $handler The route callable
  131. *
  132. * @return RouteInterface
  133. *
  134. * @throws InvalidArgumentException if the route pattern isn't a string
  135. */
  136. public function map($methods, $pattern, $handler)
  137. {
  138. if (!is_string($pattern)) {
  139. throw new InvalidArgumentException('Route pattern must be a string');
  140. }
  141. // Prepend parent group pattern(s)
  142. if ($this->routeGroups) {
  143. $pattern = $this->processGroups() . $pattern;
  144. }
  145. // According to RFC methods are defined in uppercase (See RFC 7231)
  146. $methods = array_map("strtoupper", $methods);
  147. // Add route
  148. $route = $this->createRoute($methods, $pattern, $handler);
  149. $this->routes[$route->getIdentifier()] = $route;
  150. $this->routeCounter++;
  151. return $route;
  152. }
  153. /**
  154. * Dispatch router for HTTP request
  155. *
  156. * @param ServerRequestInterface $request The current HTTP request object
  157. *
  158. * @return array
  159. *
  160. * @link https://github.com/nikic/FastRoute/blob/master/src/Dispatcher.php
  161. */
  162. public function dispatch(ServerRequestInterface $request)
  163. {
  164. $uri = '/' . ltrim($request->getUri()->getPath(), '/');
  165. return $this->createDispatcher()->dispatch(
  166. $request->getMethod(),
  167. $uri
  168. );
  169. }
  170. /**
  171. * Create a new Route object
  172. *
  173. * @param string[] $methods Array of HTTP methods
  174. * @param string $pattern The route pattern
  175. * @param callable $handler The route callable
  176. *
  177. * @return \Slim\Interfaces\RouteInterface
  178. */
  179. protected function createRoute($methods, $pattern, $callable)
  180. {
  181. $route = new Route($methods, $pattern, $callable, $this->routeGroups, $this->routeCounter);
  182. if (!empty($this->container)) {
  183. $route->setContainer($this->container);
  184. }
  185. return $route;
  186. }
  187. /**
  188. * @return \FastRoute\Dispatcher
  189. */
  190. protected function createDispatcher()
  191. {
  192. if ($this->dispatcher) {
  193. return $this->dispatcher;
  194. }
  195. $routeDefinitionCallback = function (RouteCollector $r) {
  196. foreach ($this->getRoutes() as $route) {
  197. $r->addRoute($route->getMethods(), $route->getPattern(), $route->getIdentifier());
  198. }
  199. };
  200. if ($this->cacheFile) {
  201. $this->dispatcher = \FastRoute\cachedDispatcher($routeDefinitionCallback, [
  202. 'routeParser' => $this->routeParser,
  203. 'cacheFile' => $this->cacheFile,
  204. ]);
  205. } else {
  206. $this->dispatcher = \FastRoute\simpleDispatcher($routeDefinitionCallback, [
  207. 'routeParser' => $this->routeParser,
  208. ]);
  209. }
  210. return $this->dispatcher;
  211. }
  212. /**
  213. * @param \FastRoute\Dispatcher $dispatcher
  214. */
  215. public function setDispatcher(Dispatcher $dispatcher)
  216. {
  217. $this->dispatcher = $dispatcher;
  218. }
  219. /**
  220. * Get route objects
  221. *
  222. * @return Route[]
  223. */
  224. public function getRoutes()
  225. {
  226. return $this->routes;
  227. }
  228. /**
  229. * Get named route object
  230. *
  231. * @param string $name Route name
  232. *
  233. * @return Route
  234. *
  235. * @throws RuntimeException If named route does not exist
  236. */
  237. public function getNamedRoute($name)
  238. {
  239. foreach ($this->routes as $route) {
  240. if ($name == $route->getName()) {
  241. return $route;
  242. }
  243. }
  244. throw new RuntimeException('Named route does not exist for name: ' . $name);
  245. }
  246. /**
  247. * Remove named route
  248. *
  249. * @param string $name Route name
  250. *
  251. * @throws RuntimeException If named route does not exist
  252. */
  253. public function removeNamedRoute($name)
  254. {
  255. $route = $this->getNamedRoute($name);
  256. // no exception, route exists, now remove by id
  257. unset($this->routes[$route->getIdentifier()]);
  258. }
  259. /**
  260. * Process route groups
  261. *
  262. * @return string A group pattern to prefix routes with
  263. */
  264. protected function processGroups()
  265. {
  266. $pattern = "";
  267. foreach ($this->routeGroups as $group) {
  268. $pattern .= $group->getPattern();
  269. }
  270. return $pattern;
  271. }
  272. /**
  273. * Add a route group to the array
  274. *
  275. * @param string $pattern
  276. * @param callable $callable
  277. *
  278. * @return RouteGroupInterface
  279. */
  280. public function pushGroup($pattern, $callable)
  281. {
  282. $group = new RouteGroup($pattern, $callable);
  283. array_push($this->routeGroups, $group);
  284. return $group;
  285. }
  286. /**
  287. * Removes the last route group from the array
  288. *
  289. * @return RouteGroup|bool The RouteGroup if successful, else False
  290. */
  291. public function popGroup()
  292. {
  293. $group = array_pop($this->routeGroups);
  294. return $group instanceof RouteGroup ? $group : false;
  295. }
  296. /**
  297. * @param $identifier
  298. * @return \Slim\Interfaces\RouteInterface
  299. */
  300. public function lookupRoute($identifier)
  301. {
  302. if (!isset($this->routes[$identifier])) {
  303. throw new RuntimeException('Route not found, looks like your route cache is stale.');
  304. }
  305. return $this->routes[$identifier];
  306. }
  307. /**
  308. * Build the path for a named route excluding the base path
  309. *
  310. * @param string $name Route name
  311. * @param array $data Named argument replacement data
  312. * @param array $queryParams Optional query string parameters
  313. *
  314. * @return string
  315. *
  316. * @throws RuntimeException If named route does not exist
  317. * @throws InvalidArgumentException If required data not provided
  318. */
  319. public function relativePathFor($name, array $data = [], array $queryParams = [])
  320. {
  321. $route = $this->getNamedRoute($name);
  322. $pattern = $route->getPattern();
  323. $routeDatas = $this->routeParser->parse($pattern);
  324. // $routeDatas is an array of all possible routes that can be made. There is
  325. // one routedata for each optional parameter plus one for no optional parameters.
  326. //
  327. // The most specific is last, so we look for that first.
  328. $routeDatas = array_reverse($routeDatas);
  329. $segments = [];
  330. foreach ($routeDatas as $routeData) {
  331. foreach ($routeData as $item) {
  332. if (is_string($item)) {
  333. // this segment is a static string
  334. $segments[] = $item;
  335. continue;
  336. }
  337. // This segment has a parameter: first element is the name
  338. if (!array_key_exists($item[0], $data)) {
  339. // we don't have a data element for this segment: cancel
  340. // testing this routeData item, so that we can try a less
  341. // specific routeData item.
  342. $segments = [];
  343. $segmentName = $item[0];
  344. break;
  345. }
  346. $segments[] = $data[$item[0]];
  347. }
  348. if (!empty($segments)) {
  349. // we found all the parameters for this route data, no need to check
  350. // less specific ones
  351. break;
  352. }
  353. }
  354. if (empty($segments)) {
  355. throw new InvalidArgumentException('Missing data for URL segment: ' . $segmentName);
  356. }
  357. $url = implode('', $segments);
  358. if ($queryParams) {
  359. $url .= '?' . http_build_query($queryParams);
  360. }
  361. return $url;
  362. }
  363. /**
  364. * Build the path for a named route including the base path
  365. *
  366. * @param string $name Route name
  367. * @param array $data Named argument replacement data
  368. * @param array $queryParams Optional query string parameters
  369. *
  370. * @return string
  371. *
  372. * @throws RuntimeException If named route does not exist
  373. * @throws InvalidArgumentException If required data not provided
  374. */
  375. public function pathFor($name, array $data = [], array $queryParams = [])
  376. {
  377. $url = $this->relativePathFor($name, $data, $queryParams);
  378. if ($this->basePath) {
  379. $url = $this->basePath . $url;
  380. }
  381. return $url;
  382. }
  383. /**
  384. * Build the path for a named route.
  385. *
  386. * This method is deprecated. Use pathFor() from now on.
  387. *
  388. * @param string $name Route name
  389. * @param array $data Named argument replacement data
  390. * @param array $queryParams Optional query string parameters
  391. *
  392. * @return string
  393. *
  394. * @throws RuntimeException If named route does not exist
  395. * @throws InvalidArgumentException If required data not provided
  396. */
  397. public function urlFor($name, array $data = [], array $queryParams = [])
  398. {
  399. trigger_error('urlFor() is deprecated. Use pathFor() instead.', E_USER_DEPRECATED);
  400. return $this->pathFor($name, $data, $queryParams);
  401. }
  402. }