1

I've spent the best part of the last day or two trying to implement lazy_builder (as seen in this brilliant tutorial https://github.com/joachim-n/drupalcon-europe-2020-lazy-builders).

However, rather than with a block or page render. I'd like to implement the lazy_builder into hook_tokens() and make the $replacements value dynamic so that it uses the lazy_builder.

We have a value saved to session that we use as the value of a token (so it back be used across the site).

$session = \Drupal::request()->getSession();
$session->get('my_value');

I've tried setting $bubbleable_metadata with both addCacheContexts and addCacheableDependency

$bubbleable_metadata->addCacheContexts(['session']);

&

$session = \Drupal::request()->getSession();
$bubbleable_metadata->addCacheableDependency($session);

However both these options make the page UNCACHABLE.

I'd like to keep the page a cache HIT, but load in the token value via lazy_builder.

My question is, is there anyway to leverage lazy_builder, in the token replacement?

/**
 * Implements hook_tokens().
 */
function mymodule_tokens($type, $tokens, array $data, array $options, BubbleableMetadata $bubbleable_metadata) {
  $replacements = array();
  if ($type == 'my_token') {
    foreach ($tokens as $name => $original) {
      // Find the desired token by name
      switch ($name) {
        case 'my_token':
          $session = \Drupal::request()->getSession();
          //make the below use lazy_builder
          $replacements[$original] = $session->get('tracking');
          break;
      }
    }
  }
  // Return the replacements.
  return $replacements;
}
4
  • Welcome to Drupal Answers! #lazy_builder is used in render arrays. It's not clear how you would use it to change the value returned from a token.
    – apaderno
    Mar 3, 2021 at 16:55
  • Thanks for your response. So any suggestions on how to use this token, but still make the page a CACHE HIT?
    – Adamation
    Mar 3, 2021 at 16:59
  • Which page? hook_tokens() could be invoked for every page. The code shown in the question doesn't make clear for which page it would be used or called.
    – apaderno
    Mar 3, 2021 at 17:04
  • Any page where this token could be placed.
    – Adamation
    Mar 3, 2021 at 17:05

1 Answer 1

1

This answer might be helpful. In your case you could try to bubble up the attachment from the token itself:

$replacements[$original] = '<my-placeholder>';

$bubbleable_metadata->addAttachments([
  'placeholders' => [
    '<my-placeholder>' => [
      '#lazy_builder' => ['\Drupal\mytheme\MythemeLazyBuilders::replaceUid', []],
    ],
  ],
]);

You not really need the Drupal token system, you can attach placeholders almost everywhere in the rendering process, but for some cases this could be a convenient way to make a lazy builder available.

3
  • This is really promising @4k4 and I got the attachment pulling in LazyBuilder render class. However I am getting the below error. TypeError: Argument 1 passed to Drupal\\Core\\Cache\\CacheableMetadata::createFromRenderArray() must be of the type array, string given, called in /var/www/html/web/core/lib/Drupal/Core/Render/Renderer.php on line 358 in /var/www/html/web/core/lib/Drupal/Core/Cache/CacheableMetadata.php on line 149 What would the render class need to return? Should I still be setting a replacement value on the token, or will the attachment take care of it. Thanks
    – Adamation
    Mar 3, 2021 at 17:50
  • This is what I meant, you have two token/placeholder mechanism chained, which is normally not necessary. In the first token replacement you could replace the Drupal token with a non-visible HTML tag placeholder <my-placeholder>.
    – 4uk4
    Mar 3, 2021 at 18:02
  • In the second replacement the lazy builder has to return a render array, this means at least a '#markup' element like in the linked answer.
    – 4uk4
    Mar 3, 2021 at 19:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.