Я столкнулся с проблемой, когда блок, который должен быть уникальным для каждой страницы, не предназначен для пользователей, вышедших из системы. Проблема заключается в том, что у меня есть плагин для пользовательских блоков на странице поиска представлений, который содержит пользовательские фильтры (что-то вроде пользовательской замены для открытых фильтров. Блок помещается через / admin / structure / block).
Основываясь на том, что я узнал о Drupal 8, я добавил контексты кеша в свой массив сборки:
public function build() {
$search_form = \Drupal::formBuilder()->getForm('Drupal\mymodule\Form\SearchForm');
return [
'search_form' => $search_form,
'#cache' => ['contexts' => ['url.path', 'url.query_args']]
];
}
Но, похоже, это должно быть неверно, потому что при выходе из системы блок кэшируется при первом просмотре, а при изменении URL-адреса не отображается новая версия блока.
Я думал, что это может быть проблема с страницей просмотра, но даже когда я отключил кэширование на странице просмотра, проблема осталась.
Мне удалось решить эту проблему несколькими способами, например, с помощью ловушки preprocess_block:
function mymodule_preprocess_block__mycustomsearchblock(&$variables) {
$variables['#cache']['contexts'][] = 'url.path';
$variables['#cache']['contexts'][] = 'url.query_args';
}
Но это беспокоило меня, я не мог просто поместить контексты кэша в массив сборки моего блока.
Поскольку мой блок расширяет BlockBase, я решил попробовать метод getCacheContexts (), тем более что я видел, что некоторые модули в ядре делают это именно так.
public function getCacheContexts() {
return Cache::mergeContexts(parent::getCacheContexts(), ['url.path', 'url.query_args']);
}
Это также исправило проблему, но, что интересно, когда я выводил переменные в функции блока предварительной обработки, они не отображаются в $ variable ['# cache'] ['contexts'], но они отображаются в $ variable ['elements '] [' # кэшировать '] [' контексты]
array:5 [▼
0 => "languages:language_interface"
1 => "theme"
2 => "url.path"
3 => "url.query_args"
4 => "user.permissions"
]
Я пытаюсь выяснить, как это работает, и почему это не работает из функции сборки.
Глядя на /core/modules/block/src/BlockViewBuilder.php функцию viewMultiple (), похоже, что она извлекает теги кеша из сущности и плагина:
'contexts' => Cache::mergeContexts(
$entity->getCacheContexts(),
$plugin->getCacheContexts()
),
Это объясняет, почему добавление метода getCacheContexts () в мой плагин блока добавляет контексты в мой блок. Также, глядя на метод preRender в том же классе, похоже, что он не использует массив кеша в функции сборки блоков, что меня смущает, так как кажется, что способ добавить кеширование в Drupal 8 - это добавить #cache элемент для отображения элементов.
Итак, мой вопрос,
1) Игнорируются ли контексты кеша, добавленные непосредственно в массив в блочном плагине?
2) Если так, есть ли способ обойти это, нужно ли добавить его в дочерний элемент массива сборки?
3) Если контекст, добавленный напрямую, игнорируется, является ли добавление getCacheContexts () способом пойти на блочные плагины в пользовательских модулях?
Ответы:
В большинстве случаев вы просто устанавливаете контекст кеша непосредственно в массиве рендеринга, который вы возвращаете в методе build ().
Я наконец нашел, в чем была моя проблема, с помощью @Berdir и @ 4k4. Если вы используете собственный шаблон, такой как block - myblock.html.twig, и вы выводите переменные по отдельности, например {{content.foo}}, а не все одновременно, как {{content}}, он игнорирует когда вы вышли из системы, кеш-контексты передавались непосредственно в ваш массив сборки блоков. См. Как правильно установить контексты кэша для пользовательских блоков?
Итак, чтобы ответить на оригинальный вопрос:
1) Контексты кэша, передаваемые непосредственно в пользовательский плагин блока, иногда игнорируются. Вы можете проверить это, изменив SyndicateBlock , а затем создав собственный шаблон в блоке темы - syndicate.html.php, в котором вы выводите переменные по отдельности, например так:
Когда вы измените аргументы url, вы увидите, что блок не учитывает контекст кэша.
Теперь, если вы измените его вывод всего контента как кусок, это работает:
Теперь он учитывает контекст кэша, и блок уникален для каждой страницы.
2) На данный момент, чтобы обойти это, вы можете просто вывести то, что находится в вашем блоке, в его собственный шаблон.
Это позволяет обойти эзотерические исключения кэширования блочного модуля, и ваша форма теперь уникальна для каждой страницы после выхода из системы.
3) Следует ли создать собственный шаблон темы, чтобы это исправить, или просто добавить метод для getCacheContexts () в свой пользовательский плагин Block? Лучше создать новый шаблон темы, а не добавлять метод getCacheContexts (), который переопределяет естественный порядок всплытия контекстов кэша и может более глубоко нарушать метаданные в массиве сборки.
источник
Для тех, кто находит это ...
Причина того, что рендеринг
content
(илиcontent|without()
) работает, состоит в том, что в массиве рендеринга есть элемент,content['#cache']
который содержит все кэшируемые метаданные для содержимого.Если вы не разрешаете отображать это в ветке, либо,
content
либо{{'#cache': content['#cache']|render }}
страница не знает, что она содержит кэшируемые метаданные (например, она никогда не всплывает ).Похоже, вы не делаете обычную веточку. Если вы используете что-то вроде Varnish, это также может быть причиной для анонимных пользователей.
источник
Я также столкнулся с этой проблемой, и я нашел обходной путь - создание новой переменной block_content на основе отфильтрованной версии основной переменной содержимого, исключая любые настраиваемые поля, которые я хочу визуализировать вручную:
Затем вместо рендеринга переменной «content.body» непосредственно позже, я вызываю:
Если вы хотите визуализировать каждое поле по отдельности, вы можете просто добавить их в фильтр «без», чтобы рендеринг block_content не делал ничего, кроме исправления кеширования.
источник
Самый простой способ добиться этого - объявить и определить
getCacheContexts()
методПроверьте документацию CacheableDependency , она должна содержать все, что вам нужно;)
источник