Переменные, введенные или установленные в файле Twig, не определены после первой позиции поля ссылки на сущность


У меня есть настройка абзаца, в которой есть поле ссылки на сущность, позволяющее редактору выбирать несколько узлов для использования в отображении.

Основываясь на количестве узлов, я хочу запустить класс. Я решил, что способ сделать это - использовать hook_preprocess_node() в теме:

$referringItem = $node->_referringItem;
    if (!empty($referringItem)) {
      $referringEntity = $referringItem->getEntity();

      if (
        !empty($referringEntity)
        && ($referringEntity instanceof NodeInterface || $referringEntity instanceof Paragraph)
       ) {
        $referringEntityType = $referringEntity->getType();
        $referringEntityTypeId = $referringEntity->getEntityTypeId();
      }
    }

if ($referringEntityType == 'homepage_feature') {
        $count = $referringEntity->get('field_items')->count();

        // Default.
        $variables['top_image'] = FALSE;
        $variables['right_image'] = FALSE;

        // Should this be count is only 1 AND it is the first delta item in field_feature?
        // If not, any single item Homepage Feature will get top-image which may not be
        // desired.
        if ($count == 1) {
          $variables['top_image'] = TRUE;
        }
      }

Приведенная выше логика может быть слишком сложной. В основном я оглядываюсь назад, чтобы посмотреть, какой тип абзаца использовался, чтобы я мог передать новые переменные в шаблон.

Что я заметил, так это то, что, хотя код выполняется для каждого указанного узла, переменные существуют только в первом узле. Я сбросил их в шаблон, и там все правильно, но они не определены в других узлах.

В Twig я попытался сбросить переменную в верхней части шаблона:

{{ top_image }}

Я вижу это в первой записи 1 над разметкой, а затем она больше никогда не отображается.

Как я могу гарантировать, что переменные передаются в шаблон правильно, каждый время?

Редактировать:

Похоже, что использование одного и того же узла с одинаковым режимом просмотра в разных абзацах или ссылках на сущности на одной и той же странице может привести к этому.

Является ли тогда решением добавить теги/контекст кэша к отображаемому узлу, чтобы учесть, какой родитель выводит его?

 2
Author: Kevin, 2019-07-18

1 answers

Основываясь на комментариях к вопросу, я расширил класс EntityReferenceEntityFormatter и изменил одну часть в методе viewElements (остальное то же самое):

  $view_builder = $this->entityTypeManager->getViewBuilder($entity->getEntityTypeId());
  $elements[$delta] = $view_builder->view($entity, $view_mode, $entity->language()->getId());

  try {
    $parent = $items->getParent();
    $parent_entity = $parent->getValue();
    $elements[$delta]['#cache']['keys'][] = $parent_entity->id();
    $elements[$delta]['#cache']['keys'][] = $parent_entity->bundle();
    $elements[$delta]['#cache']['keys'][] = $parent_entity->getEntityTypeId();
    $elements[$delta]['#cache']['keys'][] = 'context_aware';

    // Add special information for different paragraph types.
    if ($parent_entity->getEntityTypeId() == 'paragraph') {
      if ($parent_entity->bundle() == 'homepage_feature') {
        $elements[$delta]['#style_flags']['top_image'] = FALSE;
        $elements[$delta]['#style_flags']['right_image'] = FALSE;

        if ($parent_entity->get('field_items')->count() === 1) {
          $elements[$delta]['#style_flags']['top_image'] = TRUE;
        }
      }
    }
  } catch (\Exception $e) {
    // Add logging
  }

Позже, в разделе preprocess_node:

// ONLY for the homepage handling of featured content.
      if ($referringEntityType == 'homepage_feature') {
        $variables['top_image'] = $variables['elements']['#style_flags']['top_image'];
        $variables['right_image'] = $variables['elements']['#style_flags']['right_image'];
      }

Затем я смог добавить один и тот же узел в один и тот же тип абзаца несколько раз с правильной информацией. Теперь применяются правильные классы.

Изменить:

Просто чтобы добавить к этому, обязательно установите свои кэшируемые зависимости, чтобы любые изменения содержали ссылки не потребует очистки кэша:

$parent = $items->getParent();
$entity->addCacheableDependency($parent);

Правка 2:

Благодаря дополнительному руководству от 4k4 я ввел сервис визуализации и сократил его до:

    $parent = $items->getParent();
    $parent_entity = $parent->getValue();
    $elements[$delta]['#cache']['keys'][] = $parent_entity->id();
    $elements[$delta]['#cache']['keys'][] = $parent_entity->bundle();
    $elements[$delta]['#cache']['keys'][] = $parent_entity->getEntityTypeId();
    $elements[$delta]['#cache']['keys'][] = 'context_aware';

    if ($this->paragraphDisplaySettings->isApplicable($parent_entity)) {
      $elements[$delta]['#style_flags'] = $this->paragraphDisplaySettings->getSettings($parent_entity);
    }

    $this->renderer->addCacheableDependency($elements[$delta], $parent);

paragraphDisplaySettings это объект настраиваемой службы, который помогает оценивать различные флаги, передаваемые из исходного кода, просто для того, чтобы он был чище и компактнее. Это отлично работает.

 2
Author: Kevin, 2019-07-22 01:45:58