Browse Source

Add documentation and updated tests for RedirectRoute

Now that matching raises exceptions, the tests needed to be
restructured.
Mark Story 10 years ago
parent
commit
93668043e7

+ 23 - 1
src/Routing/Exception/RedirectException.php

@@ -1,9 +1,31 @@
 <?php
-
+/**
+ * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
+ * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
+ *
+ * Licensed under The MIT License
+ * For full copyright and license information, please see the LICENSE.txt
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @copyright     Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
+ * @link          http://cakephp.org CakePHP(tm) Project
+ * @since         3.2.0
+ * @license       http://www.opensource.org/licenses/mit-license.php MIT License
+ */
 namespace Cake\Routing\Exception;
 
 use RuntimeException;
 
+/**
+ * An exception subclass used by the routing layer to indicate
+ * that a route has resolved to a redirect.
+ *
+ * The URL and status code are provided as constructor arguments.
+ *
+ * ```
+ * throw new RedirectException('http://example.com/some/path', 301);
+ * ```
+ */
 class RedirectException extends RuntimeException
 {
 }

+ 6 - 4
src/Routing/Route/RedirectRoute.php

@@ -23,6 +23,8 @@ use Cake\Routing\Router;
  * are useful when you want to have Routing layer redirects occur in your
  * application, for when URLs move.
  *
