Skip to content
Permalink
Browse files

[Routing] added hostname matching support to PhpMatcherDumper

  • Loading branch information...
arnaud-lb committed Apr 14, 2012
1 parent 402359b commit 85d11af880e4a6525da66f99c59aed9d0aa89e20
@@ -98,4 +98,52 @@ protected function setParent(DumperCollection $parent)
{
$this->parent = $parent;
}
/**
* Returns true if the attribute is defined
*
* @param string $name The attribute name
* @return Boolean true if the attribute is defined, false otherwise
*/
public function hasAttribute($name)
{
return array_key_exists($name, $this->attributes);
}
/**
* Returns an attribute by name
*
* @param string $name The attribute name
* @param mixed $default Default value is the attribute doesn't exist
* @return mixed The attribute value
*/
public function getAttribute($name, $default = null)
{
if ($this->hasAttribute($name)) {
return $this->attributes[$name];
} else {
return $default;
}
}
/**
* Sets an attribute by name
*
* @param string $name The attribute name
* @param mixed $value The attribute value
*/
public function setAttribute($name, $value)
{
$this->attributes[$name] = $value;
}
/**
* Sets multiple attributes
*
* @param array $attributes The attributes
*/
public function setAttributes($attributes)
{
$this->attributes = $attributes;
}
}
@@ -109,10 +109,37 @@ public function match(\$pathinfo)
*/
private function compileRoutes(RouteCollection $routes, $supportsRedirections)
{
$collection = $this->flattenRouteCollection($routes);
$tree = $this->buildPrefixTree($collection);
$fetchedHostname = false;
return $this->compilePrefixRoutes($tree, $supportsRedirections);
$routes = $this->flattenRouteCollection($routes);
$groups = $this->groupRoutesByHostnameRegex($routes);
$code = '';
foreach ($groups as $collection) {
if (null !== $regex = $collection->getAttribute('hostname_regex')) {
if (!$fetchedHostname) {
$code .= " \$hostname = \$this->context->getHost();\n\n";
$fetchedHostname = true;
}
$code .= sprintf(" if (preg_match(%s, \$hostname, \$hostnameMatches)) {\n", var_export($regex, true));
}
$tree = $this->buildPrefixTree($collection);
$groupCode = $this->compilePrefixRoutes($tree, $supportsRedirections);
if (null !== $regex) {
// apply extra indention at each line (except empty ones)
$groupCode = preg_replace('/^.{2,}$/m', ' $0', $groupCode);
$code .= $groupCode;
$code .= " }\n\n";
} else {
$code .= $groupCode;
}
}
return $code;
}
/**
@@ -171,6 +198,7 @@ private function compileRoute(Route $route, $name, $supportsRedirections, $paren
$conditions = array();
$hasTrailingSlash = false;
$matches = false;
$hostnameMatches = false;
$methods = array();
if ($req = $route->getRequirement('_method')) {
@@ -183,7 +211,7 @@ private function compileRoute(Route $route, $name, $supportsRedirections, $paren
$supportsTrailingSlash = $supportsRedirections && (!$methods || in_array('HEAD', $methods));
if (!count($compiledRoute->getVariables()) && false !== preg_match('#^(.)\^(?<url>.*?)\$\1#', $compiledRoute->getRegex(), $m)) {
if (!count($compiledRoute->getPathVariables()) && false !== preg_match('#^(.)\^(?<url>.*?)\$\1#', $compiledRoute->getRegex(), $m)) {
if ($supportsTrailingSlash && substr($m['url'], -1) === '/') {
$conditions[] = sprintf("rtrim(\$pathinfo, '/') === %s", var_export(rtrim(str_replace('\\', '', $m['url']), '/'), true));
$hasTrailingSlash = true;
@@ -205,6 +233,10 @@ private function compileRoute(Route $route, $name, $supportsRedirections, $paren
$matches = true;
}
if ($compiledRoute->getHostnameVariables()) {
$hostnameMatches = true;
}
$conditions = implode(' && ', $conditions);
$code .= <<<EOF
@@ -263,10 +295,30 @@ private function compileRoute(Route $route, $name, $supportsRedirections, $paren
}
// optimize parameters array
if (true === $matches && $route->getDefaults()) {
$code .= sprintf(" return array_merge(\$this->mergeDefaults(\$matches, %s), array('_route' => '%s'));\n"
, str_replace("\n", '', var_export($route->getDefaults(), true)), $name);
} elseif (true === $matches) {
if (($matches || $hostnameMatches) && $route->getDefaults()) {
$vars = array();
if ($matches) {
$vars[] = '$matches';
}
if ($hostnameMatches) {
$vars[] = '$hostnameMatches';
}
$matchesExpr = implode(' + ', $vars);
$code .= sprintf(" return array_merge(\$this->mergeDefaults(%s, %s), array('_route' => '%s'));\n"
, $matchesExpr, str_replace("\n", '', var_export($route->getDefaults(), true)), $name);
} elseif ($matches || $hostnameMatches) {
if (!$matches) {
$code .= " \$matches = \$hostnameMatches;\n";
} else {
if ($hostnameMatches) {
$code .= " \$matches = \$matches + \$hostnameMatches;\n";
}
}
$code .= sprintf(" \$matches['_route'] = '%s';\n\n", $name);
$code .= " return \$matches;\n";
} elseif ($route->getDefaults()) {
@@ -308,6 +360,37 @@ private function flattenRouteCollection(RouteCollection $routes, DumperCollectio
return $to;
}
/**
* Groups consecutive routes having the same hostname regex
*
* The results is a collection of collections of routes having the same
* hostnameRegex
*
* @param DumperCollection $routes Flat collection of DumperRoutes
*
* @return DumperCollection A collection with routes grouped by hostname regex in sub-collections
*/
private function groupRoutesByHostnameRegex(DumperCollection $routes)
{
$groups = new DumperCollection();
$currentGroup = new DumperCollection();
$currentGroup->setAttribute('hostname_regex', null);
$groups->add($currentGroup);
foreach ($routes as $route) {
$hostnameRegex = $route->getRoute()->compile()->getHostnameRegex();
if ($currentGroup->getAttribute('hostname_regex') !== $hostnameRegex) {
$currentGroup = new DumperCollection();
$currentGroup->setAttribute('hostname_regex', $hostnameRegex);
$groups->add($currentGroup);
}
$currentGroup->add($route);
}
return $groups;
}
/**
* Organizes the routes into a prefix tree.
*
@@ -331,5 +414,4 @@ private function buildPrefixTree(DumperCollection $collection)
return $tree;
}
}
@@ -206,22 +206,121 @@ public function match($pathinfo)
return $matches;
}
if (0 === strpos($pathinfo, '/a')) {
if (0 === strpos($pathinfo, '/aba')) {
// ababa
if ($pathinfo === '/ababa') {
return array('_route' => 'ababa');
if (0 === strpos($pathinfo, '/aba')) {
// ababa
if ($pathinfo === '/ababa') {
return array('_route' => 'ababa');
}
// foo4
if (preg_match('#^/aba/(?<foo>[^/]++)$#s', $pathinfo, $matches)) {
$matches['_route'] = 'foo4';
return $matches;
}
}
$hostname = $this->context->getHost();
if (preg_match('#^a\\.example\\.com$#s', $hostname, $hostnameMatches)) {
// route1
if ($pathinfo === '/route1') {
return array('_route' => 'route1');
}
// route2
if ($pathinfo === '/c2/route2') {
return array('_route' => 'route2');
}
}
if (preg_match('#^b\\.example\\.com$#s', $hostname, $hostnameMatches)) {
// route3
if ($pathinfo === '/c2/route3') {
return array('_route' => 'route3');
}
}
if (preg_match('#^a\\.example\\.com$#s', $hostname, $hostnameMatches)) {
// route4
if ($pathinfo === '/route4') {
return array('_route' => 'route4');
}
}
if (preg_match('#^c\\.example\\.com$#s', $hostname, $hostnameMatches)) {
// route5
if ($pathinfo === '/route5') {
return array('_route' => 'route5');
}
}
// route6
if ($pathinfo === '/route6') {
return array('_route' => 'route6');
}
if (preg_match('#^(?<var1>[^\\.]++)\\.example\\.com$#s', $hostname, $hostnameMatches)) {
if (0 === strpos($pathinfo, '/route1')) {
// route11
if ($pathinfo === '/route11') {
$matches = $hostnameMatches;
$matches['_route'] = 'route11';
return $matches;
}
// foo4
if (preg_match('#^/aba/(?<foo>[^/]++)$#s', $pathinfo, $matches)) {
$matches['_route'] = 'foo4';
// route12
if ($pathinfo === '/route12') {
return array_merge($this->mergeDefaults($hostnameMatches, array ( 'var1' => 'val',)), array('_route' => 'route12'));
}
// route13
if (0 === strpos($pathinfo, '/route13') && preg_match('#^/route13/(?<name>[^/]++)$#s', $pathinfo, $matches)) {
$matches = $matches + $hostnameMatches;
$matches['_route'] = 'route13';
return $matches;
}
// route14
if (0 === strpos($pathinfo, '/route14') && preg_match('#^/route14/(?<name>[^/]++)$#s', $pathinfo, $matches)) {
return array_merge($this->mergeDefaults($matches + $hostnameMatches, array ( 'var1' => 'val',)), array('_route' => 'route14'));
}
}
}
if (preg_match('#^c\\.example\\.com$#s', $hostname, $hostnameMatches)) {
// route15
if (0 === strpos($pathinfo, '/route15') && preg_match('#^/route15/(?<name>[^/]++)$#s', $pathinfo, $matches)) {
$matches['_route'] = 'route15';
return $matches;
}
}
if (0 === strpos($pathinfo, '/route1')) {
// route16
if (0 === strpos($pathinfo, '/route16') && preg_match('#^/route16/(?<name>[^/]++)$#s', $pathinfo, $matches)) {
return array_merge($this->mergeDefaults($matches, array ( 'var1' => 'val',)), array('_route' => 'route16'));
}
// route17
if ($pathinfo === '/route17') {
return array('_route' => 'route17');
}
}
if (0 === strpos($pathinfo, '/a')) {
// a
if ($pathinfo === '/a/a...') {
return array('_route' => 'a');

0 comments on commit 85d11af

Please sign in to comment.
You can’t perform that action at this time.