Macaw.php 4.4 KB

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