@@ -111,9 +111,10 @@ private static function compilePattern(Route $route, $pattern, $isHost)
111
111
112
112
// Match all variables enclosed in "{}" and iterate over them. But we only want to match the innermost variable
113
113
// in case of nested "{}", e.g. {foo{bar}}. This in ensured because \w does not match "{" or "}" itself.
114
- preg_match_all ('#\{!? \w+\}# ' , $ pattern , $ matches , PREG_OFFSET_CAPTURE | PREG_SET_ORDER );
114
+ preg_match_all ('#\{(!)?( \w+) \}# ' , $ pattern , $ matches , PREG_OFFSET_CAPTURE | PREG_SET_ORDER );
115
115
foreach ($ matches as $ match ) {
116
- $ varName = substr ($ match [0 ][0 ], 1 , -1 );
116
+ $ important = $ match [1 ][1 ] >= 0 ;
117
+ $ varName = $ match [2 ][0 ];
117
118
// get all static text preceding the current variable
118
119
$ precedingText = substr ($ pattern , $ pos , $ match [0 ][1 ] - $ pos );
119
120
$ pos = $ match [0 ][1 ] + \strlen ($ match [0 ][0 ]);
@@ -183,10 +184,13 @@ private static function compilePattern(Route $route, $pattern, $isHost)
183
184
$ regexp = self ::transformCapturingGroupsToNonCapturings ($ regexp );
184
185
}
185
186
186
- $ tokens [] = ['variable ' , $ isSeparator ? $ precedingChar : '' , $ regexp , $ varName ];
187
- if ('! ' === $ varName [0 ]) {
188
- $ varName = substr ($ varName , 1 );
187
+ if ($ important ) {
188
+ $ token = ['variable ' , $ isSeparator ? $ precedingChar : '' , $ regexp , $ varName , false , true ];
189
+ } else {
190
+ $ token = ['variable ' , $ isSeparator ? $ precedingChar : '' , $ regexp , $ varName ];
189
191
}
192
+
193
+ $ tokens [] = $ token ;
190
194
$ variables [] = $ varName ;
191
195
}
192
196
@@ -199,7 +203,8 @@ private static function compilePattern(Route $route, $pattern, $isHost)
199
203
if (!$ isHost ) {
200
204
for ($ i = \count ($ tokens ) - 1 ; $ i >= 0 ; --$ i ) {
201
205
$ token = $ tokens [$ i ];
202
- if ('variable ' === $ token [0 ] && $ route ->hasDefault ($ token [3 ])) {
206
+ // variable is optional when it is not important and has a default value
207
+ if ('variable ' === $ token [0 ] && !($ token [5 ] ?? false ) && $ route ->hasDefault ($ token [3 ])) {
203
208
$ firstOptional = $ i ;
204
209
} else {
205
210
break ;
@@ -219,7 +224,7 @@ private static function compilePattern(Route $route, $pattern, $isHost)
219
224
$ regexp .= 'u ' ;
220
225
for ($ i = 0 , $ nbToken = \count ($ tokens ); $ i < $ nbToken ; ++$ i ) {
221
226
if ('variable ' === $ tokens [$ i ][0 ]) {
222
- $ tokens [$ i ][] = true ;
227
+ $ tokens [$ i ][4 ] = true ;
223
228
}
224
229
}
225
230
}
@@ -286,10 +291,6 @@ private static function computeRegexp(array $tokens, int $index, int $firstOptio
286
291
// Text tokens
287
292
return preg_quote ($ token [1 ], self ::REGEX_DELIMITER );
288
293
} else {
289
- if ('variable ' === $ token [0 ] && '! ' === $ token [3 ][0 ]) {
290
- $ token [3 ] = substr ($ token [3 ], 1 );
291
- }
292
-
293
294
// Variable tokens
294
295
if (0 === $ index && 0 === $ firstOptional ) {
295
296
// When the only token is an optional variable token, the separator is required
0 commit comments