Skip to content

Commit

Permalink
Add initial implementation of brace placeholders.
Browse files Browse the repository at this point in the history
Brace placeholders allow route placeholders to be more easily identified
and be placed mid-word with other alphanumeric characters.

Refs #9188
Refs #10689
  • Loading branch information
markstory committed Jan 8, 2018
1 parent bf3fddd commit d0e8f2d
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 5 deletions.
25 changes: 21 additions & 4 deletions src/Routing/Route/Route.php
Expand Up @@ -95,6 +95,13 @@ class Route
*/
protected $middleware = [];

/**
* Track whether or not brace keys `{var}` were used.
*
* @var bool
*/
protected $braceKeys = false;

/**
* Valid HTTP methods.
*
Expand Down Expand Up @@ -315,15 +322,21 @@ protected function _writeRoute()
$names = $routeParams = [];
$parsed = preg_quote($this->template, '#');

preg_match_all('/:([a-z0-9-_]+(?<![-_]))/i', $route, $namedElements);
if (strpos($route, '{') !== false) {
preg_match_all('/\{([a-z0-9-_]+)\}/i', $route, $namedElements);
$this->braceKeys = true;
} else {
preg_match_all('/:([a-z0-9-_]+(?<![-_]))/i', $route, $namedElements);
$this->braceKeys = false;
}
foreach ($namedElements[1] as $i => $name) {
$search = '\\' . $namedElements[0][$i];
$search = preg_quote($namedElements[0][$i]);
if (isset($this->options[$name])) {
$option = null;
if ($name !== 'plugin' && array_key_exists($name, $this->defaults)) {
$option = '?';
}
$slashParam = '/\\' . $namedElements[0][$i];
$slashParam = '/' . $search;
if (strpos($parsed, $slashParam) !== false) {
$routeParams[$slashParam] = '(?:/(?P<' . $name . '>' . $this->options[$name] . ')' . $option . ')' . $option;
} else {
Expand Down Expand Up @@ -788,7 +801,11 @@ protected function _writeUrl($params, $pass = [], $query = [])
} elseif (strpos($out, $key) != strlen($out) - strlen($key)) {
$key .= '/';
}
$search[] = ':' . $key;
if ($this->braceKeys) {
$search[] = "{{$key}}";
} else {
$search[] = ':' . $key;
}
$replace[] = $string;
}

Expand Down
68 changes: 67 additions & 1 deletion tests/TestCase/Routing/Route/RouteTest.php
Expand Up @@ -122,7 +122,7 @@ public function testBasicRouteCompiling()
*
* @return void
*/
public function testRouteBuildingSmallPlaceholders()
public function testRouteCompileSmallPlaceholders()
{
$route = new Route(
'/fighters/:id/move/:x/:y',
Expand All @@ -142,6 +142,72 @@ public function testRouteBuildingSmallPlaceholders()
$this->assertEquals('/fighters/123/move/8/42', $result);
}

/**
* Test route compile with brace format.
*
* @return void
*/
public function testRouteCompileBraces()
{
$route = new Route(
'/fighters/{id}/move/{x}/{y}',
['controller' => 'Fighters', 'action' => 'move'],
['id' => '\d+', 'x' => '\d+', 'y' => '\d+', 'pass' => ['id', 'x', 'y']]
);
$pattern = $route->compile();
$this->assertRegExp($pattern, '/fighters/123/move/8/42');

$result = $route->match([
'controller' => 'Fighters',
'action' => 'move',
'id' => 123,
'x' => 8,
'y' => 42
]);
$this->assertEquals('/fighters/123/move/8/42', $result);

$route = new Route(
'/images/{id}/{x}x{y}',
['controller' => 'Images', 'action' => 'view']
);
$pattern = $route->compile();
$this->assertRegExp($pattern, '/images/123/640x480');

$result = $route->match([
'controller' => 'Images',
'action' => 'view',
'id' => 123,
'x' => 8,
'y' => 42
]);
$this->assertEquals('/images/123/8x42', $result);
}

/**
* Test route compile with mixed placeholder types brace format.
*
* @return void
*/
public function testRouteCompileMixedPlaceholders()
{
$route = new Route(
'/fighters/{id}/move/{x}/:y',
['controller' => 'Fighters', 'action' => 'move'],
['id' => '\d+', 'x' => '\d+', 'pass' => ['id', 'x']]
);
$pattern = $route->compile();
$this->assertRegExp($pattern, '/fighters/123/move/8/:y');

$result = $route->match([
'controller' => 'Fighters',
'action' => 'move',
'id' => 123,
'x' => 8,
'y' => 9
]);
$this->assertEquals('/fighters/123/move/8/:y?y=9', $result);
}

/**
* Test parsing routes with extensions.
*
Expand Down

0 comments on commit d0e8f2d

Please sign in to comment.