@@ -109,10 +109,37 @@ public function match(\$pathinfo)
109
109
*/
110
110
private function compileRoutes (RouteCollection $ routes , $ supportsRedirections )
111
111
{
112
- $ collection = $ this ->flattenRouteCollection ($ routes );
113
- $ tree = $ this ->buildPrefixTree ($ collection );
112
+ $ fetchedHostname = false ;
114
113
115
- return $ this ->compilePrefixRoutes ($ tree , $ supportsRedirections );
114
+ $ routes = $ this ->flattenRouteCollection ($ routes );
115
+ $ groups = $ this ->groupRoutesByHostnameRegex ($ routes );
116
+ $ code = '' ;
117
+
118
+ foreach ($ groups as $ collection ) {
119
+ if (null !== $ regex = $ collection ->getAttribute ('hostname_regex ' )) {
120
+
121
+ if (!$ fetchedHostname ) {
122
+ $ code .= " \$hostname = \$this->context->getHost(); \n\n" ;
123
+ $ fetchedHostname = true ;
124
+ }
125
+
126
+ $ code .= sprintf (" if (preg_match(%s, \$hostname, \$hostnameMatches)) { \n" , var_export ($ regex , true ));
127
+ }
128
+
129
+ $ tree = $ this ->buildPrefixTree ($ collection );
130
+ $ groupCode = $ this ->compilePrefixRoutes ($ tree , $ supportsRedirections );
131
+
132
+ if (null !== $ regex ) {
133
+ // apply extra indention at each line (except empty ones)
134
+ $ groupCode = preg_replace ('/^.{2,}$/m ' , ' $0 ' , $ groupCode );
135
+ $ code .= $ groupCode ;
136
+ $ code .= " } \n\n" ;
137
+ } else {
138
+ $ code .= $ groupCode ;
139
+ }
140
+ }
141
+
142
+ return $ code ;
116
143
}
117
144
118
145
/**
@@ -171,6 +198,7 @@ private function compileRoute(Route $route, $name, $supportsRedirections, $paren
171
198
$ conditions = array ();
172
199
$ hasTrailingSlash = false ;
173
200
$ matches = false ;
201
+ $ hostnameMatches = false ;
174
202
$ methods = array ();
175
203
176
204
if ($ req = $ route ->getRequirement ('_method ' )) {
@@ -183,7 +211,7 @@ private function compileRoute(Route $route, $name, $supportsRedirections, $paren
183
211
184
212
$ supportsTrailingSlash = $ supportsRedirections && (!$ methods || in_array ('HEAD ' , $ methods ));
185
213
186
- if (!count ($ compiledRoute ->getVariables ()) && false !== preg_match ('#^(.)\^(?<url>.*?)\$\1# ' , $ compiledRoute ->getRegex (), $ m )) {
214
+ if (!count ($ compiledRoute ->getPathVariables ()) && false !== preg_match ('#^(.)\^(?<url>.*?)\$\1# ' , $ compiledRoute ->getRegex (), $ m )) {
187
215
if ($ supportsTrailingSlash && substr ($ m ['url ' ], -1 ) === '/ ' ) {
188
216
$ conditions [] = sprintf ("rtrim( \$pathinfo, '/') === %s " , var_export (rtrim (str_replace ('\\' , '' , $ m ['url ' ]), '/ ' ), true ));
189
217
$ hasTrailingSlash = true ;
@@ -205,6 +233,10 @@ private function compileRoute(Route $route, $name, $supportsRedirections, $paren
205
233
$ matches = true ;
206
234
}
207
235
236
+ if ($ compiledRoute ->getHostnameVariables ()) {
237
+ $ hostnameMatches = true ;
238
+ }
239
+
208
240
$ conditions = implode (' && ' , $ conditions );
209
241
210
242
$ code .= <<<EOF
@@ -263,10 +295,30 @@ private function compileRoute(Route $route, $name, $supportsRedirections, $paren
263
295
}
264
296
265
297
// optimize parameters array
266
- if (true === $ matches && $ route ->getDefaults ()) {
267
- $ code .= sprintf (" return array_merge( \$this->mergeDefaults( \$matches, %s), array('_route' => '%s')); \n"
268
- , str_replace ("\n" , '' , var_export ($ route ->getDefaults (), true )), $ name );
269
- } elseif (true === $ matches ) {
298
+ if (($ matches || $ hostnameMatches ) && $ route ->getDefaults ()) {
299
+
300
+ $ vars = array ();
301
+ if ($ matches ) {
302
+ $ vars [] = '$matches ' ;
303
+ }
304
+ if ($ hostnameMatches ) {
305
+ $ vars [] = '$hostnameMatches ' ;
306
+ }
307
+ $ matchesExpr = implode (' + ' , $ vars );
308
+
309
+ $ code .= sprintf (" return array_merge( \$this->mergeDefaults(%s, %s), array('_route' => '%s')); \n"
310
+ , $ matchesExpr , str_replace ("\n" , '' , var_export ($ route ->getDefaults (), true )), $ name );
311
+
312
+ } elseif ($ matches || $ hostnameMatches ) {
313
+
314
+ if (!$ matches ) {
315
+ $ code .= " \$matches = \$hostnameMatches; \n" ;
316
+ } else {
317
+ if ($ hostnameMatches ) {
318
+ $ code .= " \$matches = \$matches + \$hostnameMatches; \n" ;
319
+ }
320
+ }
321
+
270
322
$ code .= sprintf (" \$matches['_route'] = '%s'; \n\n" , $ name );
271
323
$ code .= " return \$matches; \n" ;
272
324
} elseif ($ route ->getDefaults ()) {
@@ -308,6 +360,37 @@ private function flattenRouteCollection(RouteCollection $routes, DumperCollectio
308
360
return $ to ;
309
361
}
310
362
363
+ /**
364
+ * Groups consecutive routes having the same hostname regex
365
+ *
366
+ * The results is a collection of collections of routes having the same
367
+ * hostnameRegex
368
+ *
369
+ * @param DumperCollection $routes Flat collection of DumperRoutes
370
+ *
371
+ * @return DumperCollection A collection with routes grouped by hostname regex in sub-collections
372
+ */
373
+ private function groupRoutesByHostnameRegex (DumperCollection $ routes )
374
+ {
375
+ $ groups = new DumperCollection ();
376
+
377
+ $ currentGroup = new DumperCollection ();
378
+ $ currentGroup ->setAttribute ('hostname_regex ' , null );
379
+ $ groups ->add ($ currentGroup );
380
+
381
+ foreach ($ routes as $ route ) {
382
+ $ hostnameRegex = $ route ->getRoute ()->compile ()->getHostnameRegex ();
383
+ if ($ currentGroup ->getAttribute ('hostname_regex ' ) !== $ hostnameRegex ) {
384
+ $ currentGroup = new DumperCollection ();
385
+ $ currentGroup ->setAttribute ('hostname_regex ' , $ hostnameRegex );
386
+ $ groups ->add ($ currentGroup );
387
+ }
388
+ $ currentGroup ->add ($ route );
389
+ }
390
+
391
+ return $ groups ;
392
+ }
393
+
311
394
/**
312
395
* Organizes the routes into a prefix tree.
313
396
*
@@ -331,5 +414,4 @@ private function buildPrefixTree(DumperCollection $collection)
331
414
332
415
return $ tree ;
333
416
}
334
-
335
417
}
0 commit comments