Almost two years ago I've written about some tips on caching in Neos CMS. At that time I thought I fully understood how caching in Fusion had worked, but how wrong I had been!

Uncached Depends on Context

mode = 'uncached' seems like the most straightforward way of caching… You just don’t cache a certain part of the page and that’s all. But there’s a huge gotcha!

Take this as an example. I’ve lately been working on a newsletter package. It generates some letters and sends them out to all subscribers. 99% of the letter is the same for all users, but for one important thing – an unsubscribe link! So I want to cache the whole generated letter, so it would be rendered only once for all users, but the unsubscribe link should not be cached. Let’s try to configure caches for such situation:

newsletter = TYPO3.TypoScript:Array {
  content = 'some newsletter content'
  unsbscribeLink = NodeUri 
    node = ${documentNode}
    additionalParams.subscriber = ${subscriber}
    @cache {
      mode = 'uncached'
      context {
        documentNode = 'documentNode'
        subscriber = 'subscriber'
      }
    }
  }
  @cache {
    mode = 'cached'
  }
}

In subscriber context variable we have data for the current subscriber to whom this letter is being sent, the rest should be self-explanatory.

But wait a minute, we get the same unsubscribe link generated for all subscribers (imagine the consequences…), why?!?

Simple! The mode uncached makes the code of that object to be re-evaluated on each execution, BUT it stores the context inside the cache entry, so the object gets re-evaluated always with the same context! That is super dangerous if you are unaware of this behaviour!

Moral of this is simple: do not rely on context to receive data in uncached segments that you don’t want to get cached by the parent cached entries. You have to get your data into the uncached segment in some other way, without using the context. E.g. I used my registry package to overcome this limitation in the newsletter package.

Many Things may Break Your Cache

Neos inserts invisible Unicode markers to mark cached fragments, which later are removed when rendering. Unfortunately some functions like json_encode when applied to your content break those markers.

Here’s the demonstration:

root = TYPO3.TypoScript:Value {
  value = TYPO3.TypoScript:Value {
    value = 'hey' {
      @cache {
        mode = 'cached'
      }
    }
  }
  @process.json = ${Json.stringify(value)}
}

Which would output:

"\u0002584e9a8950d9142e744c1afa08c0b0d8d349f08ce9b44\u001f584e9a8950d91
Everything\u001f584e9a8950d91hey\u0003584e9a8950d91"

If you wanted to fix it, you could move the cache entry to the root of the object or use something else instead of json_encode for serialisation, e.g. serialize.

Caching RawArray and other Non-String Data

You can’t cache objects that return anything other than strings, e.g. RawArray or FlowQuery results. But, you can very well cache stuff that is inside of RawArrays. E.g. this works:

root = TYPO3.TypoScript:RawArray {
  1 = TYPO3.TypoScript:Value {
    value = 'hi!'
    @cache {
      mode = 'cached'
    }
  }
}

Conslusion

Now I again have the deceptive feeling restored that I do understand Fusion caching :-) Let’s see what will prove me wrong next time!

Did this article tell you anything new about caching in Neos?