Commit a986b310 authored by mxh's avatar mxh
Browse files

Issue #3253881 by mxh: mustache_views: Caching not properly working when using...

Issue #3253881 by mxh: mustache_views: Caching not properly working when using Mustache templates in Views
parent ff16dd6d
Loading
Loading
Loading
Loading
+6 −3
Original line number Diff line number Diff line
@@ -410,9 +410,12 @@ class Sync extends MustacheMagic {
        $server_side_render['#with_tokens'] = $this->element['#with_tokens'];
        /** @var \Drupal\mustache\MustacheTokenProcessor $token_processor */
        $token_processor = \Drupal::service('mustache.token_processor');
        $tokenized = $token_processor->tokenizeTemplate($template_hash, $template_content);
        if (!empty($tokenized['tokens'])) {
          $values['token_options'] = !empty($this->element['#with_tokens']['options']) ? $this->element['#with_tokens']['options'] : [];
          $token_data = !empty($this->element['#with_tokens']['data']) ? $this->element['#with_tokens']['data'] : [];
        $token_processor->processData($token_data, 'view', $bubbleable_metadata);
          $token_processor->processData($token_data, $tokenized['tokens'], 'view', $bubbleable_metadata);
        }
      }

      $build->withPlaceholder($server_side_render);
+15 −13
Original line number Diff line number Diff line
@@ -118,14 +118,15 @@ class MustacheTokenIterate {
   */
  protected function buildRecursive(array $data, array $options, BubbleableMetadata $bubbleable_metadata, array $token_keys, $check_access = 'view') {
    $target = IterableMarkup::create();
    if (empty($data) || empty($token_keys)) {
    if (empty($data) && empty($token_keys)) {
      return $target;
    }

    $key = array_shift($token_keys);
    $property = reset($token_keys);

    if (!isset($data[$key]) && !empty($data)) {
    if (!isset($data[$key])) {
      if (!empty($data)) {
        if (strpos($key, '_') !== FALSE) {
          $key_hyphened = str_replace('_', '-', $key);
          if (isset($data[$key_hyphened])) {
@@ -140,6 +141,7 @@ class MustacheTokenIterate {
            return $this->buildRecursive($data, $options, $bubbleable_metadata, $token_keys, $check_access);
          }
        }
      }
      $data[$key] = NULL;
    }

+66 −26
Original line number Diff line number Diff line
@@ -156,17 +156,6 @@ class MustacheTokenProcessor {
      $token_options['clear'] = TRUE;
    }

    if (!empty($element['#cache'])) {
      $bubbleable_metadata = BubbleableMetadata::createFromRenderArray($element);
    }
    else {
      $bubbleable_metadata = new BubbleableMetadata();
    }

    // Build up the token data.
    $token_data = isset($token_settings['data']) ? $token_settings['data'] : [];
    $this->processData($token_data, 'view', $bubbleable_metadata, $langcode);

    $template_hash = hash('md4', $template_content);
    $tokenized = $this->tokenizeTemplate($template_hash, $template_content);
    if (empty($tokenized['tokens'])) {
@@ -177,6 +166,17 @@ class MustacheTokenProcessor {
    $template_tokens = $tokenized['tokens'];
    $mustache_variables = $tokenized['variables'];

    if (!empty($element['#cache'])) {
      $bubbleable_metadata = BubbleableMetadata::createFromRenderArray($element);
    }
    else {
      $bubbleable_metadata = new BubbleableMetadata();
    }

    // Build up the token data.
    $token_data = isset($token_settings['data']) ? $token_settings['data'] : [];
    $this->processData($token_data, $template_tokens, 'view', $bubbleable_metadata, $langcode);

    // Determine cacheability of the Token data.
    $data_is_cacheable = TRUE;
    $data_cid = [];
@@ -372,6 +372,10 @@ class MustacheTokenProcessor {
   *
   * @param array &$token_data
   *   The token data to process.
   * @param array|null $tokens
   *   (Optional) An array of tokens that are known to be used. Set to NULL if
   *   they are not known beforehand. This should be set whenever possible,
   *   otherwise cacheability may be not working properly.
   * @param string $check_access
   *   (Optional) The access check to perform. Set NULL to skip access filter.
   * @param \Drupal\Core\Render\BubbleableMetadata|null $bubbleable_metadata
@@ -379,7 +383,11 @@ class MustacheTokenProcessor {
   * @param string|null $langcode
   *   (Optional) The langcode to use. Leave NULL to use the current language.
   */
  public function processData(array &$token_data, $check_access = 'view', $bubbleable_metadata = NULL, $langcode = NULL) {
  public function processData(array &$token_data, $tokens = NULL, $check_access = 'view', $bubbleable_metadata = NULL, $langcode = NULL) {
    if (isset($tokens) && empty($tokens)) {
      return;
    }

    if (!isset($bubbleable_metadata)) {
      $bubbleable_metadata = new BubbleableMetadata();
    }
@@ -400,6 +408,7 @@ class MustacheTokenProcessor {

    // Merge the token data with any global context that provides a value.
    $context_repository = $this->contextRepository;
    $contexts = [];
    if (!isset(static::$contextIds)) {
      static::$contextIds = array_keys($context_repository->getAvailableContexts());
    }
@@ -411,32 +420,24 @@ class MustacheTokenProcessor {
        // want to only use "node").
        $type = end($context_data_type);
        $value = $context->getContextValue();
        $bubbleable_metadata->addCacheableDependency($context);
        // We add the context to the array, even if the value is not being used.
        // That way cacheability metadata will include cache contexts that are
        // required for variations, especially when global context is being
        // used elsewhere.
        $contexts[$type] = $context;
        if (isset($value) && !isset($token_data[$type])) {
          $token_data[$type] = $value;
        }
      }
    }

    // Filter out any data that is not allowed to be viewed.
    // Switch to translations if necessary and available.
    // Also re-map entities that may have a different token type defined.
    foreach ($token_data as $type => $value) {
      if (($value instanceof TranslatableInterface) && ($value->language()->getId() !== $langcode) && ($value->hasTranslation($langcode))) {
        $value = $value->getTranslation($langcode);
        $token_data[$type] = $value;
      }
      if ($value instanceof CacheableDependencyInterface) {
        $bubbleable_metadata->addCacheableDependency($value);
      }
      if ($check_access && $value instanceof AccessibleInterface) {
        /** @var \Drupal\Core\Access\AccessResultInterface $access_result */
        $access_result = $value->access($check_access, NULL, TRUE);
        $bubbleable_metadata->addCacheableDependency($access_result);
        if (!$access_result->isAllowed()) {
          unset($token_data[$type]);
          continue;
        }
      }
      if (!($value instanceof EntityInterface)) {
        continue;
      }
@@ -449,9 +450,48 @@ class MustacheTokenProcessor {
        $the_real_token_type = $definition->get('token_type') ?: $value->getEntityTypeId();
      }
      if (!isset($token_data[$the_real_token_type])) {
        if (isset($contexts[$type])) {
          $contexts[$the_real_token_type] = $contexts[$type];
        }
        $token_data[$the_real_token_type] = $value;
      }
    }

    // Filter out data that is not being used and is not allowed to be viewed.
    // Also add cacheability metadata of data that is being used.
    foreach ($token_data as $type => $value) {
      if (isset($tokens)) {
        $type_is_used = FALSE;
        foreach (array_keys($tokens) as $used_token_type) {
          if ($used_token_type === $type) {
            $type_is_used = TRUE;
            break;
          }
        }
      }
      else {
        $type_is_used = TRUE;
      }
      if (!$type_is_used) {
        unset($token_data[$type]);
        continue;
      }
      if ($value instanceof CacheableDependencyInterface) {
        $bubbleable_metadata->addCacheableDependency($value);
      }
      if (isset($contexts[$type])) {
        $bubbleable_metadata->addCacheableDependency($contexts[$type]);
      }
      if ($check_access && $value instanceof AccessibleInterface) {
        /** @var \Drupal\Core\Access\AccessResultInterface $access_result */
        $access_result = $value->access($check_access, NULL, TRUE);
        $bubbleable_metadata->addCacheableDependency($access_result);
        if (!$access_result->isAllowed()) {
          unset($token_data[$type]);
          continue;
        }
      }
    }
  }

  /**
+1 −1
Original line number Diff line number Diff line
@@ -135,7 +135,7 @@ class Introspection extends MustacheMagic {
      $token_data = isset($token_settings['data']) ? $token_settings['data'] : [];
      /** @var \Drupal\mustache\MustacheTokenProcessor $token_processor */
      $token_processor = \Drupal::service('mustache.token_processor');
      $token_processor->processData($token_data, 'view');
      $token_processor->processData($token_data);
      if (!empty($token_data)) {
        $token_info = \Drupal::token()->getInfo();
        foreach ($token_info['tokens'] as $type => $tokens) {