Created
March 1, 2010 05:16
-
-
Save leifwalsh/318098 to your computer and use it in GitHub Desktop.
This file contains hidden or 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 | |
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