PageRenderTime 54ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/fuelphp/fuel/core/classes/router.php

http://github.com/eryx/php-framework-benchmark
PHP | 292 lines | 230 code | 19 blank | 43 comment | 13 complexity | 2fa6eebf8b5ce4e47c0c66082d127d85 MD5 | raw file
Possible License(s): MIT, BSD-3-Clause, Apache-2.0, LGPL-2.1, LGPL-3.0, BSD-2-Clause
  1. <?php
  2. /**
  3. * Part of the Fuel framework.
  4. *
  5. * @package Fuel
  6. * @version 1.5
  7. * @author Fuel Development Team
  8. * @license MIT License
  9. * @copyright 2010 - 2013 Fuel Development Team
  10. * @link http://fuelphp.com
  11. */
  12. namespace Fuel\Core;
  13. class Router
  14. {
  15. /**
  16. *
  17. */
  18. public static $routes = array();
  19. /**
  20. * Defines the controller class prefix. This allows you to namespace controllers
  21. */
  22. protected static $prefix = '';
  23. /**
  24. * Fetch the controller prefix to be used, or set a default if not defined
  25. */
  26. public static function _init()
  27. {
  28. static::$prefix = ltrim(\Config::get('controller_prefix', 'Controller_'), '\\');
  29. }
  30. /**
  31. * Add one or multiple routes
  32. *
  33. * @param string
  34. * @param string|array|Route either the translation for $path, an array for verb routing or an instance of Route
  35. * @param bool whether to prepend the route(s) to the routes array
  36. */
  37. public static function add($path, $options = null, $prepend = false, $case_sensitive = null)
  38. {
  39. if (is_array($path))
  40. {
  41. // Reverse to keep correct order in prepending
  42. $prepend and $path = array_reverse($path, true);
  43. foreach ($path as $p => $t)
  44. {
  45. static::add($p, $t, $prepend);
  46. }
  47. return;
  48. }
  49. elseif ($options instanceof Route)
  50. {
  51. static::$routes[$path] = $options;
  52. return;
  53. }
  54. $name = $path;
  55. if (is_array($options) and array_key_exists('name', $options))
  56. {
  57. $name = $options['name'];
  58. unset($options['name']);
  59. if (count($options) == 1 and ! is_array($options[0]))
  60. {
  61. $options = $options[0];
  62. }
  63. }
  64. if ($prepend)
  65. {
  66. \Arr::prepend(static::$routes, $name, new \Route($path, $options, $case_sensitive));
  67. return;
  68. }
  69. static::$routes[$name] = new \Route($path, $options, $case_sensitive);
  70. }
  71. /**
  72. * Does reverse routing for a named route. This will return the FULL url
  73. * (including the base url and index.php).
  74. *
  75. * WARNING: Reverse routing with routes that contains a regex is still
  76. * experimental. The simple ones work, but complex ones might fail!
  77. *
  78. * Usage:
  79. *
  80. * <a href="<?php echo Router::get('foo'); ?>">Foo</a>
  81. *
  82. * @param string $name the name of the route
  83. * @param array $named_params the array of named parameters
  84. * @return string the full url for the named route
  85. */
  86. public static function get($name, $named_params = array())
  87. {
  88. // check if we have this named route
  89. if (array_key_exists($name, static::$routes))
  90. {
  91. // fetch the url this route defines
  92. $url = static::$routes[$name]->path;
  93. // get named parameters regex's out of the way first
  94. foreach($named_params as $name => $value)
  95. {
  96. if (is_string($name) and ($pos = strpos($url, '(:'.$name.')')) !== false)
  97. {
  98. $url = substr_replace($url,$value,$pos,strlen($name)+3);
  99. }
  100. }
  101. // deal with the remaining regex's
  102. if (preg_match_all('#\(.*?\)#', $url, $matches) !== false)
  103. {
  104. if (count($matches) == 1)
  105. {
  106. $search = array();
  107. foreach($matches[0] as $match)
  108. {
  109. $search[] = $match;
  110. }
  111. $replace = array();
  112. foreach($search as $key => $regex)
  113. {
  114. $replace = array_key_exists($key, $named_params) ? $named_params[$key] : '';
  115. if (($pos = strpos($url,$regex)) !== false)
  116. {
  117. $url = substr_replace($url,$replace,$pos,strlen($regex));
  118. }
  119. }
  120. }
  121. }
  122. // return the created URI, replace any named parameters not in a regex
  123. return \Uri::create($url, $named_params);
  124. }
  125. }
  126. /**
  127. * Delete one or multiple routes
  128. *
  129. * @param string
  130. */
  131. public static function delete($path, $case_sensitive = null)
  132. {
  133. $case_sensitive ?: \Config::get('routing.case_sensitive', true);
  134. // support the usual route path placeholders
  135. $path = str_replace(array(
  136. ':any',
  137. ':alnum',
  138. ':num',
  139. ':alpha',
  140. ':segment',
  141. ), array(
  142. '.+',
  143. '[[:alnum:]]+',
  144. '[[:digit:]]+',
  145. '[[:alpha:]]+',
  146. '[^/]*',
  147. ), $path);
  148. foreach (static::$routes as $name => $route)
  149. {
  150. if ($case_sensitive)
  151. {
  152. if (preg_match('#^'.$path.'$#uD', $name))
  153. {
  154. unset(static::$routes[$name]);
  155. }
  156. }
  157. else
  158. {
  159. if (preg_match('#^'.$path.'$#uiD', $name))
  160. {
  161. unset(static::$routes[$name]);
  162. }
  163. }
  164. }
  165. }
  166. /**
  167. * Processes the given request using the defined routes
  168. *
  169. * @param Request the given Request object
  170. * @param bool whether to use the defined routes or not
  171. * @return mixed the match array or false
  172. */
  173. public static function process(\Request $request, $route = true)
  174. {
  175. $match = false;
  176. if ($route)
  177. {
  178. foreach (static::$routes as $route)
  179. {
  180. if ($match = $route->parse($request))
  181. {
  182. break;
  183. }
  184. }
  185. }
  186. if ( ! $match)
  187. {
  188. // Since we didn't find a match, we will create a new route.
  189. $match = new Route(preg_quote($request->uri->get(), '#'), $request->uri->get());
  190. $match->parse($request);
  191. }
  192. if ($match->callable !== null)
  193. {
  194. return $match;
  195. }
  196. return static::parse_match($match);
  197. }
  198. /**
  199. * Find the controller that matches the route requested
  200. *
  201. * @param Route $match the given Route object
  202. * @return mixed the match array or false
  203. */
  204. protected static function parse_match($match)
  205. {
  206. $namespace = '';
  207. $segments = $match->segments;
  208. $module = false;
  209. // First port of call: request for a module?
  210. if (\Module::exists($segments[0]))
  211. {
  212. // make the module known to the autoloader
  213. \Module::load($segments[0]);
  214. $match->module = array_shift($segments);
  215. $namespace .= ucfirst($match->module).'\\';
  216. $module = $match->module;
  217. }
  218. if ($info = static::parse_segments($segments, $namespace, $module))
  219. {
  220. $match->controller = $info['controller'];
  221. $match->action = $info['action'];
  222. $match->method_params = $info['method_params'];
  223. return $match;
  224. }
  225. else
  226. {
  227. return null;
  228. }
  229. }
  230. protected static function parse_segments($segments, $namespace = '', $module = false)
  231. {
  232. $temp_segments = $segments;
  233. foreach (array_reverse($segments, true) as $key => $segment)
  234. {
  235. $class = $namespace.static::$prefix.\Inflector::words_to_upper(implode('_', $temp_segments));
  236. array_pop($temp_segments);
  237. if (class_exists($class))
  238. {
  239. return array(
  240. 'controller' => $class,
  241. 'action' => isset($segments[$key + 1]) ? $segments[$key + 1] : null,
  242. 'method_params' => array_slice($segments, $key + 2),
  243. );
  244. }
  245. }
  246. // Fall back for default module controllers
  247. if ($module)
  248. {
  249. $class = $namespace.static::$prefix.ucfirst($module);
  250. if (class_exists($class))
  251. {
  252. return array(
  253. 'controller' => $class,
  254. 'action' => isset($segments[0]) ? $segments[0] : null,
  255. 'method_params' => array_slice($segments, 1),
  256. );
  257. }
  258. }
  259. return false;
  260. }
  261. }