route.php 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  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 Route
  14. {
  15. /**
  16. * @var array segments array
  17. */
  18. public $segments = array();
  19. /**
  20. * @var array named params array
  21. */
  22. public $named_params = array();
  23. /**
  24. * @var array method params array
  25. */
  26. public $method_params = array();
  27. /**
  28. * @var string route path
  29. */
  30. public $path = '';
  31. /**
  32. * @var boolean route case match behaviour
  33. */
  34. public $case_sensitive = false;
  35. /**
  36. * @var boolean wether to strip the extension from the URI
  37. */
  38. public $strip_extension = true;
  39. /**
  40. * @var string route module
  41. */
  42. public $module = null;
  43. /**
  44. * @var string route directory
  45. */
  46. public $directory = null;
  47. /**
  48. * @var string controller name
  49. */
  50. public $controller = null;
  51. /**
  52. * @var string default controller action
  53. */
  54. public $action = 'index';
  55. /**
  56. * @var mixed route translation
  57. */
  58. public $translation = null;
  59. /**
  60. * @var closure
  61. */
  62. public $callable = null;
  63. /**
  64. * @var mixed the compiled route regex
  65. */
  66. protected $search = null;
  67. public function __construct($path, $translation = null, $case_sensitive = null, $strip_extension = null)
  68. {
  69. $this->path = $path;
  70. $this->translation = ($translation === null) ? $path : $translation;
  71. $this->search = ($translation == stripslashes($path)) ? $path : $this->compile();
  72. $this->case_sensitive = ($case_sensitive === null) ? \Config::get('routing.case_sensitive', true) : $case_sensitive;
  73. $this->strip_extension = ($strip_extension === null) ? \Config::get('routing.strip_extension', true) : $strip_extension;
  74. }
  75. /**
  76. * Compiles a route. Replaces named params and regex shortcuts.
  77. *
  78. * @return string compiled route.
  79. */
  80. protected function compile()
  81. {
  82. if ($this->path === '_root_')
  83. {
  84. return '';
  85. }
  86. $search = str_replace(array(
  87. ':any',
  88. ':alnum',
  89. ':num',
  90. ':alpha',
  91. ':segment',
  92. ), array(
  93. '.+',
  94. '[[:alnum:]]+',
  95. '[[:digit:]]+',
  96. '[[:alpha:]]+',
  97. '[^/]*',
  98. ), $this->path);
  99. return preg_replace('#(?<!\[\[):([a-z\_]+)(?!:\]\])#uD', '(?P<$1>.+?)', $search);
  100. }
  101. /**
  102. * Attempts to find the correct route for the given URI
  103. *
  104. * @access public
  105. * @param object The URI object
  106. * @return array
  107. */
  108. public function parse(\Request $request)
  109. {
  110. $uri = $request->uri->get();
  111. $method = $request->get_method();
  112. if ($uri === '' and $this->path === '_root_')
  113. {
  114. return $this->matched();
  115. }
  116. $result = $this->_parse_search($uri, null, $method);
  117. if ($result)
  118. {
  119. return $result;
  120. }
  121. return false;
  122. }
  123. /**
  124. * Parses a route match and returns the controller, action and params.
  125. *
  126. * @access public
  127. * @param string The matched route
  128. * @return object $this
  129. */
  130. public function matched($uri = '', $named_params = array())
  131. {
  132. // Clean out all the non-named stuff out of $named_params
  133. foreach($named_params as $key => $val)
  134. {
  135. if (is_numeric($key))
  136. {
  137. unset($named_params[$key]);
  138. }
  139. }
  140. $this->named_params = $named_params;
  141. if ($this->translation instanceof \Closure)
  142. {
  143. $this->callable = $this->translation;
  144. }
  145. else
  146. {
  147. $path = $this->translation;
  148. if ($uri != '')
  149. {
  150. if ($this->strip_extension)
  151. {
  152. strpos($uri, $ext = \Input::extension()) === false or $uri = substr($uri, 0, -(strlen($ext)+1));
  153. }
  154. if ($this->case_sensitive)
  155. {
  156. $path = preg_replace('#^'.$this->search.'$#uD', $this->translation, $uri);
  157. }
  158. else
  159. {
  160. $path = preg_replace('#^'.$this->search.'$#uiD', $this->translation, $uri);
  161. }
  162. }
  163. $this->segments = explode('/', trim($path, '/'));
  164. }
  165. return $this;
  166. }
  167. /**
  168. * Parses an actual route - extracted out of parse() to make it recursive.
  169. *
  170. * @param string The URI object
  171. * @param object route object
  172. * @param string request method
  173. * @return array|boolean
  174. */
  175. protected function _parse_search($uri, $route = null, $method = null)
  176. {
  177. if ($route === null)
  178. {
  179. $route = $this;
  180. }
  181. if (is_array($route->translation))
  182. {
  183. foreach ($route->translation as $r)
  184. {
  185. $verb = $r[0];
  186. if ($method == strtoupper($verb))
  187. {
  188. $r[1]->search = $route->search;
  189. $result = $route->_parse_search($uri, $r[1], $method);
  190. if ($result)
  191. {
  192. return $result;
  193. }
  194. }
  195. }
  196. return false;
  197. }
  198. if ($this->case_sensitive)
  199. {
  200. $result = preg_match('#^'.$route->search.'$#uD', $uri, $params);
  201. }
  202. else
  203. {
  204. $result = preg_match('#^'.$route->search.'$#uiD', $uri, $params);
  205. }
  206. if ($result === 1)
  207. {
  208. return $route->matched($uri, $params);
  209. }
  210. else
  211. {
  212. return false;
  213. }
  214. }
  215. }