Skip to content

Instantly share code, notes, and snippets.

@DiyarD
Last active July 29, 2016 10:57
Show Gist options
  • Save DiyarD/e4c3c4b4d66cd2f10f8ffabe6bbfb6e2 to your computer and use it in GitHub Desktop.
Save DiyarD/e4c3c4b4d66cd2f10f8ffabe6bbfb6e2 to your computer and use it in GitHub Desktop.
A Very Simple PHP Router
<?php
class Router
{
protected $_routes;
protected $routeMethods = ['get', 'post'];
public function add($pattern, $callback, $options) {
$pattern = '/' . trim($pattern, '/');
$routerName = isset($options['name']) ? $options['name']: null;
$type = isset($options['type']) ? strtolower($options['type']) : 'get';
if(!in_array($type, $this->routeMethods)) {
throw new InvalidRequestMethodException("'{$type}' isn't a valid request type.");
}
$this->_routes[] = [
'pretty' => $pattern, //The pretty dev-readable version of the route pattern eg : /users/{username}
'route' => $this->parseRoute($pattern), //The actual regex route pattern
'type' => $type, //the request method/type
'callback' => $callback, //the callback to be run if the route matches
'name' => $routerName, //the route name to be used in generateRoute()
];
}
// Replaces the pretty placeholders with ugly regex
public function parseRoute($pattern) {
// Replace optional paramters eg( get('/users/{username}?') )
$pattern = preg_replace("/\/{[a-z]+}\?/", "(?:\/([a-zA-Z0-9-_.]*))?", $pattern);
// Replace required parameters eg( get('/articles/{slug}') )
$pattern = preg_replace("/{[a-z]+}/", '([a-zA-Z0-9-_.]*)', $pattern);
return $pattern;
}
public function run() {
$url = isset($_GET['url']) ? '/' . trim(trim($_GET['url']), '/'): '/';
foreach($this->_routes as $route) {
//check if the route pattern matches the url
if(!preg_match("#^{$route['route']}$#", $url, $params)) {
continue;
}
// check if the request is matching
if(!$this->checkRouteMethod($route['type'])) {
continue;
}
array_shift($params);
if(is_callable($route['callback'])) {
//calls the found route callback with the matched parameters
return call_user_func_array($route['callback'], $params);
}
return new \Exception("Route callback isn't an instance of callable.");
}
// no routes matched
header($_SERVER["SERVER_PROTOCOL"]." 404 Not Found", true, 404);
die('<h1>404 - Page Not Found</h1>');
}
// checks if the current request matches a routes required request type
public function checkRouteMethod($type) {
$requestType = strtolower($_SERVER['REQUEST_METHOD']);
if(strtolower($type) == $requestType) {
return true;
}
return false;
}
// finds a route by its name
public function searchRoute($name) {
foreach($this->_routes as $route) {
if($route['name'] == $name) {
return $route;
}
}
return false;
}
// turns a route pattern into a uri with the given params (if any)
public function generateRoute($routeName, $params = []) {
$route = $this->searchRoute($routeName)['pretty'];
if($params) {
foreach($params as $name => $value) {
$route = preg_replace("/{{$name}}\??/", $this->ceoEncode($value), $route);
}
}
return $route;
}
// The following function was taken from a StackOverFlow post but I edited it.
public function ceoEncode($string) {
if(is_array($string)) {
$encoded = [];
foreach($string as $key => $value) {
$encoded[$key] = $this->ceoEncode($value);
}
return $encoded;
}
//Clean up multiple dashes or whitespaces
$string = preg_replace("/[\s-]+/", " ", $string);
//Convert whitespaces to dash
$string = preg_replace("/[\s]/", "-", $string);
return $string;
}
}
@DiyarD
Copy link
Author

DiyarD commented Jul 15, 2016

NOTE: This an example of a router class and it isn't efficient, DON'T use that in a real world example ;)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment