| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366 |
- <?php
- namespace KarmaFW\Routing;
- use \KarmaFW\WebApp;
- use \KarmaFW\App\Request;
- use \KarmaFW\App\Response;
- use \KarmaFW\App\ResponseError;
- use \KarmaFW\App\ResponseError404;
- class Router
- {
- private static $routes = [];
- private static $routed_url = null;
- private static $config = [];
- public static function config($config)
- {
- self::$config = $config;
- }
- public static function setConfig($key, $value)
- {
- self::$config[$key] = $value;
- }
-
- public static function getConfig($key)
- {
- return self::$config[$key];
- }
-
- public static function group($config, $callable)
- {
- $old_config = self::$config;
- self::$config = $config;
- $callable();
- self::$config = $old_config;
- }
- // Register a route in the router
- public static function add($methods, $url_match, $callback=null, $type_match='exact', $regex_params=[])
- {
- $route = new Route();
- if (! empty(self::$config['prefix'])) {
- // ex: $prefix == "/fr"
- $route->setPrefix(self::$config['prefix'], 'exact', self::$config['prefix']);
-
- } else if (! empty(self::$config['prefix_regex'])) {
- // ex: $prefix == "/[a-zA-Z0-9-]+"
- $get_prefix = empty(self::$config['get_prefix']) ? null : self::$config['get_prefix'];
- $route->setPrefix(self::$config['prefix_regex'], 'regex', $get_prefix);
- } else if (! empty(self::$config['prefix_array'])) {
- // ex: $prefix == ["/fr", "/us"]
- $get_prefix = empty(self::$config['get_prefix']) ? null : self::$config['get_prefix'];
- $route->setPrefix(self::$config['prefix_array'], 'array', $get_prefix);
- }
- if (! empty(self::$config['before_callback'])) {
- $route->setBeforeCallback(self::$config['before_callback']);
- }
- $route->setMatchUrl($url_match);
- $route->setCallback($callback);
- $route->setMatchType($type_match);
- $route->setRegexParams($regex_params);
-
- if (! is_array($methods)) {
- $methods = [$methods];
- }
- foreach ($methods as $method) {
- $route->setMethod($method);
- }
- self::$routes[] = $route;
- return $route;
- }
- public static function error404($callback=null)
- {
- return self::all('.*', $callback, 'regex');
- }
- // Allow whatever method (GET, POST, HEAD, OPTION, DELETE, PUT, ...)
- public static function all($url_match, $callback=null, $type_match='exact', $regex_params=[])
- {
- return self::Add(null, $url_match, $callback, $type_match, $regex_params);
- }
- // GET method
- public static function get($url_match, $callback=null, $type_match='exact', $regex_params=[])
- {
- return self::Add('GET', $url_match, $callback, $type_match, $regex_params);
- }
- // POST method
- public static function post($url_match, $callback=null, $type_match='exact', $regex_params=[])
- {
- return self::Add('POST', $url_match, $callback, $type_match, $regex_params);
- }
- // DELETE method
- public static function delete($url_match, $callback=null, $type_match='exact', $regex_params=[])
- {
- return self::Add('DELETE', $url_match, $callback, $type_match, $regex_params);
- }
- // PUT method
- public static function put($url_match, $callback=null, $type_match='exact', $regex_params=[])
- {
- return self::Add('PUT', $url_match, $callback, $type_match, $regex_params);
- }
- // HEAD method
- public static function head($url_match, $callback=null, $type_match='exact', $regex_params=[])
- {
- return self::Add('HEAD', $url_match, $callback, $type_match, $regex_params);
- }
- // PATCH method
- public static function patch($url_match, $callback=null, $type_match='exact', $regex_params=[])
- {
- return self::Add('PATCH', $url_match, $callback, $type_match, $regex_params);
- }
- // OPTIONS method
- public static function options($url_match, $callback=null, $type_match='exact', $regex_params=[])
- {
- return self::Add('OPTIONS', $url_match, $callback, $type_match, $regex_params);
- }
- // Lookup the first matching route then execute it
- public static function routeByUrl($request_method, $request_uri, $debug = false, $response = null)
- {
- foreach (self::$routes as $route) {
- if ($debug) {
- pre($route);
- }
- $route->setCalledMethod($request_method);
- $route->setCalledUrl($request_uri);
- $match = $route->match($request_method, $request_uri);
- if ($match) {
- if ($debug) {
- echo " => MATCH !<br />" . PHP_EOL;
- }
- $before_callback = $route->getBeforeCallback();
- if (! empty($before_callback)) {
- $before_callback($route);
- }
- $callback = $route->getCallback();
- if (empty($callback)) {
- // Do nothing
- return 0;
- } else if (is_callable($callback)) {
- self::$routed_url = $route;
- self::routeRun($route, $callback, $request_method, $request_uri, $response);
- } else {
- // Error: callback not callable
- return null;
- }
- return $route;
- }
- }
- // No matching route
- return false;
- }
- public static function routeRun($route, $callback, $request_method, $request_uri, $response=null)
- {
- $matched_params = $route->getMatchedParams();
- if (gettype($callback) == 'array') {
- //echo " => ARRAY !<br />" . PHP_EOL;
- //pre($callback, 1);
- $controller = new $callback[0]($request_uri, $request_method, $route, $response);
- WebApp::$controller = $controller;
- call_user_func([$controller, $callback[1]], $matched_params);
- } else {
- //echo " => FUNCTION !<br />" . PHP_EOL;
- //pre($callback, 1);
- $callback($request_uri, $request_method, $route, $matched_params, $response);
- }
- return true;
- }
- public static function routeRequest(Request $request, Response $response)
- {
- $request_method = $request->getMethod();
- $request_uri = $request->getUrl();
- foreach (self::$routes as $route) {
- $route->setCalledMethod($request_method);
- $route->setCalledUrl($request_uri);
- $match = $route->match($request_method, $request_uri);
- if ($match) {
- $before_callback = $route->getBeforeCallback();
- if (! empty($before_callback)) {
- $before_callback($route);
- }
- $callback = $route->getCallback();
- if (empty($callback)) {
- // route found but no callback defined
- //return 0;
- return new ResponseError404("<h1>Page not Found</h1><p>Warning: route found but no callback defined</p>");
- } else if (is_callable($callback)) {
- // OK !
- self::$routed_url = $route;
- $response = self::requestRouteRun($route, $callback, $request, $response);
- return $response;
- } else {
- // route found but callback is not callable
- //return null;
- return new ResponseError404("<h1>Page not Found</h1><p>Warning: route callback is not callable</p>");
- }
- }
- }
- // no matching route
- //return false;
- return new ResponseError404("<h1>Page not Found</h1><p>Warning: no matching route</p>");
- }
- public static function requestRouteRun(Route $route, callable $callback, Request $request, Response $response)
- {
- $matched_params = $route->getMatchedParams();
- if (gettype($callback) == 'array') {
- //echo " => ARRAY !<br />" . PHP_EOL;
- //pre($callback, 1);
- $controller = new $callback[0]($request, $response);
- WebApp::$controller = $controller;
- $route_response = call_user_func([$controller, $callback[1]], $matched_params);
- } else {
- //echo " => FUNCTION !<br />" . PHP_EOL;
- //pre($callback, 1);
- $route_response = $callback($request, $response, $matched_params);
- }
- if ($route_response instanceof Response) {
- $response = $route_response;
- } else if ($route_response) {
- return new ResponseError(500, "<h1>Server Error</h1><p>Error: \$response is not a Response</p>");
- } else {
- //return new ResponseError(500, "<h1>Server Error</h1><p>Error: \$response is empty</p>");
- }
- return $response;
- }
- // Search a route by its name
- public static function findRouteByName($expected_route_name, $debug = false)
- {
- if (empty($expected_route_name)) {
- return null;
- }
- foreach (self::$routes as $route) {
- $route_name = $route->getName();
- if (! empty($route_name) && $route_name == $expected_route_name) {
- return $route;
- }
- }
- return null;
- }
-
- public static function getRouteUrl($route_name, $urls_args=[])
- {
- if (empty($urls_args)) {
- $urls_args = array();
- }
- if (! is_array($urls_args)) {
- $urls_args = array($urls_args);
- }
- $route = Router::findRouteByName($route_name);
- if (empty($route) || $route === true) {
- return null;
- }
- //pre($route, 1);
- $get_prefix = $route->getCallbackGetPrefix();
- //pre($get_prefix, 0, 'get_prefix: ');
- $link = $route->getMatchUrl();
- if ($get_prefix) {
- $link = $get_prefix . $link;
- }
- //pre($link, 1, 'link: ');
- $link = rtrim($link, '$');
- $link = ltrim($link, '^');
- $link = str_replace('\\.', '.', $link);
- $link = str_replace('\\?', '?', $link);
- $link = str_replace('\\+', '+', $link);
- $link = str_replace('\\-', '-', $link);
- if (! empty($urls_args)) {
- foreach ($urls_args as $arg_value) {
- $pos1 = strpos($link, '(');
- if ($pos1 === false) {
- break;
- }
- $pos2 = strpos($link, ')', $pos1);
- if ($pos2 === false) {
- break;
- }
- $link = substr($link, 0, $pos1) . $arg_value . substr($link, $pos2+1);
- }
- }
- return $link;
- }
- public static function printRoutes()
- {
- dump(self::$routes);
- exit;
- }
- public static function getRoutedUrl()
- {
- return self::$routed_url;
- }
- }
|