@@ -109,10 +109,37 @@ public function match(\$pathinfo)
109109 */
110110 private function compileRoutes (RouteCollection $ routes , $ supportsRedirections )
111111 {
112- $ collection = $ this ->flattenRouteCollection ($ routes );
113- $ tree = $ this ->buildPrefixTree ($ collection );
112+ $ fetchedHostname = false ;
114113
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+
6D47
$ code .= $ groupCode ;
136+ $ code .= " } \n\n" ;
137+ } else {
138+ $ code .= $ groupCode ;
139+ }
140+ }
141+
142+ return $ code ;
116143 }
117144
118145 /**
@@ -171,6 +198,7 @@ private function compileRoute(Route $route, $name, $supportsRedirections, $paren
171198 $ conditions = array ();
172199 $ hasTrailingSlash = false ;
173200 $ matches = false ;
201+ $ hostnameMatches = false ;
174202 $ methods = array ();
175203
176204 if ($ req = $ route ->getRequirement ('_method ' )) {
9E79
@@ -183,7 +211,7 @@ private function compileRoute(Route $route, $name, $supportsRedirections, $paren
183211
184212 $ supportsTrailingSlash = $ supportsRedirections && (!$ methods || in_array ('HEAD ' , $ methods ));
185213
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 )) {
187215 if ($ supportsTrailingSlash && substr ($ m ['url ' ], -1 ) === '/ ' ) {
188216 $ conditions [] = sprintf ("rtrim( \$pathinfo, '/') === %s " , var_export (rtrim (str_replace ('\\' , '' , $ m ['url ' ]), '/ ' ), true ));
189217 $ hasTrailingSlash = true ;
@@ -205,6 +233,10 @@ private function compileRoute(Route $route, $name, $supportsRedirections, $paren
205233 $ matches = true ;
206234 }
207235
236+ if ($ compiledRoute ->getHostnameVariables ()) {
237+ $ hostnameMatches = true ;
238+ }
239+
208240 $ conditions = implode (' && ' , $ conditions );
209241
210242 $ code .= <<<EOF
@@ -263,10 +295,30 @@ private function compileRoute(Route $route, $name, $supportsRedirections, $paren
263295 }
264296
265297 // 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+
270322 $ code .= sprintf (" \$matches['_route'] = '%s'; \n\n" , $ name );
271323 $ code .= " return \$matches; \n" ;
272324 } elseif ($ route ->getDefaults ()) {
@@ -308,6 +360,37 @@ private function flattenRouteCollection(RouteCollection $routes, DumperCollectio
308360 return $ to ;
309361 }
310362
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+
311394 /**
312395 * Organizes the routes into a prefix tree.
313396 *
@@ -331,5 +414,4 @@ private function buildPrefixTree(DumperCollection $collection)
331414
332415 return $ tree ;
333416 }
334-
335417}
0 commit comments