/ManaPHP/Mvc/Router/Route.php

https://gitlab.com/szlongshu/manaphp · PHP · 225 lines · 134 code · 27 blank · 64 comment · 33 complexity · 3bdc6f561bc6eca43dc3b5fda84d9647 MD5 · raw file

  1. <?php
  2. namespace ManaPHP\Mvc\Router {
  3. /**
  4. * ManaPHP\Mvc\Router\Route
  5. *
  6. * This class represents every route added to the router
  7. *
  8. * NOTE_PHP:
  9. * Hostname Constraints has been removed by PHP implementation
  10. */
  11. class Route implements RouteInterface
  12. {
  13. /**
  14. * @var string
  15. */
  16. protected $_pattern;
  17. /**
  18. * @var string
  19. */
  20. protected $_compiledPattern;
  21. /**
  22. * @var array
  23. */
  24. protected $_paths;
  25. /**
  26. * @var array|null|string
  27. */
  28. protected $_httpMethods;
  29. /**
  30. * \ManaPHP\Mvc\Router\Route constructor
  31. *
  32. * @param string $pattern
  33. * @param array $paths
  34. * @param array|string $httpMethods
  35. *
  36. * @throws \ManaPHP\Mvc\Router\Exception
  37. */
  38. public function __construct($pattern, $paths = null, $httpMethods = null)
  39. {
  40. $this->_pattern = $pattern;
  41. $this->_compiledPattern = $this->_compilePattern($pattern);
  42. $this->_paths = self::getRoutePaths($paths);
  43. $this->_httpMethods = $httpMethods;
  44. }
  45. /**
  46. * Replaces placeholders from pattern returning a valid PCRE regular expression
  47. *
  48. * @param string $pattern
  49. *
  50. * @return string
  51. */
  52. protected function _compilePattern($pattern)
  53. {
  54. // If a pattern contains ':', maybe there are placeholders to replace
  55. if (strpos($pattern, ':') !== false) {
  56. $pattern = strtr($pattern, [
  57. '/:module' => '/{module:[a-z\d_-]+}',
  58. '/:controller' => '/{controller:[a-z\d_-]+}',
  59. '/:action' => '/{action:[a-z\d_-]+}',
  60. '/:params' => '/{params:.+}',
  61. '/:int' => '/(\d+)',
  62. ]);
  63. }
  64. if (strpos($pattern, '{') !== false) {
  65. $pattern = $this->_extractNamedParams($pattern);
  66. }
  67. if (strpos($pattern, '(') !== false || strpos($pattern, '[') !== false) {
  68. return '#^' . $pattern . '$#i';
  69. } else {
  70. return $pattern;
  71. }
  72. }
  73. /**
  74. * Extracts parameters from a string
  75. *
  76. * @param string $pattern
  77. *
  78. * @return string
  79. */
  80. protected function _extractNamedParams($pattern)
  81. {
  82. if (strpos($pattern, '{') === false) {
  83. return $pattern;
  84. }
  85. $left_token = '@_@';
  86. $right_token = '!_!';
  87. $need_restore_token = false;
  88. if (preg_match('#{\d#', $pattern) === 1
  89. && strpos($pattern, $left_token) === false
  90. && strpos($pattern, $right_token) === false
  91. ) {
  92. $need_restore_token = true;
  93. $pattern = preg_replace('#{(\d+,?\d*)}#', $left_token . '\1' . $right_token, $pattern);
  94. }
  95. if (preg_match_all('#{([A-Z].*)}#Ui', $pattern, $matches, PREG_SET_ORDER) > 0) {
  96. foreach ($matches as $match) {
  97. if (strpos($match[0], ':') === false) {
  98. $pattern = str_replace($match[0], '(?<' . $match[1] . '>[\w-]+)', $pattern);
  99. } else {
  100. $parts = explode(':', $match[1]);
  101. $pattern = str_replace($match[0], '(?<' . $parts[0] . '>' . $parts[1] . ')', $pattern);
  102. }
  103. }
  104. }
  105. if ($need_restore_token) {
  106. $pattern = str_replace([$left_token, $right_token], ['{', '}'], $pattern);
  107. }
  108. return $pattern;
  109. }
  110. /**
  111. * Returns routePaths
  112. *
  113. * @param string|array $paths
  114. *
  115. * @return array
  116. * @throws \ManaPHP\Mvc\Router\Exception
  117. */
  118. public static function getRoutePaths($paths = null)
  119. {
  120. if ($paths !== null) {
  121. if (is_string($paths)) {
  122. $parts = explode('::', $paths);
  123. if (count($parts) === 3) {
  124. list($moduleName, $controllerName, $actionName) = $parts;
  125. } elseif (count($parts) === 2) {
  126. list($controllerName, $actionName) = $parts;
  127. } else {
  128. $controllerName = $parts[0];
  129. }
  130. $routePaths = [];
  131. if (isset($moduleName)) {
  132. $routePaths['module'] = $moduleName;
  133. }
  134. if (isset($controllerName)) {
  135. $routePaths['controller'] = $controllerName;
  136. }
  137. if (isset($actionName)) {
  138. $routePaths['action'] = $actionName;
  139. }
  140. } elseif (is_array($paths)) {
  141. $routePaths = $paths;
  142. } else {
  143. throw new Exception('--paths must be a string or array.');
  144. }
  145. } else {
  146. $routePaths = [];
  147. }
  148. return $routePaths;
  149. }
  150. /**
  151. * Returns the paths
  152. *
  153. * @return array
  154. */
  155. public function getPaths()
  156. {
  157. return $this->_paths;
  158. }
  159. /**
  160. * @param string $handle_uri
  161. * @param array|null $matches
  162. *
  163. * @return bool
  164. * @throws \ManaPHP\Mvc\Router\Exception
  165. */
  166. public function isMatched($handle_uri, &$matches)
  167. {
  168. if ($this->_httpMethods !== null) {
  169. if (is_string($this->_httpMethods)) {
  170. if ($this->_httpMethods !== $_SERVER['REQUEST_METHOD']) {
  171. return false;
  172. }
  173. } else {
  174. if (!in_array($_SERVER['REQUEST_METHOD'], $this->_httpMethods, true)) {
  175. return false;
  176. }
  177. }
  178. }
  179. if (strpos($this->_compiledPattern, '^') !== false) {
  180. $r = preg_match($this->_compiledPattern, $handle_uri, $matches);
  181. if ($r === false) {
  182. throw new Exception('--invalid PCRE: ' . $this->_compiledPattern . ' for ' . $this->_pattern);
  183. } elseif ($r === 1) {
  184. return true;
  185. } else {
  186. return false;
  187. }
  188. } else {
  189. if ($this->_compiledPattern === $handle_uri) {
  190. $matches = [];
  191. return true;
  192. } else {
  193. return false;
  194. }
  195. }
  196. }
  197. }
  198. }