In working heavily with render arrays I have been leveraging the built in cache mechanisms along with the current pre_render and post_render functions.

However, it appears that while the caching mechanism works well it assumes there is no further post processing of the markup i.e. at first I assumed that post_render would apply after a cache hit or set instead of the current implementation which is only just prior to a cache set.

While this is an okay assumption on the surface if caching is used extensively this may result in caching of similar or largely similar render arrays for little cost benefit.

e.g. assume I have a table of membership plans and my application accepts multiple currencies and the amounts of those memberships vary by country.

Option 1 (Today):
- Render all possible membership currency and amount permutations and caching will occur for each. If I support 8 countries then I will 8 render arrays just for this table.

Option 2 (Proposed):
- Render a single table with tokens for membership currency and amounts and caching will occur for 1 render array regardless of how many countries I support.
- In drupal_render upon a cache miss call a 'post_cache' function (if set) giving the application a chance to modify the render array markup tokens with data
- In drupal_render upon a cache hit call a 'post_cache' function (if set) giving the application a chance to modify the render array markup tokens with data

This approach attempts to balance some additional on-the-fly post processing vs. caching a potentially large number of render arrays.

From a code perspective this can be achieved with ZERO impact to existing functionality and virtually no impact to the existing drupal_render function. The precise overhead would be an additional isset() test on a cache hit and a cache save. Seeing that caching is either going to the DB, Memcache or something else across some interface the additional overhead of a isset() call is very low.

Here is what I propose in drupal_render:

  // Try to fetch the element's markup from cache and return.
  if (isset($elements['#cache'])) {
    $cached_output = drupal_render_cache_get($elements);
    if ($cached_output !== FALSE) {
      // ************** START NEW ***************************
      if (isset($elements['#cache']['post_cache'])) {
        $cached_output = $elements['#cache']['post_cache']($cached_output);
      }
      // ************** END NEW ***************************
      return $cached_output;
    }
  }

and

  // Cache the processed element if #cache is set.
  if (isset($elements['#cache'])) {
    drupal_render_cache_set($output, $elements);
    // ************** START NEW ***************************
    if (isset($elements['#cache']['post_cache'])) {
      $output = $elements['#cache']['post_cache']($output);
    }
    // ************** END NEW ***************************
  }

And the new change is that along with specifying the '#cache' settings for a drupal render array you can also specify a 'post_cache' function.

Adding 'post_cache' to the settings available for '#cache' appears to make the most sense as it is only used to post process cached results and the '#' character is not included so as to align with the existing options for '#cache' like 'cid', 'keys', etc....

My apologies for not presenting the above as a patch as I have not done that before but if this idea is interesting I will definitely do it.

Please let me know what your thoughts are concerning this enhancement. Obviously best practice is to not modify core hence this feature request. Lastly, I think that this feature may be of benefit to others working with drupal render arrays and caching.

CommentFileSizeAuthor
#1 common.inc_FEATURE.patch792 bytesnikolaosinlight
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

nikolaosinlight’s picture

FileSize
792 bytes

Here is a patch for the feature request. Simply 1 if condition after the cache_get and 1 after the cache_set.