Route.class.php 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. <?php
  2. /**
  3. * Route definition
  4. *
  5. * @author Christopher Han <xiphux@gmail.com>
  6. * @copyright Copyright (c) 2012 Christopher Han
  7. * @package GitPHP
  8. * @subpackage Router
  9. */
  10. class GitPHP_Route
  11. {
  12. /**
  13. * The route path
  14. *
  15. * @var string
  16. */
  17. protected $path;
  18. /**
  19. * The route constraints
  20. *
  21. * @var string[]
  22. */
  23. protected $constraints = array();
  24. /**
  25. * Additional route parameters
  26. *
  27. * @var string[]
  28. */
  29. protected $extraParameters = array();
  30. /**
  31. * Url parameters
  32. *
  33. * @var string[]
  34. */
  35. protected $urlParameters = array();
  36. /**
  37. * Used parameters
  38. *
  39. * @var string[]
  40. */
  41. protected $usedParameters = array();
  42. /**
  43. * Cached constraints
  44. *
  45. * @var array[]
  46. */
  47. protected $cachedConstraints;
  48. /**
  49. * Constructor
  50. *
  51. * @param string $path route path
  52. * @param string[] $constraints route constraints
  53. * @param string[] $extraParameters additional route parameters
  54. * @param GitPHP_Route $parent parent route
  55. */
  56. public function __construct($path, $constraints = array(), $extraParameters = array(), $parent = null)
  57. {
  58. if (empty($path))
  59. throw new Exception('Path is required');
  60. // initialize path
  61. if ($parent)
  62. $this->path = $parent->GetPath() . '/' . $path;
  63. else
  64. $this->path = $path;
  65. // initialize constraints
  66. if ($parent)
  67. $this->constraints = array_merge($parent->constraints, $constraints);
  68. else
  69. $this->constraints = $constraints;
  70. // initialise extra parameters
  71. if ($parent)
  72. $this->extraParameters = array_merge($parent->extraParameters, $extraParameters);
  73. else
  74. $this->extraParameters = $extraParameters;
  75. // initialize url parameters
  76. $fullPath = explode('/', $this->path);
  77. foreach ($fullPath as $pathpiece) {
  78. if (strncmp($pathpiece, ':', 1) === 0) {
  79. $param = substr($pathpiece, 1);
  80. $this->urlParameters[] = $param;
  81. }
  82. }
  83. // initialize used parameters
  84. $this->usedParameters = array_merge($this->urlParameters, array_keys($extraParameters));
  85. if ($parent)
  86. $this->usedParameters = array_merge($parent->GetUsedParameters(), $this->usedParameters);
  87. $this->usedParameters = array_unique($this->usedParameters);
  88. }
  89. /**
  90. * Get route path
  91. *
  92. * @return string $path
  93. */
  94. public function GetPath()
  95. {
  96. return $this->path;
  97. }
  98. /**
  99. * Test if this route matches the given path
  100. *
  101. * @param string $path path
  102. * @return array|boolean array of parameters or false if not matched
  103. */
  104. public function Match($path)
  105. {
  106. if (empty($path))
  107. return false;
  108. $routepieces = explode('/', $this->GetPath());
  109. foreach ($routepieces as $i => $routepiece) {
  110. if (strncmp($routepiece, ':', 1) === 0) {
  111. $routepiece = substr($routepiece, 1);
  112. if (!empty($this->constraints[$routepiece])) {
  113. $pattern = '(?P<' . $routepiece . '>' . $this->constraints[$routepiece] . ')';
  114. } else {
  115. $pattern = '(?P<' . $routepiece . '>.+)';
  116. }
  117. $routepieces[$i] = $pattern;
  118. }
  119. }
  120. $routepattern = implode('/', $routepieces);
  121. if (!preg_match('@^' . $routepattern . '$@', $path, $regs))
  122. return false;
  123. $params = array();
  124. foreach ($regs as $key => $register) {
  125. if (!is_string($key))
  126. continue;
  127. $params[$key] = $register;
  128. }
  129. if (count($this->extraParameters) > 0) {
  130. $params = array_merge($params, $this->extraParameters);
  131. }
  132. return $params;
  133. }
  134. /**
  135. * Test if route is valid for the given parameters
  136. *
  137. * @param string[] $params parameters
  138. * @return boolean true if matech
  139. */
  140. public function Valid($params)
  141. {
  142. foreach ($this->constraints as $param => $constraint) {
  143. if (empty($params[$param]))
  144. return false;
  145. $paramval = $params[$param];
  146. if (!isset($this->cachedConstraints[$param][$paramval])) {
  147. $this->cachedConstraints[$param][$paramval] = preg_match('@^' . $constraint . '$@', $params[$param]);
  148. }
  149. if (!$this->cachedConstraints[$param][$paramval])
  150. return false;
  151. }
  152. foreach ($this->urlParameters as $param) {
  153. if (empty($params[$param]))
  154. return false;
  155. }
  156. return true;
  157. }
  158. /**
  159. * Build route from parameters
  160. *
  161. * @param string[] $params parameters
  162. * @return string full route
  163. */
  164. public function Build($params)
  165. {
  166. $path = $this->GetPath();
  167. $routepieces = explode('/', $path);
  168. foreach ($routepieces as $i => $piece) {
  169. if (strncmp($piece, ':', 1) !== 0) {
  170. // not a param
  171. continue;
  172. }
  173. $paramname = substr($piece, 1);
  174. $routepieces[$i] = $params[$paramname];
  175. }
  176. return trim(implode('/', $routepieces), '/');
  177. }
  178. /**
  179. * Get list of params used in this route
  180. *
  181. * @return string[] array of parameters
  182. */
  183. public function GetUsedParameters()
  184. {
  185. return $this->usedParameters;
  186. }
  187. /**
  188. * Compare routes for precedence
  189. *
  190. * @param GitPHP_Route $a route a
  191. * @param GitPHP_Route $b route b
  192. */
  193. public static function CompareRoute($a, $b)
  194. {
  195. $apath = $a->GetPath();
  196. $bpath = $b->GetPath();
  197. $acount = substr_count($apath, ':');
  198. $bcount = substr_count($bpath, ':');
  199. if ($acount == $bcount) {
  200. $acount2 = substr_count($apath, '/');
  201. $bcount2 = substr_count($bpath, '/');
  202. if ($acount2 == $bcount2)
  203. return 0;
  204. return $acount2 < $bcount2 ? 1 : -1;
  205. }
  206. return $acount < $bcount ? 1 : -1;
  207. }
  208. }