Skip to content

Instantly share code, notes, and snippets.

@arvindsvt
Last active October 30, 2019 15:09
Show Gist options
  • Save arvindsvt/ca9c4e82b782dde46b85d53a384989d6 to your computer and use it in GitHub Desktop.
Save arvindsvt/ca9c4e82b782dde46b85d53a384989d6 to your computer and use it in GitHub Desktop.
EasyRouter - A simple PHP powered, REST capable Router and Facade for easier route calls, and an example static and Class implementation
https://github.com/azeemhassni/simplest-php-router
https://github.com/arvindsvt/PHP-Custom-MVC
<?php namespace EasyRouter {
/**
* A simple, Object Oriented, yet effective REST capable PHP micro router. Can
* easily be used as a `stand-alone` Router or implemented with composers PSR4
* or your own PSR4 autoloader. See link reference below for a simple, and yet
* effective PSR4 Autoloader I had made.
*
* @link https://github.com/jason-napolitano/PSR4-Autoloader
*
* @package EasyRouter
*/
class Router
{
/**
* Base Path
*
* @var string
*/
protected $base_path;
/**
* Request URI
*
* @var string
*/
protected $request_uri;
/**
* Request method
*
* @var string
*/
protected $request_method;
/**
* Array of HTTP methods
*
* @var array
*/
private $http_methods = [
'get',
'post',
'put',
'patch',
'delete'
];
/**
* Wildcard patterns
*
* @var array $wild_cards
*/
private $wild_cards = [
'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 $base_path
*/
public function __construct(string $base_path = '')
{
$this->base_path = $base_path;
// Remove query string and trim trailing slash
$this->request_uri = rtrim(strtok($_SERVER['REQUEST_URI'], '?'), '/');
$this->request_method = $this->_determine_http_method();
}
// ------------------------------------------------------------------------
/**
* 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)
{
$method = strtolower($method);
if ($route === '/') {
$route = $this->base_path;
} else {
$route = $this->base_path . $route;
}
$matches = $this->_match_wild_cards($route);
if (is_array($matches) && $method === $this->request_method) {
// Router match and request method matches
call_user_func_array($callable, $matches);
}
}
// ------------------------------------------------------------------------
/**
* Determine method
*
* Determine which HTTP method was sent
*
* @return string
*/
private function _determine_http_method(): string
{
$method = strtolower($_SERVER['REQUEST_METHOD']);
if (in_array($method, $this->http_methods, 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 mixed
*/
private function _match_wild_cards(string $route)
{
$variables = [];
$exp_request = explode('/', $this->request_uri);
$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;
} elseif ($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->wild_cards)) {
// Check if the regex pattern matches the supplied route segment
$pattern = $this->wild_cards[$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;
}
// ------------------------------------------------------------------------
}
}
<?php namespace EasyRouter {
/**
* An Object Oriented facade class for the Core Router Module. Used to make
* routed calls using more practical and simple invocations for each Route.
*
* @package EasyRouter
* @author Jason Napolitano <jnapolitanoit@gmail.com>
*/
abstract class EasyRouterFacade
{
/**
* EasyRouter instance
*
* @var EasyRouter $router The EasyRouter class
*/
public static $router;
// --------------------------------------------------------------------
/**
* Router constructor
*
* @return EasyRouter
*/
public static function start(): EasyRouter
{
self::$router = new EasyRouter();
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);
}
// ------------------------------------------------------------------------
}
}
<?php declare(strict_types=1);
namespace Examples {
// CLASS IMPORTS ----------------------------------------------------------
use EasyRouterFacade as EasyRouter;
/**
* An example of how to use the EasyRouter in a PHP class
*
* @package Examples
*/
class Routes
{
/**
* Routes constructor
*/
public function __construct()
{
// Start the router
EasyRouter::start();
// Respond to a home page GET request
EasyRouter::get('/', function () {
// Build the data to be passed to json_encode(...)
$data = [
'message' => 'Welcome to the home area!',
'success' => true,
'status' => 200
];
// Setting the Content-Type
header('Content-Type: application/json; charset=UTF-8');
// Outputting the JSON data
echo \json_encode($data, JSON_PRETTY_PRINT);
});
// Respond to an about page GET request
EasyRouter::get('/about', function () {
// Build the data to be passed to json_encode(...)
$data = [
'message' => 'Welcome to the about area!',
'success' => true,
'status' => 200
];
// Outputting the JSON data
header('Content-Type: application/json; charset=UTF-8');
// Outputting the JSON data
echo \json_encode($data, JSON_PRETTY_PRINT);
});
}
// --------------------------------------------------------------------
}
}
<?php
// An example of using EasyRouter in a procedural PHP file, let's call this `index.php`\
// for arguments sake =D
// Import EasyRouter
use EasyRouter;
// New Routes Instance
$router = new EasyRouter();
// Respond to a home page GET request
$router->create('GET', '/', function () {
// Build the data to be passed to json_encode(...)
$data = [
'message' => 'Welcome to the home area!',
'success' => true,
'status' => 200
];
// Setting the Content-Type
header('Content-Type: application/json; charset=UTF-8');
// Outputting the JSON data
echo \json_encode($data, JSON_PRETTY_PRINT);
});
// Respond to an about page GET request
$router->create('GET', '/about', function () {
// Build the data to be passed to json_encode(...)
$data = [
'message' => 'Welcome to the home area!',
'success' => true,
'status' => 200
];
// Setting the Content-Type
header('Content-Type: application/json; charset=UTF-8');
// Outputting the JSON data
echo \json_encode($data, JSON_PRETTY_PRINT);
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment