8000 merged branch vicb/routingmatcher (PR #4170) · symfony/symfony@cc85a6e · GitHub
[go: up one dir, main page]

Skip to content

Commit cc85a6e

Browse files
committed
merged branch vicb/routingmatcher (PR #4170)
Commits ------- a196ca0 [Routing] Compiler: remove lazy quantifiers with no effect 8232aa1 [Routing] Compiler: fix in the computing of the segment separators Discussion ---------- [Routing] Fix the matching process This PR is based on the PR #3678, #4139. [![Build Status](https://secure.travis-ci.org/vicb/symfony.png?branch=routingmatcher)](http://travis-ci.org/vicb/symfony) **The spec** A pattern is composed of both text and variable segments: `/{variable}-test/{other_variable}`. A variable segment will match anything until a separator is encountered. The separator is the character following the variable segment when available or preceding the variable otherwise (i.e. at the end of the pattern). That is: * the separator is `-` for the `variable`, * the separator is `/` for the `other_variable`. *Note: This default matching behavior can be overridden if a requirement is specified for a variable)* **Fixes** * The current behavior is to consider booth the preceding and following characters as separators (considering availability), * The "preceding" separator of the first variable is always set to `/` whatever the preceding character is (due to `$pos = 0` for the first iteration). **Todo** Update the doc once this is merged
2 parents ff7c475 + a196ca0 commit cc85a6e

File tree

6 files changed

+74
-63
lines changed

6 files changed

+74
-63
lines changed

src/Symfony/Component/Routing/RouteCompiler.php

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ class RouteCompiler implements RouteCompilerInterface
2626
* @param Route $route A Route instance
2727
*
2828
* @return CompiledRoute A CompiledRoute instance
29+
*
30+
* @throws \LogicException If a variable is referenced more than once
2931
*/
3032
public function compile(Route $route)
3133
{
@@ -34,22 +36,22 @@ public function compile(Route $route)
3436
$tokens = array();
3537
$variables = array();
3638
$pos = 0;
37-
preg_match_all('#.\{([\w\d_]+)\}#', $pattern, $matches, PREG_OFFSET_CAPTURE | PREG_SET_ORDER);
39+
preg_match_all('#.\{(\w+)\}#', $pattern, $matches, PREG_OFFSET_CAPTURE | PREG_SET_ORDER);
3840
foreach ($matches as $match) {
3941
if ($text = substr($pattern, $pos, $match[0][1] - $pos)) {
4042
$tokens[] = array('text', $text);
4143
}
42-
$seps = array($pattern[$pos]);
44+
4345
$pos = $match[0][1] + strlen($match[0][0]);
4446
$var = $match[1][0];
4547

4648
if ($req = $route->getRequirement($var)) {
4749
$regexp = $req;
4850
} else {
49-
if ($pos !== $len) {
50-
$seps[] = $pattern[$pos];
51-
}
52-
$regexp = sprintf('[^%s]+?', preg_quote(implode('', array_unique($seps)), self::REGEX_DELIMITER));
51+
// Use the character following the variable as the separator when available
52+
// Use the character preceding the variable otherwise
53+
$separator = $pos !== $len ? $pattern[$pos] : $match[0][0][0];
54+
$regexp = sprintf('[^%s]+', preg_quote($separator, self::REGEX_DELIMITER));
5355
}
5456

5557
$tokens[] = array('variable', $match[0][0][0], $regexp, $var);

src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher1.apache

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,17 @@ RewriteCond %{REQUEST_URI} ^/foo/(baz|symfony)$
77
RewriteRule .* app.php [QSA,L,E=_ROUTING__route:foo,E=_ROUTING_bar:%1,E=_ROUTING_def:test]
88

99
# bar
10-
RewriteCond %{REQUEST_URI} ^/bar/([^/]+?)$
10+
RewriteCond %{REQUEST_URI} ^/bar/([^/]+)$
1111
RewriteCond %{REQUEST_METHOD} !^(GET|HEAD)$ [NC]
1212
RewriteRule .* - [S=1,E=_ROUTING__allow_GET:1,E=_ROUTING__allow_HEAD:1]
13-
RewriteCond %{REQUEST_URI} ^/bar/([^/]+?)$
13+
RewriteCond %{REQUEST_URI} ^/bar/([^/]+)$
1414
RewriteRule .* app.php [QSA,L,E=_ROUTING__route:bar,E=_ROUTING_foo:%1]
1515

1616
# baragain
17-
RewriteCond %{REQUEST_URI} ^/baragain/([^/]+?)$
17+
RewriteCond %{REQUEST_URI} ^/baragain/([^/]+)$
1818
RewriteCond %{REQUEST_METHOD} !^(GET|POST|HEAD)$ [NC]
1919
RewriteRule .* - [S=1,E=_ROUTING__allow_GET:1,E=_ROUTING__allow_POST:1,E=_ROUTING__allow_HEAD:1]
20-
RewriteCond %{REQUEST_URI} ^/baragain/([^/]+?)$
20+
RewriteCond %{REQUEST_URI} ^/baragain/([^/]+)$
2121
RewriteRule .* app.php [QSA,L,E=_ROUTING__route:baragain,E=_ROUTING_foo:%1]
2222

2323
# baz
@@ -35,25 +35,25 @@ RewriteCond %{REQUEST_URI} ^/test/baz3/$
3535
RewriteRule .* app.php [QSA,L,E=_ROUTING__route:baz3]
3636

3737
# baz4
38-
RewriteCond %{REQUEST_URI} ^/test/([^/]+?)$
38+
RewriteCond %{REQUEST_URI} ^/test/([^/]+)$
3939
RewriteRule .* $0/ [QSA,L,R=301]
40-
RewriteCond %{REQUEST_URI} ^/test/([^/]+?)/$
40+
RewriteCond %{REQUEST_URI} ^/test/([^/]+)/$
4141
RewriteRule .* app.php [QSA,L,E=_ROUTING__route:baz4,E=_ROUTING_foo:%1]
4242

4343
# baz5
44-
RewriteCond %{REQUEST_URI} ^/test/([^/]+?)/$
44+
RewriteCond %{REQUEST_URI} ^/test/([^/]+)/$
4545
RewriteCond %{REQUEST_METHOD} !^(GET|HEAD)$ [NC]
4646
RewriteRule .* - [S=2,E=_ROUTING__allow_GET:1,E=_ROUTING__allow_HEAD:1]
47-
RewriteCond %{REQUEST_URI} ^/test/([^/]+?)$
47+
RewriteCond %{REQUEST_URI} ^/test/([^/]+)$
4848
RewriteRule .* $0/ [QSA,L,R=301]
49-
RewriteCond %{REQUEST_URI} ^/test/([^/]+?)/$
49+
RewriteCond %{REQUEST_URI} ^/test/([^/]+)/$
5050
RewriteRule .* app.php [QSA,L,E=_ROUTING__route:baz5,E=_ROUTING_foo:%1]
5151

5252
# baz5unsafe
53-
RewriteCond %{REQUEST_URI} ^/testunsafe/([^/]+?)/$
53+
RewriteCond %{REQUEST_URI} ^/testunsafe/([^/]+)/$
5454
RewriteCond %{REQUEST_METHOD} !^(POST)$ [NC]
5555
RewriteRule .* - [S=1,E=_ROUTING__allow_POST:1]
56-
RewriteCond %{REQUEST_URI} ^/testunsafe/([^/]+?)/$
56+
RewriteCond %{REQUEST_URI} ^/testunsafe/([^/]+)/$
5757
RewriteRule .* app.php [QSA,L,E=_ROUTING__route:baz5unsafe,E=_ROUTING_foo:%1]
5858

5959
# baz6

src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher1.php

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ public function match($pathinfo)
3131
}
3232

3333
// bar
34-
if (0 === strpos($pathinfo, '/bar') && preg_match('#^/bar/(?<foo>[^/]+?)$#s', $pathinfo, $matches)) {
34+
if (0 === strpos($pathinfo, '/bar') && preg_match('#^/bar/(?<foo>[^/]+)$#s', $pathinfo, $matches)) {
3535
if (!in_array($this->context->getMethod(), array('GET', 'HEAD'))) {
3636
$allow = array_merge($allow, array('GET', 'HEAD'));
3737
goto not_bar;
@@ -44,7 +44,7 @@ public function match($pathinfo)
4444
not_bar:
4545

4646
// barhead
47-
if (0 === strpos($pathinfo, '/barhead') && preg_match('#^/barhead/(?<foo>[^/]+?)$#s', $pathinfo, $matches)) {
47+
if (0 === strpos($pathinfo, '/barhead') && preg_match('#^/barhead/(?<foo>[^/]+)$#s', $pathinfo, $matches)) {
4848
if (!in_array($this->context->getMethod(), array('GET', 'HEAD'))) {
4949
$allow = array_merge($allow, array('GET', 'HEAD'));
5050
goto not_barhead;
@@ -72,14 +72,14 @@ public function match($pathinfo)
7272
}
7373

7474
// baz4
75-
if (0 === strpos($pathinfo, '/test') && preg_match('#^/test/(?<foo>[^/]+?)/$#s', $pathinfo, $matches)) {
75+
if (0 === strpos($pathinfo, '/test') && preg_match('#^/test/(?<foo>[^/]+)/$#s', $pathinfo, $matches)) {
7676
$matches['_route'] = 'baz4';
7777

7878
return $matches;
7979
}
8080

8181
// baz5
82-
if (0 === strpos($pathinfo, '/test') && preg_match('#^/test/(?<foo>[^/]+?)/$#s', $pathinfo, $matches)) {
82+
if (0 === strpos($pathinfo, '/test') && preg_match('#^/test/(?<foo>[^/]+)/$#s', $pathinfo, $matches)) {
8383
if ($this->context->getMethod() != 'POST') {
8484
$allow[] = 'POST';
8585
goto not_baz5;
@@ -92,7 +92,7 @@ public function match($pathinfo)
9292
not_baz5:
9393

9494
// baz.baz6
95-
if (0 === strpos($pathinfo, '/test') && preg_match('#^/test/(?<foo>[^/]+?)/$#s', $pathinfo, $matches)) {
95+
if (0 === strpos($pathinfo, '/test') && preg_match('#^/test/(?<foo>[^/]+)/$#s', $pathinfo, $matches)) {
9696
if ($this->context->getMethod() != 'PUT') {
9797
$allow[] = 'PUT';
9898
goto not_bazbaz6;
@@ -124,14 +124,14 @@ public function match($pathinfo)
124124
if (0 === strpos($pathinfo, '/a')) {
125125
if (0 === strpos($pathinfo, '/a/b\'b')) {
126126
// foo1
127-
if (preg_match('#^/a/b\'b/(?<foo>[^/]+?)$#s', $pathinfo, $matches)) {
127+
if (preg_match('#^/a/b\'b/(?<foo>[^/]+)$#s', $pathinfo, $matches)) {
128128
$matches['_route'] = 'foo1';
129129

130130
return $matches;
131131
}
132132

133133
// bar1
134-
if (preg_match('#^/a/b\'b/(?<bar>[^/]+?)$#s', $pathinfo, $matches)) {
134+
if (preg_match('#^/a/b\'b/(?<bar>[^/]+)$#s', $pathinfo, $matches)) {
135135
$matches['_route'] = ' F438 ;bar1';
136136

137137
return $matches;
@@ -148,14 +148,14 @@ public function match($pathinfo)
148148

149149
if (0 === strpos($pathinfo, '/a/b\'b')) {
150150
// foo2
151-
if (preg_match('#^/a/b\'b/(?<foo1>[^/]+?)$#s', $pathinfo, $matches)) {
151+
if (preg_match('#^/a/b\'b/(?<foo1>[^/]+)$#s', $pathinfo, $matches)) {
152152
$matches['_route'] = 'foo2';
153153

154154
return $matches;
155155
}
156156

157157
// bar2
158-
if (preg_match('#^/a/b\'b/(?<bar1>[^/]+?)$#s', $pathinfo, $matches)) {
158+
if (preg_match('#^/a/b\'b/(?<bar1>[^/]+)$#s', $pathinfo, $matches)) {
159159
$matches['_route'] = 'bar2';
160160

161161
return $matches;
@@ -167,7 +167,7 @@ public function match($pathinfo)
167167

168168
if (0 === strpos($pathinfo, '/multi')) {
169169
// helloWorld
170-
if (0 === strpos($pathinfo, '/multi/hello') && preg_match('#^/multi/hello(?:/(?<who>[^/]+?))?$#s', $pathinfo, $matches)) {
170+
if (0 === strpos($pathinfo, '/multi/hello') && preg_match('#^/multi/hello(?:/(?<who>[^/]+))?$#s', $pathinfo, $matches)) {
171171
return array_merge($this->mergeDefaults($matches, array ( 'who' => 'World!',)), array('_route' => 'helloWorld'));
172172
}
173173

@@ -184,14 +184,14 @@ public function match($pathinfo)
184184
}
185185

186186
// foo3
187-
if (preg_match('#^/(?<_locale>[^/]+?)/b/(?<foo>[^/]+?)$#s', $pathinfo, $matches)) {
187+
if (preg_match('#^/(?<_locale>[^/]+)/b/(?<foo>[^/]+)$#s', $pathinfo, $matches)) {
188188
$matches['_route'] = 'foo3';
189189

190190
return $matches;
191191
}
192192

193193
// bar3
194-
if (preg_match('#^/(?<_locale>[^/]+?)/b/(?<bar>[^/]+?)$#s', $pathinfo, $matches)) {
194+
if (preg_match('#^/(?<_locale>[^/]+)/b/(?<bar>[^/]+)$#s', $pathinfo, $matches)) {
195195
$matches['_route'] = 'bar3';
196196

197197
return $matches;
@@ -203,7 +203,7 @@ public function match($pathinfo)
203203
}
204204

205205
// foo4
206-
if (0 === strpos($pathinfo, '/aba') && preg_match('#^/aba/(?<foo>[^/]+?)$#s', $pathinfo, $matches)) {
206+
if (0 === strpos($pathinfo, '/aba') && preg_match('#^/aba/(?<foo>[^/]+)$#s', $pathinfo, $matches)) {
207207
$matches['_route'] = 'foo4';
208208

209209
return $matches;
@@ -217,14 +217,14 @@ public function match($pathinfo)
217217

218218
if (0 === strpos($pathinfo, '/a/b')) {
219219
// b
220-
if (preg_match('#^/a/b/(?<var>[^/]+?)$#s', $pathinfo, $matches)) {
220+
if (preg_match('#^/a/b/(?<var>[^/]+)$#s', $pathinfo, $matches)) {
221221
$matches['_route'] = 'b';
222222

223223
return $matches;
224224
}
225225

226226
// c
227-
if (0 === strpos($pathinfo, '/a/b/c') && preg_match('#^/a/b/c/(?<var>[^/]+?)$#s', $pathinfo, $matches)) {
227+
if (0 === strpos($pathinfo, '/a/b/c') && preg_match('#^/a/b/c/(?<var>[^/]+)$#s', $pathinfo, $matches)) {
228228
$matches['_route'] = 'c';
229229

230230
return $matches;

src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher2.php

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ public function match($pathinfo)
3131
}
3232

3333
// bar
34-
if (0 === strpos($pathinfo, '/bar') && preg_match('#^/bar/(?<foo>[^/]+?)$#s', $pathinfo, $matches)) {
34+
if (0 === strpos($pathinfo, '/bar') && preg_match('#^/bar/(?<foo>[^/]+)$#s', $pathinfo, $matches)) {
3535
if (!in_array($this->context->getMethod(), array('GET', 'HEAD'))) {
3636
$allow = array_merge($allow, array('GET', 'HEAD'));
3737
goto not_bar;
@@ -44,7 +44,7 @@ public function match($pathinfo)
4444
not_bar:
4545

4646
// barhead
47-
if (0 === strpos($pathinfo, '/barhead') && preg_match('#^/barhead/(?<foo>[^/]+?)$#s', $pathinfo, $matches)) {
47+
if (0 === strpos($pathinfo, '/barhead') && preg_match('#^/barhead/(?<foo>[^/]+)$#s', $pathinfo, $matches)) {
4848
if (!in_array($this->context->getMethod(), array('GET', 'HEAD'))) {
4949
$allow = array_merge($allow, array('GET', 'HEAD'));
5050
goto not_barhead;
@@ -76,7 +76,7 @@ public function match($pathinfo)
7676
}
7777

7878
// baz4
79-
if (0 === strpos($pathinfo, '/test') && preg_match('#^/test/(?<foo>[^/]+?)/?$#s', $pathinfo, $matches)) {
79+
if (0 === strpos($pathinfo, '/test') && preg_match('#^/test/(?<foo>[^/]+)/?$#s', $pathinfo, $matches)) {
8080
if (substr($pathinfo, -1) !== '/') {
8181
return $this->redirect($pathinfo.'/', 'baz4');
8282
}
@@ -87,7 +87,7 @@ public function match($pathinfo)
8787
}
8888

8989
// baz5
90-
if (0 === strpos($pathinfo, '/test') && preg_match('#^/test/(?<foo>[^/]+?)/$#s', $pathinfo, $matches)) {
90+
if (0 === strpos($pathinfo, '/test') && preg_match('#^/test/(?<foo>[^/]+)/$#s', $pathinfo, $matches)) {
9191
if ($this->context->getMethod() != 'POST') {
9292
$allow[] = 'POST';
9393
goto not_baz5;
@@ -100,7 +100,7 @@ public function match($pathinfo)
100100
not_baz5:
101101

102102
// baz.baz6
103-
if (0 === strpos($pathinfo, '/test') && preg_match('#^/test/(?<foo>[^/]+?)/$#s', $pathinfo, $matches)) {
103+
if (0 === strpos($pathinfo, '/test') && preg_match('#^/test/(?<foo>[^/]+)/$#s', $pathinfo, $matches)) {
104104
if ($this->context->getMethod() != 'PUT') {
105105
$allow[] = 'PUT';
106106
goto not_bazbaz6;
@@ -132,14 +132,14 @@ public function match($pathinfo)
132132
if (0 === strpos($pathinfo, '/a')) {
133133
if (0 === strpos($pathinfo, '/a/b\'b')) {
134134
// foo1
135-
if (preg_match('#^/a/b\'b/(?<foo>[^/]+?)$#s', $pathinfo, $matches)) {
135+
if (preg_match('#^/a/b\'b/(?<foo>[^/]+)$#s', $pathinfo, $matches)) {
136136
$matches['_route'] = 'foo1';
137137

138138
return $matches;
139139
}
140140

141141
// bar1
142-
if (preg_match('#^/a/b\'b/(?<bar>[^/]+?)$#s', $pathinfo, $matches)) {
142+
if (preg_match('#^/a/b\'b/(?<bar>[^/]+)$#s', $pathinfo, $matches)) {
143143
$matches['_route'] = 'bar1';
144144

145145
return $matches;
@@ -156,14 +156,14 @@ public function match($pathinfo)
156156

157157
if (0 === strpos($pathinfo, '/a/b\'b')) {
158158
// foo2
159-
if (preg_match('#^/a/b\'b/(?<foo1>[^/]+?)$#s', $pathinfo, $matches)) {
159+
if (preg_match('#^/a/b\'b/(?<foo1>[^/]+)$#s', $pathinfo, $matches)) {
160160
$matches['_route'] = 'foo2';
161161

162162
return $matches;
163163
}
164164

165165
// bar2
166-
if (preg_match('#^/a/b\'b/(?<bar1>[^/]+?)$#s', $pathinfo, $matches)) {
166+
if (preg_match('#^/a/b\'b/(?<bar1>[^/]+)$#s', $pathinfo, $matches)) {
167167
$matches['_route'] = 'bar2';
168168

169169
return $matches;
@@ -175,7 +175,7 @@ public function match($pathinfo)
175175

176176
if (0 === strpos($pathinfo, '/multi')) {
177177
// helloWorld
178-
if (0 === strpos($pathinfo, '/multi/hello') && preg_match('#^/multi/hello(?:/(?<who>[^/]+?))?$#s', $pathinfo, $matches)) {
178+
if (0 === strpos($pathinfo, '/multi/hello') && preg_match('#^/multi/hello(?:/(?<who>[^/]+))?$#s', $pathinfo, $matches)) {
179179
return array_merge($this->mergeDefaults($matches, array ( 'who' => 'World!',)), array('_route' => 'helloWorld'));
180180
}
181181

@@ -196,14 +196,14 @@ public function match($pathinfo)
196196
}
197197

198198
// foo3
199-
if (preg_match('#^/(?<_locale>[^/]+?)/b/(?<foo>[^/]+?)$#s', $pathinfo, $matches)) {
199+
if (preg_match('#^/(?<_locale>[^/]+)/b/(?<foo>[^/]+)$#s', $pathinfo, $matches)) {
200200
$matches['_route'] = 'foo3';
201201

202202
return $matches;
203203
}
204204

205205
// bar3
206-
if (preg_match('#^/(?<_locale>[^/]+?)/b/(?<bar>[^/]+?)$#s', $pathinfo, $matches)) {
206+
if (preg_match('#^/(?<_locale>[^/]+)/b/(?<bar>[^/]+)$#s', $pathinfo, $matches)) {
207207
$matches['_route'] = 'bar3';
208208

209209
return $matches;
@@ -215,7 +215,7 @@ public function match($pathinfo)
215215
}
216216

217217
// foo4
218-
if (0 === strpos($pathinfo, '/aba') && preg_match('#^/aba/(?<foo>[^/]+?)$#s', $pathinfo, $matches)) {
218+
if (0 === strpos($pathinfo, '/aba') && preg_match('#^/aba/(?<foo>[^/]+)$#s', $pathinfo, $matches)) {
219219
$matches['_route'] = 'foo4';
220220

221221
return $matches;
@@ -229,14 +229,14 @@ public function match($pathinfo)
229229

230230
if (0 === strpos($pathinfo, '/a/b')) {
231231
// b
232-
if (preg_match('#^/a/b/(?<var>[^/]+?)$#s', $pathinfo, $matches)) {
232+
if (preg_match('#^/a/b/(?<var>[^/]+)$#s', $pathinfo, $matches)) {
233233
$matches['_route'] = 'b';
234234

235235
return $matches;
236236
}
237237

238238
// c
239-
if (0 === strpos($pathinfo, '/a/b/c') && preg_match('#^/a/b/c/(?<var>[^/]+?)$#s', $pathinfo, $matches)) {
239+
if (0 === strpos($pathinfo, '/a/b/c') && preg_match('#^/a/b/c/(?<var>[^/]+)$#s', $pathinfo, $matches)) {
240240
$matches['_route'] = 'c';
241241

242242
return $matches;

src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher3.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ public function match($pathinfo)
3232
}
3333

3434
// dynamic
35-
if (preg_match('#^/rootprefix/(?<var>[^/]+?)$#s', $pathinfo, $matches)) {
35+
if (preg_match('#^/rootprefix/(?<var>[^/]+)$#s', $pathinfo, $matches)) {
3636
$matches['_route'] = 'dynamic';
3737

3838
return $matches;

0 commit comments

Comments
 (0)
0