Router.php 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. <?php
  2. namespace KarmaFW\Routing;
  3. use \KarmaFW\WebApp;
  4. class Router
  5. {
  6. private static $routes = [];
  7. private static $routed_url = null;
  8. private static $config = [];
  9. public static function config($config)
  10. {
  11. self::$config = $config;
  12. }
  13. public static function setConfig($key, $value)
  14. {
  15. self::$config[$key] = $value;
  16. }
  17. public static function getConfig($key)
  18. {
  19. return self::$config[$key];
  20. }
  21. public static function group($config, $callable)
  22. {
  23. $old_config = self::$config;
  24. self::$config = $config;
  25. $callable();
  26. self::$config = $old_config;
  27. }
  28. // Register a route in the router
  29. public static function add($methods, $url_match, $callback=null, $type_match='exact', $regex_params=[])
  30. {
  31. $route = new Route();
  32. if (! empty(self::$config['prefix'])) {
  33. // ex: $prefix == "/fr"
  34. $route->setPrefix(self::$config['prefix'], 'exact', self::$config['prefix']);
  35. } else if (! empty(self::$config['prefix_regex'])) {
  36. // ex: $prefix == "/[a-zA-Z0-9-]+"
  37. $get_prefix = empty(self::$config['get_prefix']) ? null : self::$config['get_prefix'];
  38. $route->setPrefix(self::$config['prefix_regex'], 'regex', $get_prefix);
  39. } else if (! empty(self::$config['prefix_array'])) {
  40. // ex: $prefix == ["/fr", "/us"]
  41. $get_prefix = empty(self::$config['get_prefix']) ? null : self::$config['get_prefix'];
  42. $route->setPrefix(self::$config['prefix_array'], 'array', $get_prefix);
  43. }
  44. if (! empty(self::$config['before_callback'])) {
  45. $route->setBeforeCallback(self::$config['before_callback']);
  46. }
  47. $route->setMatchUrl($url_match);
  48. $route->setCallback($callback);
  49. $route->setMatchType($type_match);
  50. $route->setRegexParams($regex_params);
  51. if (! is_array($methods)) {
  52. $methods = [$methods];
  53. }
  54. foreach ($methods as $method) {
  55. $route->setMethod($method);
  56. }
  57. self::$routes[] = $route;
  58. return $route;
  59. }
  60. public static function error404($callback=null)
  61. {
  62. return self::all('.*', $callback, 'regex');
  63. }
  64. // Allow whatever method (GET, POST, HEAD, OPTION, DELETE, PUT, ...)
  65. public static function all($url_match, $callback=null, $type_match='exact', $regex_params=[])
  66. {
  67. return self::Add(null, $url_match, $callback, $type_match, $regex_params);
  68. }
  69. // GET method
  70. public static function get($url_match, $callback=null, $type_match='exact', $regex_params=[])
  71. {
  72. return self::Add('GET', $url_match, $callback, $type_match, $regex_params);
  73. }
  74. // POST method
  75. public static function post($url_match, $callback=null, $type_match='exact', $regex_params=[])
  76. {
  77. return self::Add('POST', $url_match, $callback, $type_match, $regex_params);
  78. }
  79. // DELETE method
  80. public static function delete($url_match, $callback=null, $type_match='exact', $regex_params=[])
  81. {
  82. return self::Add('DELETE', $url_match, $callback, $type_match, $regex_params);
  83. }
  84. // PUT method
  85. public static function put($url_match, $callback=null, $type_match='exact', $regex_params=[])
  86. {
  87. return self::Add('PUT', $url_match, $callback, $type_match, $regex_params);
  88. }
  89. // HEAD method
  90. public static function head($url_match, $callback=null, $type_match='exact', $regex_params=[])
  91. {
  92. return self::Add('HEAD', $url_match, $callback, $type_match, $regex_params);
  93. }
  94. // PATCH method
  95. public static function patch($url_match, $callback=null, $type_match='exact', $regex_params=[])
  96. {
  97. return self::Add('PATCH', $url_match, $callback, $type_match, $regex_params);
  98. }
  99. // OPTIONS method
  100. public static function options($url_match, $callback=null, $type_match='exact', $regex_params=[])
  101. {
  102. return self::Add('OPTIONS', $url_match, $callback, $type_match, $regex_params);
  103. }
  104. // Lookup the first matching route then execute it
  105. public static function routeByUrl($request_method, $request_uri, $debug = false)
  106. {
  107. foreach (self::$routes as $route) {
  108. if ($debug) {
  109. pre($route);
  110. }
  111. $route->setCalledMethod($request_method);
  112. $route->setCalledUrl($request_uri);
  113. $match = $route->match($request_method, $request_uri);
  114. if ($match) {
  115. if ($debug) {
  116. echo " => MATCH !<br />" . PHP_EOL;
  117. }
  118. $before_callback = $route->getBeforeCallback();
  119. if (! empty($before_callback)) {
  120. $before_callback($route);
  121. }
  122. $callback = $route->getCallback();
  123. if (empty($callback)) {
  124. // Do nothing
  125. return 0;
  126. } else if (is_callable($callback)) {
  127. self::$routed_url = $route;
  128. self::routeRun($route, $callback, $request_method, $request_uri);
  129. } else {
  130. // Error: callback not callable
  131. return null;
  132. }
  133. return $route;
  134. }
  135. }
  136. // No matching route
  137. return false;
  138. }
  139. public static function routeRun($route, $callback, $request_method, $request_uri)
  140. {
  141. $matched_params = $route->getMatchedParams();
  142. if (gettype($callback) == 'array') {
  143. //echo " => ARRAY !<br />" . PHP_EOL;
  144. //pre($callback, 1);
  145. $controller = new $callback[0]($request_uri, $request_method, $route);
  146. WebApp::$controller = $controller;
  147. call_user_func([$controller, $callback[1]], $matched_params);
  148. } else {
  149. //echo " => FUNCTION !<br />" . PHP_EOL;
  150. //pre($callback, 1);
  151. $callback($route, $matched_params);
  152. }
  153. return true;
  154. }
  155. // Search a route by its name
  156. public static function findRouteByName($expected_route_name, $debug = false)
  157. {
  158. if (empty($expected_route_name)) {
  159. return null;
  160. }
  161. foreach (self::$routes as $route) {
  162. $route_name = $route->getName();
  163. if (! empty($route_name) && $route_name == $expected_route_name) {
  164. return $route;
  165. }
  166. }
  167. return null;
  168. }
  169. public static function getRouteUrl($route_name, $urls_args=[])
  170. {
  171. if (empty($urls_args)) {
  172. $urls_args = array();
  173. }
  174. if (! is_array($urls_args)) {
  175. $urls_args = array($urls_args);
  176. }
  177. $route = Router::findRouteByName($route_name);
  178. if (empty($route) || $route === true) {
  179. return null;
  180. }
  181. //pre($route, 1);
  182. $get_prefix = $route->getCallbackGetPrefix();
  183. //pre($get_prefix, 0, 'get_prefix: ');
  184. $link = $route->getMatchUrl();
  185. if ($get_prefix) {
  186. $link = $get_prefix . $link;
  187. }
  188. //pre($link, 1, 'link: ');
  189. $link = rtrim($link, '$');
  190. $link = ltrim($link, '^');
  191. $link = str_replace('\\.', '.', $link);
  192. $link = str_replace('\\?', '?', $link);
  193. $link = str_replace('\\+', '+', $link);
  194. $link = str_replace('\\-', '-', $link);
  195. if (! empty($urls_args)) {
  196. foreach ($urls_args as $arg_value) {
  197. $pos1 = strpos($link, '(');
  198. if ($pos1 === false) {
  199. break;
  200. }
  201. $pos2 = strpos($link, ')', $pos1);
  202. if ($pos2 === false) {
  203. break;
  204. }
  205. $link = substr($link, 0, $pos1) . $arg_value . substr($link, $pos2+1);
  206. }
  207. }
  208. return $link;
  209. }
  210. public static function printRoutes()
  211. {
  212. dump(self::$routes);
  213. exit;
  214. }
  215. public static function getRoutedUrl()
  216. {
  217. return self::$routed_url;
  218. }
  219. }