HTTP Cache plugin

Guzzle can leverage HTTP's caching specifications using the Guzzle\Plugin\Cache\CachePlugin. The CachePlugin provides a private transparent proxy cache that caches HTTP responses. The caching logic, based on RFC 2616, uses HTTP headers to control caching behavior, cache lifetime, and supports Vary, ETag, and Last-Modified based revalidation:

use Guzzle\Http\Client;
use Doctrine\Common\Cache\FilesystemCache;
use Guzzle\Cache\DoctrineCacheAdapter;
use Guzzle\Plugin\Cache\CachePlugin;
use Guzzle\Plugin\Cache\DefaultCacheStorage;

$client = new Client('http://www.test.com/');

$cachePlugin = new CachePlugin(array(
    'storage' => new DefaultCacheStorage(
        new DoctrineCacheAdapter(
            new FilesystemCache('/path/to/cache/files')
        )
    )
));

// Add the cache plugin to the client object
$client->addSubscriber($cachePlugin);
$client->get('http://www.wikipedia.org/')->send();

// The next request will revalidate against the origin server to see if it
// has been modified. If a 304 response is received the response will be
// served from cache
$client->get('http://www.wikipedia.org/')->send();

The cache plugin intercepts GET and HEAD requests before they are actually transferred to the origin server. The cache plugin then generates a hash key based on the request method and URL, and checks to see if a response exists in the cache. If a response exists in the cache, the cache adapter then checks to make sure that the caching rules associated with the response satisfy the request, and ensures that response still fresh. If the response is acceptable for the request any required revalidation, then the cached response is served instead of contacting the origin server.

Vary

Cache keys are derived from a request method and a request URL. Multiple responses can map to the same cache key and stored in Guzzle's underlying cache storage object. You should use the Vary HTTP header to tell the cache storage object that the cache response must have been cached for a request that matches the headers specified in the Vary header of the request. This allows you to have specific cache entries for the same request URL but variations in a request's headers determine which cache entry is served. Please see the http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.44 for more information.

Cache options

There are several options you can add to requests or clients to modify the behavior of the cache plugin.

Override cache TTL

You can override the number of seconds a cacheable response is stored in the cache by setting the cache.override_ttl parameter on the params object of a request:

// If the response to the request is cacheable, then the response will be cached for 100 seconds
$request->getParams()->set('cache.override_ttl', 100);

If a response doesn't specify any freshness policy, it will be kept in cache for 3600 seconds by default.

Custom caching decision

If the service you are interacting with does not return caching headers or returns responses that are normally something that would not be cached, you can set a custom can_cache object on the constructor of the CachePlugin and provide a Guzzle\Plugin\Cache\CanCacheInterface object. You can use the Guzzle\Plugin\Cache\CallbackCanCacheStrategy to easily make a caching decision based on an HTTP request and response.

Revalidation options

You can change the revalidation behavior of a request using the cache.revalidate parameter. Setting this parameter to never will ensure that a revalidation request is never sent, and the response is always served from the origin server. Setting this parameter to skip will never revalidate and uses the response stored in the cache.

Normalizing requests for caching

Use the cache.key_filter parameter if you wish to strip certain query string parameters from your request before creating a unique hash for the request. This parameter can be useful if your requests have query string values that cause each request URL to be unique (thus preventing a cache hit). The cache.key_filter format is simply a comma separated list of query string values to remove from the URL when creating a cache key. For example, here we are saying that the a and q query string variables should be ignored when generating a cache key for the request:

$request->getParams()->set('cache.key_filter', 'a, q');

Other options

There are many other options available to the CachePlugin that can meet almost any caching requirement, including custom revalidation implementations, custom cache key generators, custom caching decision strategies, and custom cache storage objects. Take a look the constructor of Guzzle\Plugin\Cache\CachePlugin for more information.

Setting Client-wide cache settings

You can specify cache settings for every request created by a client by adding cache settings to the configuration options of a client.

$client = new Guzzle\Http\Client('http://www.test.com', array(
    'request.params' => array(
        'cache.override_ttl' => 3600,
        'params.cache.revalidate' => 'never'
    )
));

echo $client->get('/')->getParams()->get('cache.override_ttl');
// >>> 3600

echo $client->get('/')->getParams()->get('cache.revalidate');
// >>> never

Cache revalidation

If the cache plugin determines that a response to a GET request needs revalidation, a conditional GET is transferred to the origin server. If the origin server returns a 304 response, then a response containing the merged headers of the cached response with the new response and the entity body of the cached response is returned. Custom revalidation strategies can be injected into a CachePlugin if needed.

Cache adapters

Guzzle doesn't try to reinvent the wheel when it comes to caching or logging. Plenty of other frameworks have excellent solutions in place that you are probably already using in your applications. Guzzle uses adapters for caching and logging. The cache plugin requires a cache adapter so that is can store responses in a cache. Guzzle currently supports cache adapters for Doctrine 2.0 and the Zend Framework.

Doctrine cache adapter

use Doctrine\Common\Cache\ArrayCache;
use Guzzle\Cache\DoctrineCacheAdapter;
use Guzzle\Plugin\Cache\CachePlugin;

$backend = new ArrayCache();
$adapter = new DoctrineCacheAdapter($backend);
$cache = new CachePlugin($adapter);

Zend Framework cache adapter

use Guzzle\Cache\ZendCacheAdapter;
use Zend\Cache\Backend\TestBackend;

$backend = new TestBackend();
$adapter = new ZendCacheAdapter($backend);
$cache = new CachePlugin($adapter);
comments powered by Disqus