Problem/Motivation

The current placeholder functionality is a lot of work to get done, while all you want to do is add a placeholder and call a function later.

Proposed resolution

For D7, I have implemented the API in the following way:

  return RenderCacheControllerBase::getPlaceholder('comment_node_page_additions', array(
    '%node' => $node->nid,
  ));

The interface looks like this:

interface RenderCacheControllerPlaceholderInterface {
  public static function getPlaceholder($function, array $args = array());
  public static function postRenderCacheCallback(array $element, array $context);
  public static function loadPlaceholderFunctionArgs(array $context);
}

The implementation like this:

 // -----------------------------------------------------------------------
  // RenderCacheControllerPlaceholderInterface

  public static function getPlaceholder($function, array $args = array()) {
    $callback = 'RenderCacheControllerBase::postRenderCacheCallback';

    $context = array(
      'function' => $function,
      'args' => $args,
    );

    $placeholder = drupal_render_cache_generate_placeholder($context['function'], $context);

    return array(
      '#post_render_cache' => array(
          $callback => array(
          $context,
        ),
      ),
      '#markup' => $placeholder,
    );
  }

  public static function postRenderCacheCallback(array $element, array $context) {
    $placeholder = drupal_render_cache_generate_placeholder($context['function'], $context);

    // Check if the placeholder is present at all.
    if (strpos($element['#markup'], $placeholder) === FALSE) {
      return $element;
    }

    $function = $context['function'];
    $args = static::loadPlaceholderFunctionArgs($context);
    $new_element = call_user_func_array($function, $args);

    // @todo D8 - This needs to switch to some function, which ensures #attached, #cache tags and #post render cache can be updated
    //                    from this.
    $markup = RenderCacheControllerBase::drupalRender($new_element);
    $element['#markup'] = str_replace($placeholder, $markup, $element['#markup']);

    return $element;
  }

  public static function loadPlaceholderFunctionArgs(array $context) {
    $args = array();

    foreach ($context['args'] as $key => $arg) {
      // In case a dynamic argument has been passed, load it with the loader.
      if (preg_match('/^%(|' . DRUPAL_PHP_FUNCTION_PATTERN . ')$/', $key, $matches)) {
        if (!empty($matches[1]) && function_exists($matches[1] . '_load')) {
          $loader_function = $matches[1] . '_load';
          $arg = $loader_function($arg);
        }
      }
      $args[] = $arg;
    }

    return $args;
  }

Note: This has an added menu_loader for convenience similar to how %node works in Drupal 7.

Update: http://cgit.drupalcode.org/render_cache/tree/includes/RenderCachePlaceho...

has the newest code.

It has 'multiple' support - so you can group multiple objects together so you get a function call like:


  RenderCachePlaceholder::getPlaceholder('post_render_function', $object_1, TRUE);
  RenderCachePlaceholder::getPlaceholder('post_render_function', $object_2, TRUE);

  function post_render_function(array $args) {
    $placeholders = array();

    foreach ($args as $placeholder => $object) {
       $placeholders[$placeholder] = array(
          '#markup' => $object->id,
       );
    }

    return $placeholders;
  }

Remaining tasks

- Discuss implementation
- Find a class or service for it to add to
- Make a patch

API changes

API Addition:

- Added RenderCacheControllerBase::getPlaceholder() function.

Comments

Fabianx’s picture

Fabianx’s picture

Issue summary: View changes
Fabianx’s picture

Issue summary: View changes
Fabianx’s picture

Issue summary: View changes
Fabianx’s picture

Priority: Normal » Major

Dawehner thinks this should be at least major.

idebr’s picture

Status: Needs work » Active

I think the correct issue status is 'Active', since there is no patch attached to this issue.

Fabianx’s picture

Status: Active » Closed (duplicate)