Skip to content

Commit

Permalink
Implementing sharable() and maxAge() in CakeResponse for a finer grai…
Browse files Browse the repository at this point in the history
…n and easier control of cache headers
  • Loading branch information
lorenzo committed Jan 19, 2012
1 parent 130b827 commit d9987c9
Show file tree
Hide file tree
Showing 2 changed files with 112 additions and 3 deletions.
81 changes: 78 additions & 3 deletions lib/Cake/Network/CakeResponse.php
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,14 @@ class CakeResponse {
*/
protected $_charset = 'UTF-8';

/**
* Holds all the cache directives that will be converted
* into headers when sending the request
*
* @var string
*/
protected $_cacheDirectives = array();

/**
* Class constructor
*
Expand Down Expand Up @@ -675,14 +683,81 @@ public function cache($since, $time = '+1 day') {
$time = strtotime($time);
}
$this->header(array(
'Date' => gmdate("D, j M Y G:i:s ", time()) . 'GMT',
'Cache-Control' => 'public, max-age=' . ($time - time()),
'Pragma' => 'cache'
'Date' => gmdate("D, j M Y G:i:s ", time()) . 'GMT'
));
$this->modified($since);
$this->expires($time);
$this->sharable(true);
$this->maxAge($time - time());
}

/**
* Sets whether a response is eligible to be cached by intermediate proxies
* This method controls the `public` or `private` directive in the Cache-Control
* header
*
* @param boolean $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
* if no value is provided, it will return whether the response is sharable or not
* @return boolean
*/
public function sharable($public = null) {
if ($public === null) {
$public = array_key_exists('public', $this->_cacheDirectives);
$private = array_key_exists('private', $this->_cacheDirectives);
$noCache = array_key_exists('no-cache', $this->_cacheDirectives);
if (!$public && !$private && !$noCache) {
return null;
}
$sharable = $public || ! ($private || $noCache);
return $sharable;
}
if ($public) {
$this->_cacheDirectives['public'] = null;
unset($this->_cacheDirectives['private']);
} else {
$this->_cacheDirectives['private'] = null;
unset($this->_cacheDirectives['public']);
}
$this->_setCacheControl();
return (bool) $public;
}

/**
* Sets the Cache-Control max-age directive.
* 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.
* If called with no parameters, this function will return the current max-age value if any
*
* @param int $seconds
* @return int
*/
public function maxAge($seconds = null) {
if ($seconds !== null) {
$this->_cacheDirectives['max-age'] = $seconds;
$this->_setCacheControl();
}
if (isset($this->_cacheDirectives['max-age'])) {
return $this->_cacheDirectives['max-age'];
}
return null;
}

/**
* Helper method to generate a valid Cache-Control header from the options set
* in other methods
*
* @return void
*/
protected function _setCacheControl() {
$control = '';
foreach ($this->_cacheDirectives as $key => $val) {
$control .= is_null($val) ? $key : sprintf('%s=%s', $key, $val);
$control .= ', ';
}
$control = rtrim($control, ', ');
$this->header('Cache-Control', $control);
}

/**
* Sets the Expires header for the response by taking an expiration time
Expand Down
34 changes: 34 additions & 0 deletions lib/Cake/Test/Case/Network/CakeResponseTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -635,4 +635,38 @@ public function testModified() {
->method('_sendHeader')->with('Last-Modified', $time->format('D, j M Y H:i:s') . ' GMT');
$response->send();
}

public function testSharable() {
$response = $this->getMock('CakeResponse', array('_sendHeader', '_sendContent'));
$this->assertNull($response->sharable());
$response->sharable(true);
$headers = $response->header();
$this->assertEquals('public', $headers['Cache-Control']);
$response->expects($this->at(1))
->method('_sendHeader')->with('Cache-Control', 'public');
$response->send();


$response = $this->getMock('CakeResponse', array('_sendHeader', '_sendContent'));
$response->sharable(false);
$headers = $response->header();
$this->assertEquals('private', $headers['Cache-Control']);
$response->expects($this->at(1))
->method('_sendHeader')->with('Cache-Control', 'private');
$response->send();

$response = $this->getMock('CakeResponse', array('_sendHeader', '_sendContent'));
$response->sharable(true);
$headers = $response->header();
$this->assertEquals('public', $headers['Cache-Control']);
$response->sharable(false);
$headers = $response->header();
$this->assertEquals('private', $headers['Cache-Control']);
$response->expects($this->at(1))
->method('_sendHeader')->with('Cache-Control', 'private');
$response->send();
$this->assertFalse($response->sharable());
$response->sharable(true);
$this->assertTrue($response->sharable());
}
}

0 comments on commit d9987c9

Please sign in to comment.