Router.php 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. <?php
  2. namespace Typecho;
  3. use Typecho\Router\Parser;
  4. use Typecho\Router\Exception as RouterException;
  5. /**
  6. * Typecho组件基类
  7. *
  8. * @package Router
  9. */
  10. class Router
  11. {
  12. /**
  13. * 当前路由名称
  14. *
  15. * @access public
  16. * @var string
  17. */
  18. public static $current;
  19. /**
  20. * 已经解析完毕的路由表配置
  21. *
  22. * @access private
  23. * @var mixed
  24. */
  25. private static $routingTable = [];
  26. /**
  27. * 解析路径
  28. *
  29. * @access public
  30. *
  31. * @param string|null $pathInfo 全路径
  32. * @param mixed $parameter 输入参数
  33. *
  34. * @return false|Widget
  35. * @throws \Exception
  36. */
  37. public static function match(?string $pathInfo, $parameter = null)
  38. {
  39. foreach (self::$routingTable as $key => $route) {
  40. if (preg_match($route['regx'], $pathInfo, $matches)) {
  41. self::$current = $key;
  42. try {
  43. /** 载入参数 */
  44. $params = null;
  45. if (!empty($route['params'])) {
  46. unset($matches[0]);
  47. $params = array_combine($route['params'], $matches);
  48. }
  49. return Widget::widget($route['widget'], $parameter, $params);
  50. } catch (\Exception $e) {
  51. if (404 == $e->getCode()) {
  52. Widget::destroy($route['widget']);
  53. continue;
  54. }
  55. throw $e;
  56. }
  57. }
  58. }
  59. return false;
  60. }
  61. /**
  62. * 路由分发函数
  63. *
  64. * @throws RouterException|\Exception
  65. */
  66. public static function dispatch()
  67. {
  68. /** 获取PATHINFO */
  69. $pathInfo = Request::getInstance()->getPathInfo();
  70. foreach (self::$routingTable as $key => $route) {
  71. if (preg_match($route['regx'], $pathInfo, $matches)) {
  72. self::$current = $key;
  73. try {
  74. /** 载入参数 */
  75. $params = null;
  76. if (!empty($route['params'])) {
  77. unset($matches[0]);
  78. $params = array_combine($route['params'], $matches);
  79. }
  80. $widget = Widget::widget($route['widget'], null, $params);
  81. if (isset($route['action'])) {
  82. $widget->{$route['action']}();
  83. }
  84. return;
  85. } catch (\Exception $e) {
  86. if (404 == $e->getCode()) {
  87. Widget::destroy($route['widget']);
  88. continue;
  89. }
  90. throw $e;
  91. }
  92. }
  93. }
  94. /** 载入路由异常支持 */
  95. throw new RouterException("Path '{$pathInfo}' not found", 404);
  96. }
  97. /**
  98. * 路由反解析函数
  99. *
  100. * @param string $name 路由配置表名称
  101. * @param array|null $value 路由填充值
  102. * @param string|null $prefix 最终合成路径的前缀
  103. *
  104. * @return string
  105. */
  106. public static function url(string $name, ?array $value = null, ?string $prefix = null): string
  107. {
  108. $route = self::$routingTable[$name];
  109. //交换数组键值
  110. $pattern = [];
  111. foreach ($route['params'] as $row) {
  112. $pattern[$row] = $value[$row] ?? '{' . $row . '}';
  113. }
  114. return Common::url(vsprintf($route['format'], $pattern), $prefix);
  115. }
  116. /**
  117. * 设置路由器默认配置
  118. *
  119. * @access public
  120. *
  121. * @param mixed $routes 配置信息
  122. *
  123. * @return void
  124. */
  125. public static function setRoutes($routes)
  126. {
  127. if (isset($routes[0])) {
  128. self::$routingTable = $routes[0];
  129. } else {
  130. /** 解析路由配置 */
  131. $parser = new Parser($routes);
  132. self::$routingTable = $parser->parse();
  133. }
  134. }
  135. /**
  136. * 获取路由信息
  137. *
  138. * @param string $routeName 路由名称
  139. *
  140. * @static
  141. * @access public
  142. * @return mixed
  143. */
  144. public static function get(string $routeName)
  145. {
  146. return self::$routingTable[$routeName] ?? null;
  147. }
  148. }