Skip to content

Instantly share code, notes, and snippets.

@bkudria
Forked from leifwalsh/gist:318098
Created March 1, 2010 05:17
Show Gist options
  • Save bkudria/318100 to your computer and use it in GitHub Desktop.
Save bkudria/318100 to your computer and use it in GitHub Desktop.
<?php
namespace ynd\thsx\core;
class Router {
protected $prefix;
protected $routes;
// Used in specificity calculations.
const MAX_PATH_SEGMENTS = 10;
public function __construct($routes, $prefix = NULL) {
$this->prefix = $prefix;
$this->routes = $routes;
}
private function routeToRegex($route) {
$mappings =
array(
':(\w+)=(\w+)' => '(?<$1>$2)',
':(\w+)' => '(?<$1>[A-Za-z0-9\$\-_\.\+!\*\'\(\),]+)',
);
$regex = $route;
foreach ($mappings as $route_part => $regex_part) {
$regex = preg_replace("/$route_part/", $regex_part, $regex);
}
$prefix_path = isset($this->prefix) ? '/' . $this->prefix : '' ;
$regex = '@^' . $prefix_path . $regex . '/?$@i';
return $regex;
}
private function routeSpecificity($route) {
$segments = array_filter(explode('/', $route));
$total = count($segments);
$variables = count(preg_grep('/^:\w+$/', $segments));
$invariants = $total - $variables;
return (self::MAX_PATH_SEGMENTS * $invariants) + $variables;
}
public function route($path) {
$routes = array_keys($this->routes);
$route_assoc_array = array_combine($routes, $routes);
$route_regexps = array_map(array($this, 'RouteToRegex'), $route_assoc_array);
$matching_route_regexps = array_filter($route_regexps, function($regex) use ($path){return preg_match($regex, $path);});
$number_of_matching_routes = count($matching_route_regexps);
if ($number_of_matching_routes == 0) {
throw new UnknownPathRouteException("Could not find a matching route for request path: $path");
} else if ($number_of_matching_routes == 1) {
$routes = array_keys($matching_route_regexps);
$route = $routes[0];
} else {
$route_specificities = array();
foreach ($matching_route_regexps as $route => $regexp) {
$route_specificity = $this->routeSpecificity($route);
if (isset($route_specificities[$route_specificity])) {
throw new AmbiguousRouteException("Ambiguous matching routes found! $route and {$route_specificities[$route_specificity]} both have a route specificity of $route_specificity !");
} else {
$route_specificities[$route_specificity] = $route;
}
}
$specificities = array_keys($route_specificities);
rsort($specificities);
$route = $route_specificities[$specificities[0]];
}
$variables = array();
preg_match($matching_route_regexps[$route], $path, $variables);
unset($variables[0]);
return array($this->routes[$route], $variables);
}
}
class AmbiguousRouteException extends \DomainException {}
class UnknownPathRouteException extends \UnexpectedValueException {}
?>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment