Update TemplateRouter to better match templates with variables in more complicated paths

This commit is contained in:
PJ Dietz 2015-02-02 17:08:25 -05:00
parent bcaa0ee7b7
commit 38639d9ee4
2 changed files with 26 additions and 44 deletions

View File

@ -59,65 +59,45 @@ class TemplateRoute extends RegexRoute
*/
private function buildPattern($template, $defaultPattern, $variablePatterns)
{
// Ensure $variablePatterns is an array.
if (is_null($variablePatterns)) {
$variablePatterns = array();
} elseif (is_object($variablePatterns)) {
$variablePatterns = (array) $variablePatterns;
}
// Ensure a default is set.
if (!$defaultPattern) {
$defaultPattern = self::RE_SLUG;
}
$pattern = '';
// Convert the template into the pattern
$pattern = $template;
// Explode the template into an array of path segments.
if ($template[0] === '/') {
$parts = explode('/', substr($template, 1));
// Escape allowable characters with regex meaning.
$pattern = str_replace(
array("-", "."),
array("\\-", "\\."),
$pattern);
// Replace * with .* AFTER escaping to avoid escaping .*
$pattern = str_replace("*", ".*", $pattern);
// Surroung the pattern with delimiters
$pattern = "~^{$pattern}$~";
// Replace all template variables with matching subpatterns.
$callback = function ($matches) use ($variablePatterns, $defaultPattern) {
$key = $matches[1];
if (isset($variablePatterns[$key])) {
$pattern = $variablePatterns[$key];
} else {
$parts = explode('/', $template);
$pattern = $defaultPattern;
}
return "(?<{$key}>{$pattern})";
};
$pattern = preg_replace_callback(self::URI_TEMPLATE_EXPRESSION_RE, $callback, $pattern);
foreach ($parts as $part) {
$pattern .= '\/';
// Is this part an expression or a literal?
if (preg_match(self::URI_TEMPLATE_EXPRESSION_RE, $part, $matches)) {
// Locate the name for the variable from the template.
$variableName = $matches[1];
// If the caller passed an array with this variable name
// as a key, use its value for the pattern here.
// Otherwise, use the class's current default.
if (isset($variablePatterns[$variableName])) {
$variablePattern = $variablePatterns[$variableName];
} else {
$variablePattern = $defaultPattern;
}
$pattern .= sprintf(
'(?<%s>%s)',
$variableName,
$variablePattern
);
} else {
// This part is a literal.
$pattern .= $part;
}
}
$pattern = '/^' . $pattern;
if (substr($pattern, -1) === "*") {
// Allow path to include characters passed the pattern.
$pattern = rtrim($pattern, "*") . '/';
} else {
// Path must end at the end of the pattern.
$pattern .= "$/";
}
return $pattern;
}

View File

@ -34,11 +34,13 @@ class TemplateRouteTest extends \PHPUnit_Framework_TestCase
"catId" => TemplateRoute::RE_SLUG,
"dogId" => TemplateRoute::RE_SLUG],
"/cat/molly/bear", "dogId", "bear"],
["cat/{catId}/{dogId}", TemplateRoute::RE_NUM, (object) [
["/cat/{catId}/{dogId}", TemplateRoute::RE_NUM, (object) [
"catId" => TemplateRoute::RE_SLUG,
"dogId" => TemplateRoute::RE_SLUG],
"/cat/molly/bear", "dogId", "bear"],
["/cat/{id}/*", null, null, "/cat/12/molly", "id", "12"]
["/cat/{id}/*", null, null, "/cat/12/molly", "id", "12"],
["/cat/{id}-{width}x{height}.jpg", TemplateRoute::RE_NUM, null, "/cat/17-100x100.jpg", "id", "17"],
["/cat/{path}", ".*", null, "/cat/this/section/has/slashes", "path", "this/section/has/slashes"]
];
}