You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
251 lines
9.1 KiB
PHP
251 lines
9.1 KiB
PHP
<?php
|
|
|
|
require_once 'RequestMethod.php';
|
|
|
|
/**
|
|
* @class Main class of the Link router that helps you create and deploy routes
|
|
*/
|
|
class Link
|
|
{
|
|
|
|
/**
|
|
* @var array A collection of the routes originally passed into all function. Used by static function route
|
|
*/
|
|
private static $routes = array();
|
|
|
|
/**
|
|
* @var array A collection of functions that are executed before a route completion ( valid for all routes ), aka universal before functions
|
|
*/
|
|
private static $beforeFuncs = array();
|
|
|
|
/**
|
|
* @var array A collection of function that are executed after a route completion ( valid for all routes ), aka universal after functions
|
|
*/
|
|
private static $afterFuncs = array();
|
|
|
|
/**
|
|
* Static function of the class Link that deploys the route according to the passed handler and path
|
|
*
|
|
* @param array $routes An array of combination of the path and its handler, that are final deployed for a particular url
|
|
*/
|
|
public static function all( $routes )
|
|
{
|
|
|
|
/* Call all functions that are to be executed before routing */
|
|
foreach( self::$beforeFuncs as $beforeFunc ) {
|
|
if( $beforeFunc[1] ) {
|
|
call_user_func_array( $beforeFunc[0] , $beforeFunc[1] );
|
|
} else {
|
|
call_user_func( $beforeFunc[0] );
|
|
}
|
|
}
|
|
|
|
self::$routes = $routes;
|
|
$method = self::getRequestMethod();
|
|
$acceptedMethods = RequestMethod::all();
|
|
$path = '/';
|
|
$handler = null;
|
|
$matched = array();
|
|
$middleware = null;
|
|
if ( !empty ( $_SERVER['PATH_INFO'] ) ) {
|
|
$path = $_SERVER['PATH_INFO'];
|
|
} else if ( !empty ( $_SERVER['REQUEST_URI'] ) ) {
|
|
$parts = explode('/', $_SERVER['REQUEST_URI']);
|
|
$startingIndex = -1;
|
|
for ($i = count($parts) - 1; $i > -1 && $startingIndex === -1; $i--) {
|
|
if ($parts[$i] === 'index.php' || $parts[$i] === 'api') {
|
|
$startingIndex = $i + 1;
|
|
}
|
|
}
|
|
$path = '';
|
|
for ($i = $startingIndex; $i < count($parts); $i++) {
|
|
$path .= "/{$parts[$i]}";
|
|
}
|
|
}
|
|
|
|
if ( isset($routes[$path] ) ) {
|
|
if( is_array( $routes[$path] ) ) {
|
|
$handler = $routes[$path][0];
|
|
$middleware = $routes[$path][2];
|
|
$acceptedMethods = $routes[$path][3];
|
|
} else {
|
|
$handler = $routes[$path];
|
|
}
|
|
} else if ( $routes ) {
|
|
|
|
$regex = array(
|
|
'/{i}/',
|
|
'/{s}/',
|
|
'/{a}/'
|
|
);
|
|
|
|
$replacements = array(
|
|
'([\d]+)' ,
|
|
'([a-zA-Z]+)',
|
|
'([\w-]+)'
|
|
);
|
|
|
|
foreach ( $routes as $routePath => $routeDesc ){
|
|
$routePath = preg_replace( $regex, $replacements, $routePath );
|
|
if( preg_match( '#^/?' . $routePath . '/?$#', $path, $matches ) ){
|
|
if( is_array( $routeDesc ) ) {
|
|
$handler = $routeDesc[0];
|
|
if( isset( $routeDesc[2] )) {
|
|
$middleware = $routeDesc[2];
|
|
$acceptedMethods = $routeDesc[3];
|
|
}
|
|
}
|
|
else
|
|
$handler = $routeDesc;
|
|
$matched = $matches;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
unset( $matched[0] );
|
|
|
|
if( isset($middleware) ){
|
|
$newMatched = self::callFunction( $middleware, $matched, $method, $acceptedMethods );
|
|
/* If new wildcard param are there pass them to main handler */
|
|
if( $newMatched ) {
|
|
self::callFunction( $handler, $newMatched, $method, $acceptedMethods );
|
|
} else {
|
|
self::callFunction( $handler, $matched, $method, $acceptedMethods );
|
|
}
|
|
} else {
|
|
self::callFunction( $handler, $matched, $method, $acceptedMethods );
|
|
}
|
|
|
|
/* Call all the function that are to be executed after routing */
|
|
foreach( self::$afterFuncs as $afterFunc )
|
|
if( $afterFunc[1] ) {
|
|
call_user_func_array( $afterFunc[0] , $afterFunc[1] );
|
|
} else {
|
|
call_user_func( $afterFunc[0] );
|
|
}
|
|
}
|
|
|
|
private static function getRequestMethod() {
|
|
$headers = getallheaders();
|
|
|
|
$uppercaseHeaders = array();
|
|
foreach ($headers as $header => $value) {
|
|
$uppercaseHeaders[strtoupper($header)] = $value;
|
|
}
|
|
|
|
if (isset($uppercaseHeaders['X-HTTP-METHOD-OVERRIDE'])) {
|
|
return $uppercaseHeaders['X-HTTP-METHOD-OVERRIDE'];
|
|
}
|
|
|
|
return $_SERVER['REQUEST_METHOD'];
|
|
}
|
|
|
|
/**
|
|
* Static function that helps you generate links effortlessly and pass parameters to them, thus enabling to generate dynamic links
|
|
*
|
|
* @param string $name name of the route for which the link has to be generated
|
|
* @param array $params An array of parameters that are replaced in the route if it contains wildcards
|
|
* For e.g. if route is /name/{i}/{a} and parameters passed are 1, aps then link generated will be /name/1/aps
|
|
*/
|
|
public static function route( $name, $params = array() )
|
|
{
|
|
$href = null;
|
|
foreach ( self::$routes as $routePath => $routeDesc ) {
|
|
if( is_array( $routeDesc ) ){
|
|
if( $name == $routeDesc[1] ){
|
|
$href = $routePath;
|
|
for( $i = 0; $i < count($params); $i++){
|
|
$href = preg_replace('#{(.*?)}#', $params[$i], $href, 1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return $href;
|
|
}
|
|
|
|
/**
|
|
* Static function to handle cases when route is not found, call handler of 404 if defined else
|
|
* sends a 404 header
|
|
*/
|
|
public static function handle404()
|
|
{
|
|
/* Call '404' route if it exists */
|
|
if( isset ( self::$routes['404'] ) ) {
|
|
call_user_func( self::$routes['404'] );
|
|
} else {
|
|
header($_SERVER["SERVER_PROTOCOL"]." 404 Not Found");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Static function to handle both middlewares' call and main handler's call.
|
|
*
|
|
* @param array|string $handler Handler that will handle the routes call or middleware
|
|
* @param array $matched The parameters that we get from the route wildcard
|
|
* @param $method string request method
|
|
* @param $acceptedMethods array Accepted request methods for the request
|
|
* @return array $newParams The parameters return in the case of middleware if you intend to
|
|
* the wildcards that were originally passed, this newParams will
|
|
* be next passed to main handler
|
|
*/
|
|
public static function callFunction( $handler , $matched, $method, $acceptedMethods )
|
|
{
|
|
if (!in_array($method, $acceptedMethods)) {
|
|
print_r('Request method ' . $method . ' not allowed');
|
|
header($_SERVER['SERVER_PROTOCOL'] . ' 405 Method Not Allowed', true, 405);
|
|
die();
|
|
}
|
|
|
|
if ( $handler ) {
|
|
if ( is_callable( $handler ) ) {
|
|
$newParams = call_user_func_array( $handler, $matched ) ;
|
|
} else {
|
|
|
|
/* Check if class exists in the case user is using RESTful pattern */
|
|
|
|
if( class_exists( $handler ) ) {
|
|
$instanceOfHandler = new $handler(); // Won't work in case of middleware since we aren't using RESTful in that
|
|
} else {
|
|
print_r('Class or function ' . $handler . ' not found');
|
|
header($_SERVER['SERVER_PROTOCOL'] . ' 500 Internal Server Error', true, 500);
|
|
die();
|
|
}
|
|
}
|
|
} else {
|
|
self::handle404();
|
|
}
|
|
|
|
if( isset( $instanceOfHandler ) ) {
|
|
if( method_exists( $instanceOfHandler, $method ) ) {
|
|
$newParams = call_user_func_array( array( $instanceOfHandler, $method ), $matched );
|
|
}
|
|
}
|
|
if( isset( $newParams ) && $newParams ) {
|
|
return $newParams;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Static function to add functions that are to be excuted before each routing, must be called before Link::all
|
|
*
|
|
* @param string $funcName Name of the funtion to be called upon before
|
|
* @param array $params Array of parameters that are to be passed to before function, can be null but if not
|
|
* it must be an array
|
|
*/
|
|
public static function before( $funcName, $params = null )
|
|
{
|
|
array_push( self::$beforeFuncs, array($funcName, $params));
|
|
}
|
|
|
|
/**
|
|
* Static function to add functions that are to be excuted after each routing, must be called before Link::all
|
|
*
|
|
* @param string $funcName Name of the funtion to be called upon after
|
|
* @param array $params Array of parameters that are to be passed to after function, can be null but if not
|
|
* it must be an array
|
|
*/
|
|
public static function after( $funcName, $params = null )
|
|
{
|
|
array_push( self::$afterFuncs, array($funcName, $params));
|
|
}
|
|
} |