Skip to content

Instantly share code, notes, and snippets.

@morrisonlevi
Created August 15, 2013 23:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save morrisonlevi/a9873054cd384cf90581 to your computer and use it in GitHub Desktop.
Save morrisonlevi/a9873054cd384cf90581 to your computer and use it in GitHub Desktop.
<?php
require_once 'Rule.php';
class OneRegexToRuleThemAllRouter implements Router {
private $routes = [];
private $rules = [];
private $regexs = [];
private $theOneRegex = '';
function addRoute($httpMethod, $route, $handler) {
$expression = str_replace(
['\$'],
['$'],
preg_quote($route, '~')
);
$rule = new Rule;
$offset = 0;
while (($varPos = strpos($expression, '$', $offset)) !== FALSE) {
$offset = $varPos+1;
$end = strpos($expression, '/', $offset);
if ($end === FALSE) {
$var = substr($expression, $offset);
} else {
$var = substr($expression, $offset, $end - $offset);
}
if (strlen($var) < 1) {
throw new Exception;
}
if ($var[0] === '#') {
$var = substr($var, 1);
if (strlen($var) < 1) {
throw new Exception;
}
$key = "X$var";
$substitute = "(?P<$key>\\d+)";
$expression = str_replace("\$#$var", $substitute, $expression);
$offset += strlen($substitute) - 1;
$rule->variables[$key] = '#';
} else {
$key = "x$var";
$substitute = "(?P<$key>[^/]+)";
$expression = str_replace("\$$var", $substitute, $expression);
$offset += strlen($substitute) - 1;
$rule->variables[$key] = '';
}
}
if (empty($rule->variables)) {
$this->routes[$route][$httpMethod] = $handler;
} else {
$rule->route = $route;
$rule->expression = $expression;
$rule->handler = $handler;
$this->regexs[] = $rule;
$this->rules[$rule->route][$httpMethod] = $handler;
}
$this->forgeTheOneRegex();
}
private function forgeTheOneRegex() {
reset($this->regexs);
if (key($this->regexs) === NULL) {
$this->theOneRegex = '~~';
return;
}
$expr = '~';
/**
* @var Rule $rule
*/
$rule = current($this->regexs);
$expr .= "(?:{$rule->expression})";
next($this->regexs);
while ($rule = current($this->regexs)) {
$expr .= "|(?:{$rule->expression})";
next($this->regexs);
}
$expr .= "~";
$this->theOneRegex = $expr;
}
function matchRoute($httpMethod, $uri) {
if (isset($this->routes[$uri][$httpMethod])) {
return [self::MATCHED, $this->routes[$uri][$httpMethod], []];
}
$matches = [];
if (preg_match($this->theOneRegex, $uri, $matches, PREG_OFFSET_CAPTURE)) {
$size = count($matches);
$variables = array_diff_key($matches, array_fill_keys(range(0, $size), 0));
$offset = 0;
$buffer = '';
foreach ($variables as $key => $value) {
$buffer .= substr($uri, $offset, $value[1] - $offset);
$buffer .= $key[0] === 'x'
? '$' . substr($key, 1)
: '$#' . substr($key, 1);
$offset = $value[1] + strlen($value[0]);
}
$buffer .= substr($uri, $offset);
if (!isset($this->rules[$buffer][$httpMethod])) {
return [self::METHOD_NOT_ALLOWED];
}
$arguments = [];
foreach ($variables as $key => $value) {
$arguments[substr($key, 1)] = $value[0];
}
return [self::MATCHED, $this->rules[$buffer][$httpMethod], $arguments];
}
return [self::NOT_FOUND];
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment