Skip to main content

Response Cache

The Response Cache is a server-side cache and enables request times similar to those of static server content.

Response Cache Control​

You can instruct n2n via ControllerAdapter::assignResponseCacheControl() to store the generated response for the current path in the Response Cache. On the next call of the same path (with the same subsystem and the same HTTP method) n2n reads this stored response directly from the cache and outputs it, without initializing any controllers, models, entities, etc. This considerably reduces the waiting time for the user.

class ExampleController extends ControllerAdapter {
public function doFoo() {
$this->assignResponseCacheControl(new \DateInterval('PT30M'));

$this->forward('view\bar.html');
}
}

assignResponseCacheControl() expects the interval after which the cached response has to be renewed as its first parameter. In the example above, the response for http://.../foo is cached for 30 minutes. The URL query is ignored. The same cached response is therefore also output when http://.../foo?param=bar is called.

If you want the URL query to be taken into account as well, you can pass true as second parameter. All query values that are passed as parameters to the current controller method are taken into account.

public function doFoo(ParamQuery $param = null) {
$this->assignResponseCacheControl(new \DateInterval('PT1M'), true);

$this->forward('view\bar.html');
}

In this example the responses for http://.../foo and http://.../foo?param=bar are now cached individually. However, the called URL must now exactly match the URL for which the response was cached in order for n2n to output the cached response. If you call doFoo() for example via http://.../foo?param=bar&param2=baz, a new version of the response for http://.../foo?param=bar is created with every call, overwriting the cached version, but it is never output, because the called URL is a different one.

Attention

A cache file is stored under var/tmp/n2n/responsecache for every cached response. Therefore it is important that you validate all parameters that are taken into account for the Response Cache. In the example above, an attacker could call doFoo() with an arbitrary parameter "param" and create a new cache file for every different value, thus filling up the server's storage space.

Response Cache Store​

Let's assume we have cached the response of a page that displays arbitrary data from a database. If this data changes, the changes only become visible when the cached response has to be renewed the next time. So that you don't have to wait, the ResponseCacheStore gives you the possibility to clear the Response Cache right after the data has changed. ResponseCacheStore is lookupable and can be passed to any magic method.

Such data could be articles, for example.

class BlogArticleDao implements RequestScoped {
private $em;
private $responseCacheStore;

private function _init(EntityManager $em, ResponseCacheStore $responseCacheStore) {
$this->em = $em;
$this->responseCacheStore = $responseCacheStore;
}

public function saveArticle(BlogArticle $article) {
$this->em->persist($article);
$this->responseCacheStore->clear();
}
}

In the example above we implemented a BlogArticleDao with a method saveArticle(), which persists an article. Right after the call of EntityManger::persist() we clear the entire Response Cache of your application via ResponseCacheStore::clear(). This means that all cached responses are deleted and regenerated the next time the respective page is called.

In most cases it makes more sense to trigger the clearing of the cache from lifecycle callbacks. This way you make sure that the cache is always cleared as soon as an entity object (record) has been changed - for example also when a user makes these changes via Rocket.

class BlogArticle extends ObjectAdapter {

// class body

private function _postPersist(ResponseCacheStore $responseCacheStore) {
$responseCacheStore->clear();
}

private function _postRemove(ResponseCacheStore $responseCacheStore) {
$responseCacheStore->clear();
}

private function _postUpdate(ResponseCacheStore $responseCacheStore) {
$responseCacheStore->clear();
}
}

In the example above the entire Response Cache is cleared as soon as an article has been persisted, deleted or changed.

So that you don't have to implement these three methods for all your entities, you can simply annotate the entity listener n2n/web/http/orm/ResponseCacheClearer instead.

class BlogArticle extends ObjectAdapter {
private static function _annos(AnnoInit $ai) {
$ai->c(new AnnoEntityListeners(ResponseCacheClearer::getClass()));

// further annotations
}

// rest of class body

}

In the example above, just like in the previous example, the entire Response Cache is cleared as soon as an article has been persisted, deleted or changed.

Characteristics​

In the previous section you were shown how to clear the entire Response Cache of your application. But the ResponseCacheStore also gives you the possibility to clear the Response Cache more selectively. For this, however, you have to categorize it first. The third parameter of ControllerAdapter::assignResponseCacheControl() allows you to do this, with which you can define so-called characteristics. A characteristic always consists of a key and a value.

public function doArticle(ArticleDao $articleDao, $id) {
$article = $articleDao->getArticleById($id);
if ($article === null) {
throw new PageNotFoundException();
}

$this->assignResponseCacheControl(new \DateInterval('P1D'), false,
array('type' => 'blogArticle', 'id' => $id));

$this->forward('view\article.html', array('article' => $article));
}

The controller method doArticle() in the example above generates the response for the article with the passed $id. This response is cached and tagged with the two characteristics "type" and "id". This allows us to identify this cached response in the Response Cache and delete it specifically via ResponseCacheStore::removeByCharacteristics() in case of any changes, without affecting the rest of the Response Cache.

$responseCacheStore->removeByCharacteristics(array('type' => 'blogArticle', 'id' => $id));

The method call above deletes the cached response of one article.

ResponseCacheStore::removeByCharacteristics() deletes the cached responses that were tagged with all passed characteristics. You could delete the cached responses of all articles with the following call:

$responseCacheStore->removeByCharacteristics(array('type' => 'blogArticle'));