Skip to content

Commit 2dfdbc7

Browse files
committed
cleanup documentation for tag formatter
1 parent 3a912ac commit 2dfdbc7

File tree

10 files changed

+97
-62
lines changed

10 files changed

+97
-62
lines changed

CHANGELOG.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,8 @@ See also the [GitHub releases page](https://github.com/FriendsOfSymfony/FOSHttpC
4040
* Abstracting tags by adding new `TagCapable` for ProxyClients.
4141
* Added `strict` option to `ResponseTagger` that throws an exception when empty
4242
tags are added. By default, empty tags are ignored.
43-
* Added a `TagHeaderFormatter` interface that is used within the `ResponseTagger`
44-
to provide the header name and the formatted tags header value.
43+
* Added `TagHeaderFormatter` interface that is used within the `ResponseTagger`
44+
to provide the header name and for formatting the tags header value.
4545

4646
### Varnish
4747

@@ -82,10 +82,10 @@ See also the [GitHub releases page](https://github.com/FriendsOfSymfony/FOSHttpC
8282
2.0.0-beta3
8383
-----------
8484

85-
* **BC break:** The `ResponseTagger` now expects an instance of
86-
`TagHeaderFormatter` instead of `TagCapable` as first argument.
87-
* **BC break:** The constant `Varnish::DEFAULT_HTTP_HEADER_CACHE_TAGS` has been
88-
moved to ``TagHeaderFormatter::DEFAULT_HEADER_NAME``.
85+
* **BC break:** The `ResponseTagger` no longer expects an instance of
86+
`TagCapable` as first argument. To adjust the tag header name or the way the
87+
tags are formatted, use the new `header_formatter` option with a
88+
`TagHeaderFormatter`.
8989

9090
1.4.2
9191
-----

doc/proxy-clients.rst

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -94,15 +94,14 @@ dispatcher as explained above and pass it to the Varnish client::
9494

9595
You can also pass some options to the Varnish client:
9696

97-
* ``tags_header`` (default: ``X-Cache-Tags``): Allows you to change the HTTP header
98-
used for purge and ban requests. It is **NOT** related to response tagging! It
99-
is possible to use different header names for both, the tagging process and the
100-
ban/purge requests. If you change this, make sure to use the correct header name
101-
in your :doc:`proxy server configuration <proxy-configuration>`;
102-
* ``header_length`` (7500): Control the maximum header size when invalidating
97+
* ``tags_header`` (default: ``X-Cache-Tags``): The HTTP header used to specify
98+
which tags to invalidate when sending invalidation requests to the caching
99+
proxy. Make sure that your :ref:`Varnish configuration <varnish_tagging>`
100+
corresponds to the header used here;
101+
* ``header_length`` (default: 7500): Control the maximum header size when invalidating
103102
tags. If there are more tags to invalidate than fit into the header, the
104103
invalidation request is split into several requests;
105-
* ``default_ban_headers`` Map of headers that are set on each ban request,
104+
* ``default_ban_headers`` (default: []): Map of headers that are set on each ban request,
106105
merged with the built-in headers.
107106

108107
Additionally, you can specify the request factory used to build the

doc/response-tagging.rst

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
Response Tagging
22
================
33

4-
The ``ResponseTagger`` helps you keep track tags for a response, which can be
5-
added to response headers that you can later use to invalidate all cache
4+
The ``ResponseTagger`` helps you keep track of tags for a response. It can add
5+
the tags as a response header that you can later use to invalidate all cache
66
entries with that tag.
77

88
.. _tags:
@@ -12,30 +12,40 @@ Setup
1212

1313
.. note::
1414

15-
Make sure to :doc:`configure your proxy <proxy-configuration>` for tagging first.
15+
Make sure to :doc:`configure your proxy <proxy-configuration>` for tagging
16+
first.
1617

17-
The response tagger takes an instance of ``TagHeaderFormatter`` as first
18-
argument which is responsible for providing the header name as well as formatting
19-
the provided tags into a proper header value. This library ships with a
20-
``CommaSeparatedTagHeaderFormatter`` which simply turns an array of tags into a
21-
comma-separated list. If you need a different behavior, provide your own implementation
22-
of the `TagHeaderFormatter`` interface.
23-
Just note: It's your responsibility to make sure, your proxy configuration matches
24-
the configuration of the ``ResponseTagger``::
18+
The response tagger uses an instance of ``TagHeaderFormatter`` to know the
19+
header name used to mark tags on the content and to format the tags into the
20+
correct header value. This library ships with a
21+
``CommaSeparatedTagHeaderFormatter`` that formats an array of tags into a
22+
comma-separated list. This format is expected for invalidation with the
23+
Varnish reverse proxy. When using the default settings, everything is created
24+
automatically and the ``X-Cache-Tags`` header will be used::
2525

2626
use FOS\HttpCache\ResponseTagger;
27-
use FOS\HttpCache\TagHeaderFormatter;
2827

29-
$tagHeaderFormatter = new CommaSeparatedTagHeaderFormatter('Header-Name');
30-
$responseTagger = new ResponseTagger($tagHeaderFormatter);
28+
$responseTagger = new ResponseTagger();
3129

3230
.. _response_tagger_optional_parameters:
3331

32+
If you need a different behavior, you can provide your own implementation of
33+
the ``TagHeaderFormatter`` interface. But be aware that your
34+
:ref:`Varnish configuration <varnish_tagging>` has to match with the tag on the response.
35+
For example, to use a different header name::
36+
37+
use FOS\HttpCache\ResponseTagger;
38+
use FOS\HttpCache\TagHeaderFormatter;
39+
40+
$formatter = new CommaSeparatedTagHeaderFormatter('Custom-Header-Name');
41+
$responseTagger = new ResponseTagger(['header_formatter' => $formatter]);
42+
3443
The response tagger validates tags that you set. By default, it simply ignores
35-
empty strings. You can set the response tagger to strict mode to have it throw
36-
an ``InvalidTagException`` on empty tags::
44+
empty strings and does not add them to the list of tags. You can set the
45+
response tagger to strict mode to have it throw an ``InvalidTagException`` on
46+
empty tags::
3747

38-
$responseTagger = new ResponseTagger($proxyClient, ['strict' => true]);
48+
$responseTagger = new ResponseTagger(['strict' => true]);
3949

4050
Usage
4151
~~~~~

doc/varnish-configuration.rst

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -175,31 +175,33 @@ Tagging
175175
Feature: :ref:`cache tagging <tags>`
176176

177177
If you have included ``fos_ban.vcl``, tagging will be automatically enabled
178-
using an ``X-Cache-Tags`` header.
178+
with the ``X-Cache-Tags`` header for both marking the tags on the response and
179+
for the invalidation request to tell what tags to invalidate.
179180

180-
If you need to use a different tag for the headers than the default
181-
``X-Cache-Tags`` used in ``fos_ban.vcl``, you will have to write your own VCL
182-
code for tag invalidation and change the tagging header
183-
:ref:`configured in the cache invalidator <varnish_custom_tags_header>`. Your custom
184-
VCL will look like this:
181+
If you use a different name for :doc:`response tagging <response-tagging>` than
182+
the default ``X-Cache-Tags`` or a different name for specifying which tags to
183+
invalidate in your :ref:`cache invalidator configuration <varnish_custom_tags_header>`
184+
you have to write your own VCL code for tag invalidation. Your custom VCL will
185+
look like this:
185186

186187
.. configuration-block::
187188

188189
.. literalinclude:: ../resources/config/varnish/fos_ban.vcl
189190
:language: varnish
190-
:emphasize-lines: 17-22,49-50
191+
:emphasize-lines: 17-23,50-51
191192
:linenos:
192193

193194
.. literalinclude:: ../resources/config/varnish-3/fos_ban.vcl
194195
:language: varnish3
195-
:emphasize-lines: 17-22,49-50
196+
:emphasize-lines: 17-23,50-51
196197
:linenos:
197198

198-
.. warning::
199+
.. hint::
199200

200-
Note that by default, both, the header name for tagging using the response
201-
tagger and the header name for Varnish's purge and ban requests are named
202-
``X-Cache-Tags``. You may, however, have different header names.
201+
The line you need to adjust from the code above is line 21. The left side
202+
is the header used to tag the response, the right side is the header used
203+
when sending invalidation requests. If you change one or the other header
204+
name, make sure to adjust the configuration accordingly.
203205

204206
.. _varnish user context:
205207

resources/config/varnish-3/fos_ban.vcl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ sub fos_ban_recv {
1818
ban("obj.http.X-Host ~ " + req.http.X-Host
1919
+ " && obj.http.X-Url ~ " + req.http.X-Url
2020
+ " && obj.http.content-type ~ " + req.http.X-Content-Type
21+
// the left side is the response header, the right side the invalidation header
2122
+ " && obj.http.X-Cache-Tags ~ " + req.http.X-Cache-Tags
2223
);
2324
} else {

resources/config/varnish/fos_ban.vcl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ sub fos_ban_recv {
1818
ban("obj.http.X-Host ~ " + req.http.X-Host
1919
+ " && obj.http.X-Url ~ " + req.http.X-Url
2020
+ " && obj.http.content-type ~ " + req.http.X-Content-Type
21+
// the left side is the response header, the right side the invalidation header
2122
+ " && obj.http.X-Cache-Tags ~ " + req.http.X-Cache-Tags
2223
);
2324
} else {

src/ProxyClient/Varnish.php

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
use FOS\HttpCache\ProxyClient\Invalidation\PurgeCapable;
1717
use FOS\HttpCache\ProxyClient\Invalidation\RefreshCapable;
1818
use FOS\HttpCache\ProxyClient\Invalidation\TagCapable;
19-
use FOS\HttpCache\TagHeaderFormatter\TagHeaderFormatter;
2019

2120
/**
2221
* Varnish HTTP cache invalidator.
@@ -38,6 +37,16 @@ class Varnish extends HttpProxyClient implements BanCapable, PurgeCapable, Refre
3837
const HTTP_HEADER_URL = 'X-Url';
3938
const HTTP_HEADER_CONTENT_TYPE = 'X-Content-Type';
4039

40+
/**
41+
* Default name of the header used to invalidate content with specific tags.
42+
*
43+
* This happens to be the same as TagHeaderFormatter::DEFAULT_HEADER_NAME
44+
* but does not technically need to be the same.
45+
*
46+
* @var string
47+
*/
48+
const DEFAULT_HTTP_HEADER_CACHE_TAGS = 'X-Cache-Tags';
49+
4150
/**
4251
* {@inheritdoc}
4352
*/
@@ -133,7 +142,7 @@ protected function configureOptions()
133142
{
134143
$resolver = parent::configureOptions();
135144
$resolver->setDefaults([
136-
'tags_header' => TagHeaderFormatter::DEFAULT_HEADER_NAME,
145+
'tags_header' => self::DEFAULT_HTTP_HEADER_CACHE_TAGS,
137146
'header_length' => 7500,
138147
'default_ban_headers' => [],
139148
]);

src/ResponseTagger.php

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,10 @@
1212
namespace FOS\HttpCache;
1313

1414
use FOS\HttpCache\Exception\InvalidTagException;
15+
use FOS\HttpCache\TagHeaderFormatter\CommaSeparatedTagHeaderFormatter;
1516
use FOS\HttpCache\TagHeaderFormatter\TagHeaderFormatter;
1617
use Psr\Http\Message\ResponseInterface;
18+
use Symfony\Component\OptionsResolver\Options;
1719
use Symfony\Component\OptionsResolver\OptionsResolver;
1820

1921
/**
@@ -43,27 +45,31 @@ class ResponseTagger
4345
private $tags = [];
4446

4547
/**
46-
* Create the response tagger with a tag capable proxy client and options.
48+
* Create the response tagger with a tag header formatter and options.
4749
*
4850
* Supported options are:
4951
*
52+
* - header_formatter (TagHeaderFormatter) Default: CommaSeparatedTagHeaderFormatter with default header name
5053
* - strict (bool) Default: false. If set to true, throws exception when adding empty tags
5154
*
52-
* @param TagHeaderFormatter $headerFormatter
53-
* @param array $options
55+
* @param array $options
5456
*/
55-
public function __construct(TagHeaderFormatter $headerFormatter, array $options = [])
57+
public function __construct(array $options = [])
5658
{
57-
$this->headerFormatter = $headerFormatter;
58-
5959
$resolver = new OptionsResolver();
6060
$resolver->setDefaults([
61+
// callback to avoid instantiating the formatter when its not needed
62+
'header_formatter' => function (Options $options) {
63+
return new CommaSeparatedTagHeaderFormatter();
64+
},
6165
'strict' => false,
6266
]);
6367

68+
$resolver->setAllowedTypes('header_formatter', TagHeaderFormatter::class);
6469
$resolver->setAllowedTypes('strict', 'bool');
6570

6671
$this->options = $resolver->resolve($options);
72+
$this->headerFormatter = $this->options['header_formatter'];
6773
}
6874

6975
/**

src/TagHeaderFormatter/TagHeaderFormatter.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,11 @@
1818
*/
1919
interface TagHeaderFormatter
2020
{
21+
/**
22+
* Default name of the header to mark tags on responses.
23+
*
24+
* @var string
25+
*/
2126
const DEFAULT_HEADER_NAME = 'X-Cache-Tags';
2227

2328
/**

tests/Unit/ResponseTaggerTest.php

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,12 @@
1919

2020
class ResponseTaggerTest extends \PHPUnit_Framework_TestCase
2121
{
22+
public function testDefaultFormatter()
23+
{
24+
$tagger = new ResponseTagger();
25+
$this->assertEquals('X-Cache-Tags', $tagger->getTagsHeaderName());
26+
}
27+
2228
public function testGetTagsHeaderValue()
2329
{
2430
$headerFormatter = \Mockery::mock(TagHeaderFormatter::class)
@@ -28,7 +34,7 @@ public function testGetTagsHeaderValue()
2834
->andReturn('post-1,test_post')
2935
->getMock();
3036

31-
$tagger = new ResponseTagger($headerFormatter);
37+
$tagger = new ResponseTagger(['header_formatter' => $headerFormatter]);
3238
$this->assertFalse($tagger->hasTags());
3339
$tagger->addTags(['post-1', 'test,post']);
3440
$this->assertTrue($tagger->hasTags());
@@ -47,7 +53,7 @@ public function testTagResponseReplace()
4753
->andReturn('FOS-Tags')
4854
->getMock();
4955

50-
$tagger = new ResponseTagger($headerFormatter);
56+
$tagger = new ResponseTagger(['header_formatter' => $headerFormatter]);
5157

5258
$response = \Mockery::mock(ResponseInterface::class)
5359
->shouldReceive('withHeader')
@@ -70,7 +76,7 @@ public function testTagResponseAdd()
7076
->andReturn('FOS-Tags')
7177
->getMock();
7278

73-
$tagger = new ResponseTagger($headerFormatter);
79+
$tagger = new ResponseTagger(['header_formatter' => $headerFormatter]);
7480

7581
$response = \Mockery::mock(ResponseInterface::class)
7682
->shouldReceive('withAddedHeader')
@@ -88,7 +94,7 @@ public function testTagResponseNoTags()
8894
->shouldReceive('getTagsHeaderValue')->never()
8995
->getMock();
9096

91-
$tagger = new ResponseTagger($headerFormatter);
97+
$tagger = new ResponseTagger(['header_formatter' => $headerFormatter]);
9298

9399
$response = \Mockery::mock(ResponseInterface::class)
94100
->shouldReceive('withHeader')->never()
@@ -102,14 +108,10 @@ public function testStrictEmptyTag()
102108
{
103109
$headerFormatter = new CommaSeparatedTagHeaderFormatter('FOS-Tags');
104110

105-
$tagHandler = new ResponseTagger($headerFormatter, ['strict' => true]);
111+
$tagHandler = new ResponseTagger(['header_formatter' => $headerFormatter, 'strict' => true]);
106112

107-
try {
108-
$tagHandler->addTags(['post-1', false]);
109-
$this->fail('Expected exception');
110-
} catch (InvalidTagException $e) {
111-
// success
112-
}
113+
$this->setExpectedException(InvalidTagException::class);
114+
$tagHandler->addTags(['post-1', false]);
113115
}
114116

115117
public function testNonStrictEmptyTag()
@@ -121,7 +123,7 @@ public function testNonStrictEmptyTag()
121123
->andReturn('post-1')
122124
->getMock();
123125

124-
$tagHandler = new ResponseTagger($headerFormatter);
126+
$tagHandler = new ResponseTagger(['header_formatter' => $headerFormatter]);
125127
$tagHandler->addTags(['post-1', false, null, '']);
126128
$this->assertTrue($tagHandler->hasTags());
127129
$this->assertEquals('post-1', $tagHandler->getTagsHeaderValue());

0 commit comments

Comments
 (0)