Skip to content

Commit 6709f53

Browse files
committed
Improve Cache-Control header handling
1 parent e222332 commit 6709f53

4 files changed

Lines changed: 73 additions & 5 deletions

File tree

src/Cache.php

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,13 @@ public function __invoke(RequestInterface $request, ResponseInterface $response,
4848
$response = $next($request, $response);
4949

5050
// Cache-Control header
51-
$response = $response->withHeader('Cache-Control', sprintf(
52-
'%s, max-age=%s',
53-
$this->type,
54-
$this->maxAge
55-
));
51+
if (!$response->hasHeader('Cache-Control')) {
52+
$response = $response->withHeader('Cache-Control', sprintf(
53+
'%s, max-age=%s',
54+
$this->type,
55+
$this->maxAge
56+
));
57+
}
5658

5759
// Last-Modified header and conditional GET check
5860
$lastModified = $response->getHeader('Last-Modified');

src/CacheProvider.php

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,43 @@ public function register(Container $container)
1717
$container['cache'] = $this;
1818
}
1919

20+
/**
21+
* Enable client-side HTTP caching
22+
*
23+
* @param ResponseInterface $response PSR7 response object
24+
* @param string $type Cache-Control type: "private" or "public"
25+
* @param null|int|string $maxAge Maximum cache age (integer timestamp or datetime string)
26+
*
27+
* @return ResponseInterface A new PSR7 response object with `Cache-Control` header
28+
*/
29+
public function allowCache(ResponseInterface $response, $type = 'private', $maxAge = null)
30+
{
31+
if (!in_array($type, ['private', 'public'])) {
32+
throw new \InvalidArgumentException('Invalid Cache-Control type. Must be "public" or "private".');
33+
}
34+
$headerValue = $type;
35+
if ($maxAge) {
36+
if (!is_integer($maxAge)) {
37+
$maxAge = strtotime($maxAge);
38+
}
39+
$headerValue = $headerValue . ', max-age=' . $maxAge;
40+
}
41+
42+
return $response->withHeader('Cache-Control', $headerValue);
43+
}
44+
45+
/**
46+
* Disable client-side HTTP caching
47+
*
48+
* @param ResponseInterface $response PSR7 response object
49+
*
50+
* @return ResponseInterface A new PSR7 response object with `Cache-Control` header
51+
*/
52+
public function denyCache(ResponseInterface $response)
53+
{
54+
return $response->withHeader('Cache-Control', 'no-store,no-cache');
55+
}
56+
2057
/**
2158
* Add `Expires` header to PSR7 response object
2259
*

tests/CacheProviderTest.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,22 @@
66

77
class CacheProviderTest extends \PHPUnit_Framework_TestCase
88
{
9+
public function testAllowCache()
10+
{
11+
$cacheProvider = new CacheProvider();
12+
$res = $cacheProvider->allowCache(new Response(), 'private', 43200);
13+
14+
$this->assertEquals('private, max-age=43200', $res->getHeader('Cache-Control'));
15+
}
16+
17+
public function testDenyCache()
18+
{
19+
$cacheProvider = new CacheProvider();
20+
$res = $cacheProvider->denyCache(new Response());
21+
22+
$this->assertEquals('no-store,no-cache', $res->getHeader('Cache-Control'));
23+
}
24+
925
public function testWithExpires()
1026
{
1127
$now = time();

tests/CacheTest.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,19 @@ public function testCacheControlHeader()
3535
$this->assertEquals('public, max-age=86400', $res->getHeader('Cache-Control'));
3636
}
3737

38+
public function testCacheControlHeaderDoesNotOverrideExistingHeader()
39+
{
40+
$cache = new Cache('public', 86400);
41+
$req = $this->requestFactory();
42+
$res = new Response();
43+
$next = function (Request $req, Response $res) {
44+
return $res->withHeader('Cache-Control', 'no-cache,no-store');
45+
};
46+
$res = $cache($req, $res, $next);
47+
48+
$this->assertEquals('no-cache,no-store', $res->getHeader('Cache-Control'));
49+
}
50+
3851
public function testLastModifiedWithCacheHit()
3952
{
4053
$now = time();

0 commit comments

Comments
 (0)