Browse Source

Merge pull request #9831 from cakephp/response-helpers-3

3.next - Add more Response helpers
Mark Story 9 years ago
parent
commit
966d3b7eb6
2 changed files with 221 additions and 0 deletions
  1. 117 0
      src/Network/Response.php
  2. 104 0
      tests/TestCase/Network/ResponseTest.php

+ 117 - 0
src/Network/Response.php

@@ -1265,6 +1265,30 @@ class Response implements ResponseInterface
     }
 
     /**
+     * Create a new instace with the public/private Cache-Control directive set.
+     *
+     * @param bool $public If set to true, the Cache-Control header will be set as public
+     *   if set to false, the response will be set to private.
+     * @param int|null $time time in seconds after which the response should no longer be considered fresh.
+     * @return static
+     */
+    public function withSharable($public, $time = null)
+    {
+        $new = clone $this;
+        unset($new->_cacheDirectives['private'], $new->_cacheDirectives['public']);
+
+        $key = $public ? 'public' : 'private';
+        $new->_cacheDirectives[$key] = true;
+
+        if ($time !== null) {
+            $new->_cacheDirectives['max-age'] = $time;
+        }
+        $new->_setCacheControl();
+
+        return $new;
+    }
+
+    /**
      * Sets the Cache-Control s-maxage directive.
      *
      * The max-age is the number of seconds after which the response should no longer be considered
@@ -1310,6 +1334,24 @@ class Response implements ResponseInterface
     }
 
     /**
+     * Create an instance with Cache-Control max-age directive set.
+     *
+     * The max-age is the number of seconds after which the response should no longer be considered
+     * a good candidate to be fetched from the local (client) cache.
+     *
+     * @param int $seconds The seconds a cached response can be considered valid
+     * @return static
+     */
+    public function withMaxAge($seconds)
+    {
+        $new = clone $this;
+        $new->_cacheDirectives['max-age'] = $seconds;
+        $new->_setCacheControl();
+
+        return $new;
+    }
+
+    /**
      * Sets the Cache-Control must-revalidate directive.
      * must-revalidate indicates that the response should not be served
      * stale by a cache under any circumstance without first revalidating
@@ -1432,6 +1474,35 @@ class Response implements ResponseInterface
     }
 
     /**
+     * Create a new instance as 'not modified'
+     *
+     * This will remove any body contents set the status code
+     * to "304" and removing headers that describe
+     * a response body.
+     *
+     * @return static
+     */
+    public function withNotModified()
+    {
+        $new = $this->withStatus(304);
+        $new->_createStream();
+        $remove = [
+            'Allow',
+            'Content-Encoding',
+            'Content-Language',
+            'Content-Length',
+            'Content-MD5',
+            'Content-Type',
+            'Last-Modified'
+        ];
+        foreach ($remove as $header) {
+            $new = $new->withoutHeader($header);
+        }
+
+        return $new;
+    }
+
+    /**
      * Sets the Vary header for the response, if an array is passed,
      * values will be imploded into a comma separated string. If no
      * parameters are passed, then an array with the current Vary header
@@ -1440,6 +1511,7 @@ class Response implements ResponseInterface
      * @param string|array|null $cacheVariances A single Vary string or an array
      *   containing the list for variances.
      * @return array|null
+     * @deprecated 3.4.0 Use withVary() instead.
      */
     public function vary($cacheVariances = null)
     {
@@ -1456,6 +1528,22 @@ class Response implements ResponseInterface
     }
 
     /**
+     * Create a new instance with the Vary header set.
+     *
+     * If an array is passed values will be imploded into a comma
+     * separated string. If no parameters are passed, then an
+     * array with the current Vary header value is returned
+     *
+     * @param string|array $cacheVariances A single Vary string or an array
+     *   containing the list for variances.
+     * @return static
+     */
+    public function withVary($cacheVariances)
+    {
+        return $this->withHeader('Vary', (array)$cacheVariances);
+    }
+
+    /**
      * Sets the response Etag, Etags are a strong indicative that a response
      * can be cached by a HTTP client. A bad way of generating Etags is
      * creating a hash of the response output, instead generate a unique
@@ -1475,6 +1563,7 @@ class Response implements ResponseInterface
      * @param bool $weak Whether the response is semantically the same as
      *   other with the same hash or not
      * @return string|null
+     * @deprecated 3.4.0 Use withEtag() instead.
      */
     public function etag($hash = null, $weak = false)
     {
@@ -1490,6 +1579,34 @@ class Response implements ResponseInterface
     }
 
     /**
+     * Create a new instance with the Etag header set.
+     *
+     * Etags are a strong indicative that a response can be cached by a
+     * HTTP client. A bad way of generating Etags is creating a hash of
+     * the response output, instead generate a unique hash of the
+     * unique components that identifies a request, such as a
+     * modification time, a resource Id, and anything else you consider it
+     * that makes the response unique.
+     *
+     * The second parameter is used to inform clients that the content has
+     * changed, but semantically it is equivalent to existing cached values. Consider
+     * a page with a hit counter, two different page views are equivalent, but
+     * they differ by a few bytes. This permits the Client to decide whether they should
+     * use the cached data.
+     *
+     * @param string $hash The unique hash that identifies this response
+     * @param bool $weak Whether the response is semantically the same as
+     *   other with the same hash or not. Defaults to false
+     * @return static
+     */
+    public function withEtag($hash, $weak = false)
+    {
+        $hash = sprintf('%s"%s"', ($weak) ? 'W/' : null, $hash);
+
+        return $this->withHeader('Etag', $hash);
+    }
+
+    /**
      * Returns a DateTime object initialized at the $time param and using UTC
      * as timezone
      *

+ 104 - 0
tests/TestCase/Network/ResponseTest.php

@@ -832,6 +832,28 @@ class ResponseTest extends TestCase
     }
 
     /**
+     * Tests withSharable()
+     *
+     * @return void
+     */
+    public function testWithSharable()
+    {
+        $response = new Response();
+        $new = $response->withSharable(true);
+        $this->assertFalse($response->hasHeader('Cache-Control'), 'old instance unchanged');
+        $this->assertEquals('public', $new->getHeaderLine('Cache-Control'));
+
+        $new = $response->withSharable(false);
+        $this->assertEquals('private', $new->getHeaderLine('Cache-Control'));
+
+        $new = $response->withSharable(true, 3600);
+        $this->assertEquals('public, max-age=3600', $new->getHeaderLine('Cache-Control'));
+
+        $new = $response->withSharable(false, 3600);
+        $this->assertEquals('private, max-age=3600', $new->getHeaderLine('Cache-Control'));
+    }
+
+    /**
      * Tests setting of max-age Cache-Control directive
      *
      * @return void
@@ -851,6 +873,24 @@ class ResponseTest extends TestCase
     }
 
     /**
+     * Tests withMaxAge()
+     *
+     * @return void
+     */
+    public function testWithMaxAge()
+    {
+        $response = new Response();
+        $this->assertFalse($response->hasHeader('Cache-Control'));
+
+        $new = $response->withMaxAge(3600);
+        $this->assertEquals('max-age=3600', $new->getHeaderLine('Cache-Control'));
+
+        $new = $response->withMaxAge(3600)
+            ->withSharable(false);
+        $this->assertEquals('max-age=3600, private', $new->getHeaderLine('Cache-Control'));
+    }
+
+    /**
      * Tests setting of s-maxage Cache-Control directive
      *
      * @return void
@@ -913,6 +953,24 @@ class ResponseTest extends TestCase
     }
 
     /**
+     * Tests withVary()
+     *
+     * @return void
+     */
+    public function testWithVary()
+    {
+        $response = new Response();
+        $new = $response->withVary('Accept-encoding');
+
+        $this->assertFalse($response->hasHeader('Vary'));
+        $this->assertEquals('Accept-encoding', $new->getHeaderLine('Vary'));
+
+        $new = $response->withVary(['Accept-encoding', 'Accept-language']);
+        $this->assertFalse($response->hasHeader('Vary'));
+        $this->assertEquals('Accept-encoding,Accept-language', $new->getHeaderLine('Vary'));
+    }
+
+    /**
      * Tests getting/setting the Etag header
      *
      * @return void
@@ -931,6 +989,23 @@ class ResponseTest extends TestCase
     }
 
     /**
+     * Tests withEtag()
+     *
+     * @return void
+     */
+    public function testWithEtag()
+    {
+        $response = new Response();
+        $new = $response->withEtag('something');
+
+        $this->assertFalse($response->hasHeader('Etag'));
+        $this->assertEquals('"something"', $new->getHeaderLine('Etag'));
+
+        $new = $response->withEtag('something', true);
+        $this->assertEquals('W/"something"', $new->getHeaderLine('Etag'));
+    }
+
+    /**
      * Tests that the response is able to be marked as not modified
      *
      * @return void
@@ -952,6 +1027,35 @@ class ResponseTest extends TestCase
     }
 
     /**
+     * Tests withNotModified()
+     *
+     * @return void
+     */
+    public function testWithNotModified()
+    {
+        $response = new Response(['body' => 'something']);
+        $response = $response->withLength(100)
+            ->withStatus(200)
+            ->withHeader('Last-Modified', 'value')
+            ->withHeader('Content-Language', 'en-EN')
+            ->withHeader('X-things', 'things')
+            ->withType('application/json');
+
+        $new = $response->withNotModified();
+        $this->assertTrue($response->hasHeader('Content-Language'), 'old instance not changed');
+        $this->assertTrue($response->hasHeader('Content-Length'), 'old instance not changed');
+
+        $this->assertFalse($new->hasHeader('Content-Type'));
+        $this->assertFalse($new->hasHeader('Content-Length'));
+        $this->assertFalse($new->hasHeader('Content-Language'));
+        $this->assertFalse($new->hasHeader('Last-Modified'));
+
+        $this->assertSame('things', $new->getHeaderLine('X-things'), 'Other headers are retained');
+        $this->assertSame(304, $new->getStatusCode());
+        $this->assertSame('', $new->getBody()->getContents());
+    }
+
+    /**
      * Test checkNotModified method
      *
      * @return void