Route 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. <?php
  2. /**
  3. * @method static Macaw get(string $route, Callable $callback)
  4. * @method static Macaw post(string $route, Callable $callback)
  5. * @method static Macaw put(string $route, Callable $callback)
  6. * @method static Macaw delete(string $route, Callable $callback)
  7. * @method static Macaw options(string $route, Callable $callback)
  8. * @method static Macaw head(string $route, Callable $callback)
  9. *
  10. */
  11. class Route {
  12. public static $halts = false;
  13. public static $routes = array();
  14. public static $methods = array();
  15. public static $callbacks = array();
  16. public static $patterns = array(
  17. ':any' => '[^/]+',
  18. ':num' => '[0-9]+',
  19. ':all' => '.*',
  20. );
  21. public static $error_callback;
  22. /**
  23. * Defines a route w/ callback and method
  24. */
  25. public static function __callstatic($method, $params) {
  26. $uri = dirname($_SERVER['PHP_SELF']) . '/' . $params[0];
  27. $callback = $params[1];
  28. array_push(self::$routes, $uri);
  29. array_push(self::$methods, strtoupper($method));
  30. array_push(self::$callbacks, $callback);
  31. }
  32. /**
  33. *
  34. * Defines callback if route is not found
  35. */
  36. public static function error($callback) {
  37. self::$error_callback = $callback;
  38. }
  39. public static function haltOnMatch($flag = true) {
  40. self::$halts = $flag;
  41. }
  42. /**
  43. * Runs the callback for the given request
  44. */
  45. public static function dispatch() {
  46. $uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
  47. $method = $_SERVER['REQUEST_METHOD'];
  48. $searches = array_keys(static::$patterns);
  49. $replaces = array_values(static::$patterns);
  50. $found_route = false;
  51. self::$routes = preg_replace('/\/+/', '/', self::$routes);
  52. // Check if route is defined without regex
  53. if (in_array($uri, self::$routes)) {
  54. $route_pos = array_keys(self::$routes, $uri);
  55. foreach ($route_pos as $route) {
  56. // Using an ANY option to match both GET and POST requests
  57. if (self::$methods[$route] == $method || self::$methods[$route] == 'ANY') {
  58. $found_route = true;
  59. // If route is not an object
  60. if (!is_object(self::$callbacks[$route])) {
  61. // Grab all parts based on a / separator
  62. $parts = explode('/', self::$callbacks[$route]);
  63. // Collect the last index of the array
  64. $last = end($parts);
  65. // Grab the controller name and method call
  66. $segments = explode('@', $last);
  67. global $ViewPath;
  68. $ViewPath = $segments[0] . "\\" . $segments[1];
  69. // Instanitate controller
  70. $controller = new $segments[0]();
  71. // Call method
  72. $controller->{$segments[1]}();
  73. if (self::$halts) {
  74. return;
  75. }
  76. } else {
  77. // Call closure
  78. call_user_func(self::$callbacks[$route]);
  79. if (self::$halts) {
  80. return;
  81. }
  82. }
  83. }
  84. }
  85. } else {
  86. // Check if defined with regex
  87. $pos = 0;
  88. foreach (self::$routes as $route) {
  89. if (strpos($route, ':') !== false) {
  90. $route = str_replace($searches, $replaces, $route);
  91. }
  92. if (preg_match('#^' . $route . '$#', $uri, $matched)) {
  93. if (self::$methods[$pos] == $method || self::$methods[$pos] == 'ANY') {
  94. $found_route = true;
  95. // Remove $matched[0] as [1] is the first parameter.
  96. array_shift($matched);
  97. if (!is_object(self::$callbacks[$pos])) {
  98. // Grab all parts based on a / separator
  99. $parts = explode('/', self::$callbacks[$pos]);
  100. // Collect the last index of the array
  101. $last = end($parts);
  102. // Grab the controller name and method call
  103. $segments = explode('@', $last);
  104. // Instanitate controller
  105. $controller = new $segments[0]();
  106. // Fix multi parameters
  107. if (!method_exists($controller, $segments[1])) {
  108. echo "controller and action not found";
  109. } else {
  110. call_user_func_array(array($controller, $segments[1]), $matched);
  111. }
  112. if (self::$halts) {
  113. return;
  114. }
  115. } else {
  116. call_user_func_array(self::$callbacks[$pos], $matched);
  117. if (self::$halts) {
  118. return;
  119. }
  120. }
  121. }
  122. }
  123. $pos++;
  124. }
  125. }
  126. // Run the error callback if the route was not found
  127. if ($found_route == false) {
  128. if (!self::$error_callback) {
  129. self::$error_callback = function () {
  130. header($_SERVER['SERVER_PROTOCOL'] . " 404 Not Found");
  131. include "Public/error/404.html";
  132. };
  133. } else {
  134. if (is_string(self::$error_callback)) {
  135. self::get($_SERVER['REQUEST_URI'], self::$error_callback);
  136. self::$error_callback = null;
  137. self::dispatch();
  138. return;
  139. }
  140. }
  141. call_user_func(self::$error_callback);
  142. }
  143. }
  144. }