+ * Redirection is signalled by an exception that halts route matching and
+ * defines the redirect URL and status code.
  */
 class RedirectRoute extends Route
 {
@@ -31,6 +33,7 @@ class RedirectRoute extends Route
      * A Response object
      *
      * @var \Cake\Network\Response
+     * @deprecated 3.2.0 This property is unused.
      */
     public $response = null;
 
@@ -62,7 +65,9 @@ class RedirectRoute extends Route
      * redirection.
      *
      * @param string $url The URL to parse.
-     * @return false|null False on failure, null otherwise.
+     * @return false|null False on failure. An exception is raised on a successful match.
+     * @throws \Cake\Routing\Exception\RedirectException An exception is raised on successful match.
+     *   This is used to halt route matching and signal to the middleware that a redirect should happen.
      */
     public function parse($url)
     {
@@ -70,9 +75,6 @@ class RedirectRoute extends Route
         if (!$params) {
             return false;
         }
-        if (!$this->response) {
-            $this->response = new Response();
-        }
         $redirect = $this->redirect;
         if (count($this->redirect) === 1 && !isset($this->redirect['controller'])) {
             $redirect = $this->redirect[0];

+ 116 - 48
tests/TestCase/Routing/Route/RedirectRouteTest.php

@@ -36,82 +36,150 @@ class RedirectRouteTest extends TestCase
     public function setUp()
     {
         parent::setUp();
-        Configure::write('Routing', ['admin' => null, 'prefixes' => []]);
         Router::reload();
+
+        Router::connect('/:controller', ['action' => 'index']);
+        Router::connect('/:controller/:action/*');
     }
 
     /**
      * test the parsing of routes.
      *
+     * @expectedException Cake\Routing\Exception\RedirectException
+     * @expectedExceptionMessage http://localhost/posts
+     * @expectedExceptionCode 301
      * @return void
      */
-    public function testParsing()
+    public function testParseSimple()
     {
-        Router::connect('/:controller', ['action' => 'index']);
-        Router::connect('/:controller/:action/*');
-
         $route = new RedirectRoute('/home', ['controller' => 'posts']);
-        $route->response = $this->getMock('Cake\Network\Response', ['_sendHeader', 'stop']);
-        $result = $route->parse('/home');
-        $header = $route->response->header();
-        $this->assertEquals(Router::url('/posts', true), $header['Location']);
+        $route->parse('/home');
+    }
 
+    /**
+     * test the parsing of routes.
+     *
+     * @expectedException Cake\Routing\Exception\RedirectException
+     * @expectedExceptionMessage http://localhost/posts
+     * @expectedExceptionCode 301
+     * @return void
+     */
+    public function testParseArray()
+    {
         $route = new RedirectRoute('/home', ['controller' => 'posts', 'action' => 'index']);
-        $route->response = $this->getMock('Cake\Network\Response', ['_sendHeader', 'stop']);
-        $result = $route->parse('/home');
-        $header = $route->response->header();
-        $this->assertEquals(Router::url('/posts', true), $header['Location']);
-        $this->assertEquals(301, $route->response->statusCode());
+        $route->parse('/home');
+    }
 
+    /**
+     * test redirecting to an external url
+     *
+     * @expectedException Cake\Routing\Exception\RedirectException
+     * @expectedExceptionMessage http://google.com
+     * @expectedExceptionCode 301
+     * @return void
+     */
+    public function testParseAbsolute()
+    {
         $route = new RedirectRoute('/google', 'http://google.com');
-        $route->response = $this->getMock('Cake\Network\Response', ['_sendHeader', 'stop']);
-        $result = $route->parse('/google');
-        $header = $route->response->header();
-        $this->assertEquals('http://google.com', $header['Location']);
+        $route->parse('/google');
+    }
 
+    /**
+     * test redirecting with a status code
+     *
+     * @expectedException Cake\Routing\Exception\RedirectException
+     * @expectedExceptionMessage http://localhost/posts/view
+     * @expectedExceptionCode 302
+     * @return void
+     */
+    public function testParseStatusCode()
+    {
         $route = new RedirectRoute('/posts/*', ['controller' => 'posts', 'action' => 'view'], ['status' => 302]);
-        $route->response = $this->getMock('Cake\Network\Response', ['_sendHeader', 'stop']);
-        $result = $route->parse('/posts/2');
-        $header = $route->response->header();
-        $this->assertEquals(Router::url('/posts/view', true), $header['Location']);
-        $this->assertEquals(302, $route->response->statusCode());
+        $route->parse('/posts/2');
+    }
 
+    /**
+     * test redirecting with the persist option
+     *
+     * @expectedException Cake\Routing\Exception\RedirectException
+     * @expectedExceptionMessage http://localhost/posts/view/2
+     * @expectedExceptionCode 301
+     * @return void
+     */
+    public function testParsePersist()
+    {
         $route = new RedirectRoute('/posts/*', ['controller' => 'posts', 'action' => 'view'], ['persist' => true]);
-        $route->response = $this->getMock('Cake\Network\Response', ['_sendHeader', 'stop']);
-        $result = $route->parse('/posts/2');
-        $header = $route->response->header();
-        $this->assertEquals(Router::url('/posts/view/2', true), $header['Location']);
+        $route->parse('/posts/2');
+    }
 
+    /**
+     * test redirecting with persist and string target URLs
+     *
+     * @expectedException Cake\Routing\Exception\RedirectException
+     * @expectedExceptionMessage http://localhost/test
+     * @expectedExceptionCode 301
+     * @return void
+     */
+    public function testParsePersistStringUrl()
+    {
         $route = new RedirectRoute('/posts/*', '/test', ['persist' => true]);
-        $route->response = $this->getMock('Cake\Network\Response', ['_sendHeader', 'stop']);
-        $result = $route->parse('/posts/2');
-        $header = $route->response->header();
-        $this->assertEquals(Router::url('/test', true), $header['Location']);
+        $route->parse('/posts/2');
+    }
 
+    /**
+     * test redirecting with persist and passed args
+     *
+     * @expectedException Cake\Routing\Exception\RedirectException
+     * @expectedExceptionMessage http://localhost/tags/add/passme
+     * @expectedExceptionCode 301
+     * @return void
+     */
+    public function testParsePersistPassedArgs()
+    {
         $route = new RedirectRoute('/my_controllers/:action/*', ['controller' => 'tags', 'action' => 'add'], ['persist' => true]);
-        $route->response = $this->getMock('Cake\Network\Response', ['_sendHeader', 'stop']);
-        $result = $route->parse('/my_controllers/do_something/passme');
-        $header = $route->response->header();
-        $this->assertEquals(Router::url('/tags/add/passme', true), $header['Location']);
+        $route->parse('/my_controllers/do_something/passme');
+    }
 
+    /**
+     * test redirecting without persist and passed args
+     *
+     * @expectedException Cake\Routing\Exception\RedirectException
+     * @expectedExceptionMessage http://localhost/tags/add
+     * @expectedExceptionCode 301
+     * @return void
+     */
+    public function testParseNoPersistPassedArgs()
+    {
         $route = new RedirectRoute('/my_controllers/:action/*', ['controller' => 'tags', 'action' => 'add']);
-        $route->response = $this->getMock('Cake\Network\Response', ['_sendHeader', 'stop']);
-        $result = $route->parse('/my_controllers/do_something/passme');
-        $header = $route->response->header();
-        $this->assertEquals(Router::url('/tags/add', true), $header['Location']);
+        $route->parse('/my_controllers/do_something/passme');
+    }
 
+    /**
+     * test redirecting with patterns
+     *
+     * @expectedException Cake\Routing\Exception\RedirectException
+     * @expectedExceptionMessage http://localhost/tags/add?lang=nl
+     * @expectedExceptionCode 301
+     * @return void
+     */
+    public function testParsePersistPatterns()
+    {
         $route = new RedirectRoute('/:lang/my_controllers', ['controller' => 'tags', 'action' => 'add'], ['lang' => '(nl|en)', 'persist' => ['lang']]);
-        $route->response = $this->getMock('Cake\Network\Response', ['_sendHeader', 'stop']);
-        $result = $route->parse('/nl/my_controllers/');
-        $header = $route->response->header();
-        $this->assertEquals(Router::url('/tags/add?lang=nl', true), $header['Location']);
+        $route->parse('/nl/my_controllers/');
+    }
 
-        Router::reload(); // reset default routes
+    /**
+     * test redirecting with patterns and a routed target
+     *
+     * @expectedException Cake\Routing\Exception\RedirectException
+     * @expectedExceptionMessage http://localhost/nl/preferred_controllers
+     * @expectedExceptionCode 301
+     * @return void
+     */
+    public function testParsePersistMatchesAnotherRoute()
+    {
         Router::connect('/:lang/preferred_controllers', ['controller' => 'tags', 'action' => 'add'], ['lang' => '(nl|en)', 'persist' => ['lang']]);
         $route = new RedirectRoute('/:lang/my_controllers', ['controller' => 'tags', 'action' => 'add'], ['lang' => '(nl|en)', 'persist' => ['lang']]);
-        $route->response = $this->getMock('Cake\Network\Response', ['_sendHeader', 'stop']);
-        $result = $route->parse('/nl/my_controllers/');
-        $header = $route->response->header();
-        $this->assertEquals(Router::url('/nl/preferred_controllers', true), $header['Location']);
+        $route->parse('/nl/my_controllers/');
     }
 }