@@ -93,10 +93,31 @@ public function addExpressionLanguageProvider(ExpressionFunctionProviderInterfac
93
93
*/
94
94
private function generateMatchMethod ($ supportsRedirections )
95
95
{
96
- $ code = rtrim ($ this ->compileRoutes ($ this ->getRoutes (), $ supportsRedirections ), "\n" );
97
-
98
96
return <<<EOF
99
97
public function match( \$rawPathinfo)
98
+ {
99
+ try {
100
+ return \$this->matchWithoutTrailingSlashManagement( \$rawPathinfo);
101
+ } catch (MethodNotAllowedException \$e) {
102
+ throw \$e;
103
+ } catch (ResourceNotFoundException \$e) {
104
+ return \$this->matchWithTrailingSlashManagement( \$rawPathinfo);
105
+ }
106
+ }
107
+
108
+ {$ this ->generateMatchWithTrailingSlashManagement ($ supportsRedirections )}
109
+
110
+ {$ this ->generateMatchWithoutTrailingSlashManagement ($ supportsRedirections )}
111
+ EOF ;
112
+
113
+ }
114
+
115
+ private function generateMatchWithTrailingSlashManagement ($ supportsRedirections )
116
+ {
117
+ $ code = rtrim ($ this ->compileRoutes ($ this ->getRoutes (), $ supportsRedirections , true ), "\n" );
118
+
119
+ return <<<EOF
120
+ public function matchWithTrailingSlashManagement( \$rawPathinfo)
100
121
{
101
122
\$allow = [];
102
123
\$pathinfo = rawurldecode( \$rawPathinfo);
@@ -109,6 +130,30 @@ public function match(\$rawPathinfo)
109
130
\$canonicalMethod = 'GET';
110
131
}
111
132
133
+ $ code
134
+
135
+ throw 0 < count( \$allow) ? new MethodNotAllowedException(array_unique( \$allow)) : new ResourceNotFoundException();
136
+ }
137
+ EOF ;
138
+ }
139
+
140
+ private function generateMatchWithoutTrailingSlashManagement ($ supportsRedirections )
141
+ {
142
+ $ code = rtrim ($ this ->compileRoutes ($ this ->getRoutes (), $ supportsRedirections , false ), "\n" );
143
+
144
+ return <<<EOF
145
+ public function matchWithoutTrailingSlashManagement( \$rawPathinfo)
146
+ {
147
+ \$allow = [];
148
+ \$pathinfo = rawurldecode( \$rawPathinfo);
149
+ \$context = \$this->context;
150
+ \$request = \$this->request ?: \$this->createRequest( \$pathinfo);
151
+ \$requestMethod = \$canonicalMethod = \$context->getMethod();
152
+
153
+ if ('HEAD' === \$requestMethod) {
154
+ \$canonicalMethod = 'GET';
155
+ }
156
+
112
157
$ code
113
158
114
159
throw 0 < count( \$allow) ? new MethodNotAllowedException(array_unique( \$allow)) : new ResourceNotFoundException();
@@ -124,7 +169,7 @@ public function match(\$rawPathinfo)
124
169
*
125
170
* @return string PHP code
126
171
*/
127
- private function compileRoutes (RouteCollection $ routes , $ supportsRedirections )
172
+ private function compileRoutes (RouteCollection $ routes , $ supportsRedirections, $ trailingSlashManagement = true )
128
173
{
129
174
$ fetchedHost = false ;
130
175
$ groups = $ this ->groupRoutesByHostRegex ($ routes );
@@ -141,7 +186,7 @@ private function compileRoutes(RouteCollection $routes, $supportsRedirections)
141
186
}
142
187
143
188
$ tree = $ this ->buildStaticPrefixCollection ($ collection );
144
- $ groupCode = $ this ->compileStaticPrefixRoutes ($ tree , $ supportsRedirections );
189
+ $ groupCode = $ this ->compileStaticPrefixRoutes ($ tree , $ supportsRedirections, $ trailingSlashManagement );
145
190
146
191
if (null !== $ regex ) {
147
192
// apply extra indention at each line (except empty ones)
@@ -184,7 +229,7 @@ private function buildStaticPrefixCollection(DumperCollection $collection)
184
229
*
185
230
* @return string PHP code
186
231
*/
187
- private function compileStaticPrefixRoutes (StaticPrefixCollection $ collection , $ supportsRedirections , $ ifOrElseIf = 'if ' )
232
+ private function compileStaticPrefixRoutes (StaticPrefixCollection $ collection , $ supportsRedirections , $ trailingSlashManagement , $ ifOrElseIf = 'if ' )
188
233
{
189
234
$ code = '' ;
190
235
$ prefix = $ collection ->getPrefix ();
@@ -200,7 +245,7 @@ private function compileStaticPrefixRoutes(StaticPrefixCollection $collection, $
200
245
$ code .= $ this ->compileStaticPrefixRoutes ($ route , $ supportsRedirections , $ ifOrElseIf );
201
246
$ ifOrElseIf = 'elseif ' ;
202
247
} else {
203
- $ code .= $ this ->compileRoute ($ route [1 ]->getRoute (), $ route [1 ]->getName (), $ supportsRedirections , $ prefix )."\n" ;
248
+ $ code .= $ this ->compileRoute ($ route [1 ]->getRoute (), $ route [1 ]->getName (), $ supportsRedirections , $ trailingSlashManagement , $ prefix )."\n" ;
204
249
$ ifOrElseIf = 'if ' ;
205
250
}
206
251
}
@@ -226,7 +271,7 @@ private function compileStaticPrefixRoutes(StaticPrefixCollection $collection, $
226
271
*
227
272
* @throws \LogicException
228
273
*/
229
- private function compileRoute (Route $ route , $ name , $ supportsRedirections , $ parentPrefix = null )
274
+ private function compileRoute (Route $ route , $ name , $ supportsRedirections , $ trailingSlashManagement , $ parentPrefix = null )
230
275
{
231
276
$ code = '' ;
232
277
$ compiledRoute = $ route ->compile ();
@@ -236,7 +281,7 @@ private function compileRoute(Route $route, $name, $supportsRedirections, $paren
236
281
$ hostMatches = false ;
237
282
$ methods = $ route ->getMethods ();
238
283
239
- $ supportsTrailingSlash = $ supportsRedirections && (!$ methods || \in_array ('GET ' , $ methods ));
284
+ $ supportsTrailingSlash = $ supportsRedirections && (!$ methods || \in_array ('GET ' , $ methods )) && $ trailingSlashManagement ;
240
285
$ regex = $ compiledRoute ->getRegex ();
241
286
242
287
if (!\count ($ compiledRoute ->getPathVariables ()) && false !== preg_match ('#^(.)\^(?P<url>.*?)\$\1# ' .('u ' === substr ($ regex , -1 ) ? 'u ' : '' ), $ regex , $ m )) {