Last active
January 5, 2021 04:46
-
-
Save jason-napolitano/208d0e5e27a69957f4af21cedfdbfb86 to your computer and use it in GitHub Desktop.
Router.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* A facade class for the Core Router Module. Used to make routed calls using | |
* more practical and simple invocations for each Route. | |
* | |
* @author Jason Napolitano <jnapolitanoit@gmail.com> | |
* @license MIT | |
*/ | |
abstract class RouteHandler | |
{ | |
/** | |
* Router instance | |
* | |
* @var Router $router The Router class | |
*/ | |
public static Router $router; | |
// -------------------------------------------------------------------- | |
/** | |
* Router constructor | |
* | |
* @return Router | |
*/ | |
public static function start(): Router | |
{ | |
self::$router = new Router(); | |
return self::$router; | |
} | |
// -------------------------------------------------------------------- | |
/** | |
* A facade function to preform GET requests | |
* | |
* @param string $uri | |
* @param callable $callable | |
* | |
*/ | |
public static function get(string $uri, callable $callable): void | |
{ | |
self::$router->create('GET', $uri, $callable); | |
} | |
// -------------------------------------------------------------------- | |
/** | |
* A facade function to preform POST requests | |
* | |
* @param string $uri | |
* @param callable $callable | |
* | |
*/ | |
public static function post(string $uri, callable $callable): void | |
{ | |
self::$router->create('POST', $uri, $callable); | |
} | |
// -------------------------------------------------------------------- | |
/** | |
* A facade function to preform PUT requests | |
* | |
* @param string $uri | |
* @param callable $callable | |
* | |
*/ | |
public static function put(string $uri, callable $callable): void | |
{ | |
self::$router->create('PUT', $uri, $callable); | |
} | |
// -------------------------------------------------------------------- | |
/** | |
* A facade function to preform PATCH requests | |
* | |
* @param string $uri | |
* @param callable $callable | |
* | |
*/ | |
public static function patch(string $uri, callable $callable): void | |
{ | |
self::$router->create('PATCH', $uri, $callable); | |
} | |
// -------------------------------------------------------------------- | |
/** | |
* A facade function to preform DELETE requests | |
* | |
* @param string $uri | |
* @param callable $callable | |
* | |
*/ | |
public static function delete(string $uri, callable $callable): void | |
{ | |
self::$router->create('DELETE', $uri, $callable); | |
} | |
// ------------------------------------------------------------------------ | |
/** | |
* A facade function to preform DELETE requests | |
* | |
* @param string $uri | |
* @param callable $callable | |
* | |
*/ | |
public static function options(string $uri, callable $callable): void | |
{ | |
self::$router->create('OPTIONS', $uri, $callable); | |
} | |
// ------------------------------------------------------------------------ | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* A simple yet effective, Object Oriented, REST capable PHP micro router. Can | |
* easily be used as a `stand-alone` Router or implemented with composers PSR4 | |
* or your own PSR4 autoloader | |
* | |
* @package Core\Services\Router | |
*/ | |
class Router | |
{ | |
/** | |
* Request URI | |
* | |
* @var string | |
*/ | |
protected string $requestUri; | |
/** | |
* Request method | |
* | |
* @var string | |
*/ | |
protected string $requestMethod; | |
/** | |
* Array of HTTP methods | |
* | |
* @var array | |
*/ | |
private array $httpMethods = [ | |
'get', | |
'post', | |
'put', | |
'patch', | |
'delete', | |
]; | |
/** | |
* Wildcard patterns | |
* | |
* @var array $wildCards | |
*/ | |
private array $wildCards = [ | |
'int' => '/^[0-9]+$/', | |
'any' => '/^[0-9A-Za-z]+$/', | |
]; | |
// ------------------------------------------------------------------------ | |
/** | |
* If all routes will share a common base path, it can be set here in the constructor | |
* | |
* @param string $basePath | |
*/ | |
public function __construct( | |
protected string $basePath = '' | |
) | |
{ | |
// Remove query string and trim trailing slash | |
$this->requestUri = rtrim(strtok($_SERVER['REQUEST_URI'], '?'), '/'); | |
$this->requestMethod = $this->determineHttpMethod(); | |
} | |
// ------------------------------------------------------------------------ | |
/** | |
* Point a method/route to its target and create a new route request | |
* | |
* @param string $method The HTTP method to respond to (GET, POST, PUT, DELETE, or PATCH) | |
* @param string $route The uri route (with any wild cards) to respond to | |
* @param callable $callable The method to execute when a successful route is matched | |
*/ | |
public function create(string $method, string $route, callable $callable): void | |
{ | |
$method = strtolower($method); | |
if ( $route === '/' ) { | |
$route = $this->basePath; | |
} else { | |
$route = $this->basePath . $route; | |
} | |
$matches = $this->matchWilCards($route); | |
if ( is_array($matches) && $method === $this->requestMethod ) { | |
// Router match and request method matches | |
call_user_func_array($callable, $matches); | |
} | |
} | |
// ------------------------------------------------------------------------ | |
/** | |
* Determine method | |
* | |
* Determine which HTTP method was sent | |
* | |
* @return string | |
*/ | |
private function determineHttpMethod(): string | |
{ | |
$method = strtolower($_SERVER['REQUEST_METHOD']); | |
if ( in_array($method, $this->httpMethods, true) ) { | |
return $method; | |
} | |
return 'get'; | |
} | |
// ------------------------------------------------------------------------ | |
/** | |
* Match wild cards | |
* | |
* Check if any wild cards are supplied. | |
* | |
* This will return false if there is a mis-match anywhere in the route, | |
* or it will return an array with the key => values being the user supplied variable names. | |
* | |
* If no variable names are supplied an empty array will be returned. | |
* | |
* TODO - Support for custom regex | |
* | |
* @param string $route The user-supplied route (with wild cards) to match against | |
* | |
* @return bool|array | |
*/ | |
private function matchWilCards(string $route): bool|array | |
{ | |
$variables = []; | |
$exp_request = explode('/', $this->requestUri); | |
$exp_route = explode('/', $route); | |
if ( count($exp_request) === count($exp_route) ) { | |
foreach ( $exp_route as $key => $value ) { | |
if ( $value === $exp_request[$key] ) { | |
// So far the routes are matching | |
continue; | |
} | |
if ( $value[0] === '(' && substr($value, -1) === ')' ) { | |
// A wild card has been supplied in the route at this position | |
$strip = str_replace(['(', ')'], '', $value); | |
$exp = explode(':', $strip); | |
$wc_type = $exp[0]; | |
if ( array_key_exists($wc_type, $this->wildCards) ) { | |
// Check if the regex pattern matches the supplied route segment | |
$pattern = $this->wildCards[$wc_type]; | |
if ( preg_match($pattern, $exp_request[$key]) ) { | |
if ( isset($exp[1]) ) { | |
// A variable was supplied, let's assign it | |
$variables[$exp[1]] = $exp_request[$key]; | |
} | |
// We have a matching pattern | |
continue; | |
} | |
} | |
} | |
// There is a mis-match | |
return false; | |
} | |
// All segments match | |
return $variables; | |
} | |
return false; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment