Router.php 6.1 KB

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