Skip to content

Commit 3530c26

Browse files
committed
addTags on TagHandler
1 parent b8cbdbf commit 3530c26

File tree

4 files changed

+121
-9
lines changed

4 files changed

+121
-9
lines changed

doc/invalidation-handlers.rst

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,15 @@ to simplify common operations.
99
Tag Handler
1010
-----------
1111

12-
The tag handler helps you to invalidate all cache entries that where marked
13-
with a specified tag. It works only with a ``CacheInvalidator`` that supports
14-
``CacheInvalidator::INVALIDATE``.
12+
.. versionadded:: 1.3
13+
14+
The tag handler was added in FOSHttpCache 1.3. If you are using an older
15+
version of the library and can not update, you need to use
16+
``CacheInvalidator::invalidateTags``.
17+
18+
The tag handler helps you to mark responses with tags that you can later use to
19+
invalidate all cache entries with that tag. Tag invalidation works only with a
20+
``CacheInvalidator`` that supports ``CacheInvalidator::INVALIDATE``.
1521

1622
Setup
1723
~~~~~
@@ -34,8 +40,22 @@ Usage
3440

3541
With tags you can group related representations so it becomes easier to
3642
invalidate them. You will have to make sure your web application adds the
37-
correct tags on all responses by setting the ``X-Cache-Tags`` header. The
38-
FOSHttpCacheBundle_ does this for you when you’re using Symfony.
43+
correct tags on all responses. You can add tags to the handler using::
44+
45+
$tagHandler->addTags(array('tag-two', 'group-a'));
46+
47+
Before any content is sent out, you need to send the tag header_::
48+
49+
header(sprintf('%s: %s),
50+
$tagHandler->getTagsHeaderName(),
51+
$tagHandler->getTagsHeaderValue()
52+
);
53+
54+
.. tip::
55+
56+
If you are using Symfony with the FOSHttpCacheBundle_, the tag header is
57+
set automatically. You also have `additional methods of defining tags`_ with
58+
annotations and on URL patterns.
3959

4060
Assume you sent four responses:
4161

@@ -74,3 +94,6 @@ header ``X-Cache-Tags`` in the constructor::
7494

7595
Make sure to reflect this change in your
7696
:doc:`caching proxy configuration <proxy-configuration>`.
97+
98+
.. _header: http://php.net/header
99+
.. _additional methods of defining tags: http://foshttpcachebundle.readthedocs.org/en/latest/features/tagging.html

src/CacheInvalidator.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ public function addSubscriber(EventSubscriberInterface $subscriber)
160160
*/
161161
public function setTagsHeader($tagsHeader)
162162
{
163-
if ($this->tagHandler && $this->tagsHeader !== $tagsHeader) {
163+
if ($this->tagHandler && $this->tagHandler->getTagsHeaderName() !== $tagsHeader) {
164164
$this->tagHandler = new TagHandler($this, $tagsHeader);
165165
}
166166

@@ -172,11 +172,11 @@ public function setTagsHeader($tagsHeader)
172172
*
173173
* @return string
174174
*
175-
* @deprecated Use TagHandler::getTagsHeader instead.
175+
* @deprecated Use TagHandler::getTagsHeaderName instead.
176176
*/
177177
public function getTagsHeader()
178178
{
179-
return $this->tagsHeader;
179+
return $this->tagHandler ? $this->tagHandler->getTagsHeaderName() : $this->tagsHeader;
180180
}
181181

182182
/**

src/Handler/TagHandler.php

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,11 @@ class TagHandler
3232
*/
3333
private $tagsHeader;
3434

35+
/**
36+
* @var array
37+
*/
38+
private $tags = array();
39+
3540
/**
3641
* Constructor
3742
*
@@ -49,6 +54,40 @@ public function __construct(CacheInvalidator $invalidator, $tagsHeader = 'X-Cach
4954
$this->tagsHeader = $tagsHeader;
5055
}
5156

57+
/**
58+
* Get the HTTP header name that will hold cache tags.
59+
*
60+
* @return string
61+
*/
62+
public function getTagsHeaderName()
63+
{
64+
return $this->tagsHeader;
65+
}
66+
67+
/**
68+
* Get the value for the HTTP tag header.
69+
*
70+
* This concatenates all tags and ensures correct encoding.
71+
*
72+
* @return string
73+
*/
74+
public function getTagsHeaderValue()
75+
{
76+
return implode(',', array_unique($this->escapeTags($this->tags)));
77+
}
78+
79+
/**
80+
* Add tags to be sent.
81+
*
82+
* This must be called before any response is sent to the client.
83+
*
84+
* @param array $tags List of tags to add.
85+
*/
86+
public function addTags(array $tags)
87+
{
88+
$this->tags = array_merge($this->tags, $tags);
89+
}
90+
5291
/**
5392
* Invalidate cache entries that contain any of the specified tags in their
5493
* tag header.
@@ -59,10 +98,26 @@ public function __construct(CacheInvalidator $invalidator, $tagsHeader = 'X-Cach
5998
*/
6099
public function invalidateTags(array $tags)
61100
{
62-
$tagExpression = sprintf('(%s)(,.+)?$', implode('|', array_map('preg_quote', $tags)));
101+
$tagExpression = sprintf('(%s)(,.+)?$', implode('|', array_map('preg_quote', $this->escapeTags($tags))));
63102
$headers = array($this->tagsHeader => $tagExpression);
64103
$this->invalidator->invalidate($headers);
65104

66105
return $this;
67106
}
107+
108+
/**
109+
* Make sure that the tags are valid.
110+
*
111+
* @param array $tags The tags to escape.
112+
*
113+
* @return array Sane tags.
114+
*/
115+
protected function escapeTags(array $tags)
116+
{
117+
array_walk($tags, function (&$tag) {
118+
$tag = str_replace(array(',', "\n"), array('_', '_'), $tag);
119+
});
120+
121+
return $tags;
122+
}
68123
}

tests/Unit/Handler/TagHandlerTest.php

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,22 @@ public function testInvalidateTagsCustomHeader()
4848
$tagHandler->invalidateTags(array('post-1'));
4949
}
5050

51+
public function testEscapingTags()
52+
{
53+
$cacheInvalidator = \Mockery::mock('FOS\HttpCache\CacheInvalidator')
54+
->shouldReceive('invalidate')
55+
->with(array('X-Cache-Tags' => '(post_test)(,.+)?$'))
56+
->once()
57+
->shouldReceive('supports')
58+
->with(CacheInvalidator::INVALIDATE)
59+
->once()
60+
->andReturn(true)
61+
->getMock();
62+
63+
$tagHandler = new TagHandler($cacheInvalidator);
64+
$tagHandler->invalidateTags(array('post,test'));
65+
}
66+
5167
/**
5268
* @expectedException \FOS\HttpCache\Exception\UnsupportedProxyOperationException
5369
*/
@@ -62,4 +78,22 @@ public function testInvalidateUnsupported()
6278

6379
new TagHandler($cacheInvalidator);
6480
}
81+
82+
/**
83+
* @runInSeparateProcess
84+
*/
85+
public function testTagResponse()
86+
{
87+
$cacheInvalidator = \Mockery::mock('FOS\HttpCache\CacheInvalidator')
88+
->shouldReceive('supports')
89+
->with(CacheInvalidator::INVALIDATE)
90+
->once()
91+
->andReturn(true)
92+
->getMock();
93+
94+
$tagHandler = new TagHandler($cacheInvalidator);
95+
$tagHandler->addTags(array('post-1', 'test,post'));
96+
$tagHandler->flushTags();
97+
// it seems on cli we can not investigate the headers_list
98+
}
6599
}

0 commit comments

Comments
 (0)