Browse Source

Merge pull request #10062 from cakephp/issue-10057

Make routes use host conditions to generate URLs
José Lorenzo Rodríguez 9 years ago
parent
commit
506cf85bfb

+ 19 - 3
src/Routing/Route/Route.php

@@ -480,7 +480,7 @@ class Route
             $this->compile();
         }
         $defaults = $this->defaults;
-        $context += ['params' => []];
+        $context += ['params' => [], '_port' => null, '_scheme' => null, '_host' => null];
 
         if (!empty($this->options['persist']) &&
             is_array($this->options['persist'])
@@ -503,6 +503,21 @@ class Route
             }
         }
 
+        // Apply the _host option if possible
+        if (isset($this->options['_host'])) {
+            if (!isset($hostOptions['_host']) && strpos($this->options['_host'], '*') === false) {
+                $hostOptions['_host'] = $this->options['_host'];
+            }
+            if (!isset($hostOptions['_host'])) {
+                $hostOptions['_host'] = $context['_host'];
+            }
+
+            // The host did not match the route preferences
+            if (!$this->hostMatches($hostOptions['_host'])) {
+                return false;
+            }
+        }
+
         // If no base is set, copy one in.
         if (!isset($hostOptions['_base']) && isset($context['_base'])) {
             $hostOptions['_base'] = $context['_base'];
@@ -671,11 +686,12 @@ class Route
         ) {
             $host = $params['_host'];
 
-            // append the port if it exists.
+            // append the port & scheme if they exists.
             if (isset($params['_port'])) {
                 $host .= ':' . $params['_port'];
             }
-            $out = "{$params['_scheme']}://{$host}{$out}";
+            $scheme = isset($params['_scheme']) ? $params['_scheme'] : 'http';
+            $out = "{$scheme}://{$host}{$out}";
         }
         if (!empty($params['_ext']) || !empty($query)) {
             $out = rtrim($out, '/');

+ 68 - 0
tests/TestCase/Routing/Route/RouteTest.php

@@ -537,6 +537,8 @@ class RouteTest extends TestCase
 
     /**
      * Test match() with _host and other keys.
+     *
+     * @return void
      */
     public function testMatchWithHostKeys()
     {
@@ -586,6 +588,72 @@ class RouteTest extends TestCase
     }
 
     /**
+     * Test that the _host option sets the default host.
+     *
+     * @return void
+     */
+    public function testMatchWithHostOption()
+    {
+        $route = new Route(
+            '/fallback',
+            ['controller' => 'Articles', 'action' => 'index'],
+            ['_host' => 'www.example.com']
+        );
+        $result = $route->match([
+            'controller' => 'Articles',
+            'action' => 'index'
+        ]);
+        $this->assertSame('http://www.example.com/fallback', $result);
+    }
+
+    /**
+     * Test wildcard host options
+     *
+     * @return void
+     */
+    public function testMatchWithHostWildcardOption()
+    {
+        $route = new Route(
+            '/fallback',
+            ['controller' => 'Articles', 'action' => 'index'],
+            ['_host' => '*.example.com']
+        );
+        $result = $route->match([
+            'controller' => 'Articles',
+            'action' => 'index'
+        ]);
+        $this->assertFalse($result, 'No request context means no match');
+
+        $result = $route->match([
+            'controller' => 'Articles',
+            'action' => 'index',
+        ], ['_host' => 'wrong.com']);
+        $this->assertFalse($result, 'Request context has bad host');
+
+        $result = $route->match([
+            'controller' => 'Articles',
+            'action' => 'index',
+            '_host' => 'wrong.com'
+        ]);
+        $this->assertFalse($result, 'Url param is wrong');
+
+        $result = $route->match([
+            'controller' => 'Articles',
+            'action' => 'index',
+            '_host' => 'foo.example.com'
+        ]);
+        $this->assertSame('http://foo.example.com/fallback', $result);
+
+        $result = $route->match([
+            'controller' => 'Articles',
+            'action' => 'index',
+        ], [
+            '_host' => 'foo.example.com'
+        ]);
+        $this->assertSame('http://foo.example.com/fallback', $result);
+    }
+
+    /**
      * Test that non-greedy routes fail with extra passed args
      *
      * @return void

+ 28 - 0
tests/TestCase/Routing/RouterTest.php

@@ -559,6 +559,34 @@ class RouterTest extends TestCase
     }
 
     /**
+     * Test url() with _host option routes with request context
+     *
+     * @return void
+     */
+    public function testUrlGenerationHostOptionRequestContext()
+    {
+        $server = [
+            'HTTP_HOST' => 'foo.example.com',
+            'DOCUMENT_ROOT' => '/Users/markstory/Sites',
+            'SCRIPT_FILENAME' => '/Users/markstory/Sites/subdir/webroot/index.php',
+            'PHP_SELF' => '/subdir/webroot/index.php/articles/view/1',
+            'REQUEST_URI' => '/subdir/articles/view/1',
+            'QUERY_STRING' => '',
+            'SERVER_PORT' => 80,
+        ];
+
+        Router::connect('/fallback', ['controller' => 'Articles'], ['_host' => '*.example.com']);
+        $request = ServerRequestFactory::fromGlobals($server);
+        Router::setRequestContext($request);
+
+        $result = Router::url(['controller' => 'Articles', 'action' => 'index']);
+        $this->assertEquals('http://foo.example.com/subdir/fallback', $result);
+
+        $result = Router::url(['controller' => 'Articles', 'action' => 'index'], true);
+        $this->assertEquals('http://foo.example.com/subdir/fallback', $result);
+    }
+
+    /**
      * Test that catch all routes work with a variety of falsey inputs.
      *
      * @return void