Skip to content

Commit

Permalink
[Routing] Add {foo:bar} syntax to define a mapping between a route …
Browse files Browse the repository at this point in the history
…parameter and its corresponding request attribute
  • Loading branch information
nicolas-grekas committed May 2, 2024
1 parent 9f15bda commit 91479c4
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 4 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
CHANGELOG
=========

7.1
---

* Add `{foo:bar}` syntax to define a mapping between a route parameter and its corresponding request attribute

7.0
---

Expand Down
4 changes: 4 additions & 0 deletions Matcher/UrlMatcher.php
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,10 @@ protected function getAttributes(Route $route, string $name, array $attributes):
}
$attributes['_route'] = $name;

if ($mapping = $route->getOption('mapping')) {
$attributes['_route_mapping'] = $mapping;
}

return $this->mergeDefaults($attributes, $defaults);
}

Expand Down
19 changes: 15 additions & 4 deletions Route.php
Original file line number Diff line number Diff line change
Expand Up @@ -412,20 +412,31 @@ public function compile(): CompiledRoute

private function extractInlineDefaultsAndRequirements(string $pattern): string
{
if (false === strpbrk($pattern, '?<')) {
if (false === strpbrk($pattern, '?<:')) {
return $pattern;
}

return preg_replace_callback('#\{(!?)([\w\x80-\xFF]++)(<.*?>)?(\?[^\}]*+)?\}#', function ($m) {
$mapping = $this->getDefault('_route_mapping') ?? [];

$pattern = preg_replace_callback('#\{(!?)([\w\x80-\xFF]++)(:[\w\x80-\xFF]++)?(<.*?>)?(\?[^\}]*+)?\}#', function ($m) use (&$mapping) {
if (isset($m[5][0])) {
$this->setDefault($m[2], '?' !== $m[5] ? substr($m[5], 1) : null);
}
if (isset($m[4][0])) {
$this->setDefault($m[2], '?' !== $m[4] ? substr($m[4], 1) : null);
$this->setRequirement($m[2], substr($m[4], 1, -1));
}
if (isset($m[3][0])) {
$this->setRequirement($m[2], substr($m[3], 1, -1));
$mapping[$m[2]] = substr($m[3], 1);
}

return '{'.$m[1].$m[2].'}';
}, $pattern);

if ($mapping) {
$this->setDefault('_route_mapping', $mapping);
}

return $pattern;
}

private function sanitizeRequirement(string $key, string $regex): string
Expand Down
17 changes: 17 additions & 0 deletions Tests/Matcher/UrlMatcherTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -1000,6 +1000,23 @@ public function testUtf8VarName()
$this->assertEquals(['_route' => 'foo', 'bär' => 'baz', 'bäz' => 'foo'], $matcher->match('/foo/baz'));
}

public function testMapping()
{
$collection = new RouteCollection();
$collection->add('a', new Route('/conference/{slug:conference}'));

$matcher = $this->getUrlMatcher($collection);

$expected = [
'_route' => 'a',
'slug' => 'vienna-2024',
'_route_mapping' => [
'slug' => 'conference',
],
];
$this->assertEquals($expected, $matcher->match('/conference/vienna-2024'));
}

protected function getUrlMatcher(RouteCollection $routes, ?RequestContext $context = null)
{
return new UrlMatcher($routes, $context ?? new RequestContext());
Expand Down

0 comments on commit 91479c4

Please sign in to comment.