Saya telah mengalami masalah di mana blok yang seharusnya unik per halaman bukan untuk pengguna yang keluar. Masalahnya adalah plugin blok khusus yang saya miliki pada halaman pencarian tampilan yang berisi filter khusus (semacam pengganti kustom untuk filter terbuka. Blok ditempatkan melalui / admin / struktur / blok).
Berdasarkan apa yang telah saya pelajari tentang Drupal 8, saya menambahkan konteks cache ke array build saya:
public function build() {
$search_form = \Drupal::formBuilder()->getForm('Drupal\mymodule\Form\SearchForm');
return [
'search_form' => $search_form,
'#cache' => ['contexts' => ['url.path', 'url.query_args']]
];
}
Tapi sepertinya ini pasti salah karena ketika keluar, blok akan di-cache pada tampilan pertama, dan ketika url berubah, itu tidak menunjukkan versi baru dari blok.
Saya pikir itu mungkin halaman tampilan yang menyebabkan masalah, tetapi bahkan ketika saya mematikan caching pada halaman tampilan, masalah tetap ada.
Saya dapat memperbaiki masalah ini beberapa cara, misalnya, dengan menggunakan kait preprocess_block:
function mymodule_preprocess_block__mycustomsearchblock(&$variables) {
$variables['#cache']['contexts'][] = 'url.path';
$variables['#cache']['contexts'][] = 'url.query_args';
}
Tapi itu mengganggu saya, saya tidak bisa begitu saja memasukkan konteks cache ke dalam array build blok saya.
Karena blok saya memperluas BlockBase, saya memutuskan untuk mencoba metode getCacheContexts (), terutama karena saya melihat beberapa modul di dalam core melakukannya dengan cara ini.
public function getCacheContexts() {
return Cache::mergeContexts(parent::getCacheContexts(), ['url.path', 'url.query_args']);
}
Ini juga memperbaiki masalah, tetapi yang menarik, ketika saya menampilkan variabel dalam fungsi blok preproses, ini tidak ditampilkan dalam $ variabel ['# cache'] ['konteks'], tetapi mereka ditampilkan dalam elemen $ variabel [' '] [' # cache '] [' contexts ']
array:5 [▼
0 => "languages:language_interface"
1 => "theme"
2 => "url.path"
3 => "url.query_args"
4 => "user.permissions"
]
Saya mencoba mencari tahu bagaimana ini bekerja, dan mengapa itu tidak berfungsi dari fungsi build.
Melihat /core/modules/block/src/BlockViewBuilder.php pada fungsi viewMultiple (), sepertinya ia menarik tag cache dari entitas dan plugin:
'contexts' => Cache::mergeContexts(
$entity->getCacheContexts(),
$plugin->getCacheContexts()
),
Jadi itu menjelaskan mengapa menambahkan metode getCacheContexts () ke plugin blok saya menambahkan konteks ke blok saya. Juga, melihat metode preRender di kelas yang sama, sepertinya itu tidak menggunakan array cache di fungsi blok bangunan, yang membingungkan saya, karena tampaknya cara untuk menambahkan caching di Drupal 8 adalah menambahkan #cache elemen untuk membuat elemen.
Jadi pertanyaan saya adalah,
1) Apakah konteks cache ditambahkan langsung pada array di plugin blok diabaikan?
2) Jika demikian, apakah ada cara lain, apakah kita perlu menambahkannya ke elemen turunan build?
3) Jika konteks yang ditambahkan secara langsung diabaikan, apakah menambahkan getCacheContexts () cara untuk mencari plugin blok dalam modul khusus?
Jawaban:
Dalam kebanyakan kasus, Anda cukup mengatur konteks cache secara langsung pada array render yang Anda kembalikan dalam metode build () Anda.
Saya akhirnya menemukan apa masalah saya, dengan bantuan @Berdir dan @ 4k4. Jika Anda menggunakan templat khusus, seperti blok - myblock.html.twig dan Anda menampilkan variabel satu per satu, seperti {{content.foo}} alih-alih semuanya pada saat bersamaan seperti {{content}}, ia mengabaikan konteks cache Anda diteruskan langsung ke array build blok Anda, ketika keluar. Lihat Apa cara yang benar untuk mengatur konteks cache pada blok khusus?
Jadi, untuk menjawab pertanyaan awal:
1) Konteks cache yang diteruskan langsung ke plugin blok khusus terkadang diabaikan. Anda dapat menguji ini dengan mengubah SyndicateBlock , dan kemudian membuat templat kustom di blok tema Anda - syndicate.html.php di mana Anda menampilkan variabel secara individual seperti ini:
Saat Anda mengubah argumen url, Anda akan melihat blok tidak menghormati konteks cache.
Sekarang jika Anda mengubahnya mengeluarkan semua konten sebagai bagian, itu berfungsi:
Sekarang, itu menghormati konteks cache, dan blok itu unik per halaman.
2) Untuk saat ini, untuk mengatasinya, Anda bisa menampilkan apa yang ada di blok Anda di template itu sendiri.
Ini menghindari pengecualian caching esoterik modul blok dan formulir Anda sekarang unik per halaman saat keluar.
3) Haruskah Anda membuat templat tema Anda sendiri untuk memperbaikinya, atau cukup tambahkan metode untuk getCacheContexts () di plugin Blok khusus Anda? Lebih baik untuk membuat templat tema baru, daripada menambahkan metode getCacheContexts () yang mengesampingkan urutan alami penggelembungan konteks cache, dan dapat memecah metadata lebih dalam di array build Anda.
sumber
Bagi siapa pun yang menemukan ini ...
Alasan rendering
content
(ataucontent|without()
) berfungsi adalah bahwa ada elemen dalam array rendercontent['#cache']
yang berisi semua metadata yang dapat di-cache untuk konten.Jika Anda tidak mengizinkan ini untuk dirender dalam ranting, salah satu
content
atau{{'#cache': content['#cache']|render }}
, halaman tidak tahu itu memiliki metadata yang dapat di-cache (mis. Itu tidak pernah muncul).Sepertinya Anda tidak melakukan ranting khusus. Jika Anda menggunakan sesuatu seperti Varnish, itu juga bisa menjadi penyebab bagi pengguna anonim.
sumber
Saya juga mengalami masalah ini dan solusinya adalah membuat variabel block_content baru berdasarkan versi yang disaring dari variabel konten utama tidak termasuk bidang kustom yang ingin saya render secara manual:
Kemudian alih-alih merender variabel "content.body" secara langsung nanti, saya memanggil:
Jika Anda ingin merender setiap bidang secara individual, Anda bisa terus menambahkannya ke filter "tanpa" sehingga rendering block_content tidak melakukan apa pun kecuali memperbaiki caching.
sumber
Metode yang lebih mudah untuk mencapai ini adalah dengan mendeklarasikan dan mendefinisikan
getCacheContexts()
metodeLihat dokumentasi CacheableDependency , itu harus berisi semua yang Anda butuhkan;)
sumber