Saya memiliki blok yang sangat mendasar ini yang hanya menunjukkan ID node saat ini.
<?php
/**
* @file
* Contains \Drupal\mymodule\Plugin\Block\ExampleEmptyBlock.
*/
namespace Drupal\mymodule\Plugin\Block;
use Drupal\Core\Block\BlockBase;
use Drupal\Core\Cache\Cache;
/**
* @Block(
* id = "example_empty",
* admin_label = @Translation("Example: empty block")
* )
*/
class ExampleEmptyBlock extends BlockBase {
/**
* {@inheritdoc}
*/
public function build() {
$node = \Drupal::routeMatch()->getParameter('node');
$build = array();
if ($node) {
$config = \Drupal::config('system.site');
$build = array(
'#type' => 'markup',
'#markup' => '<p>' . $node->id() . '<p>',
'#cache' => array(
'tags' => $this->getCacheTags(),
'contexts' => $this->getCacheContexts(),
),
);
}
return $build;
}
/**
* {@inheritdoc}
*/
public function getCacheTags() {
$node = \Drupal::routeMatch()->getParameter('node');
return Cache::mergeTags(parent::getCacheTags(), ["node:{$node->id()}"]);
}
/**
* {@inheritdoc}
*/
public function getCacheContexts() {
return Cache::mergeContexts(parent::getCacheContexts(), ['user.node_grants:view']);
}
}
Tapi begitu di-cache, blok tetap sama, terlepas dari simpul mana yang saya kunjungi. Bagaimana cara menyimpan hasil per ID node dengan benar?
getCacheTags()
dari BlockBase, Anda hanya perlu menambahkan tag yang mewakili simpul Anda (simpul: {nid}). Maaf saya sedang terburu-buru sekarang, saya bisa menjelaskan lebih baik nanti,Jawaban:
Ini adalah kode kerja lengkap dengan komentar.
Saya mengujinya; berhasil.
Cukup masukkan kode dalam file bernama NodeCachedBlock.php di folder modul Anda, ubah namespace {module_name}, kosongkan cache dan gunakan.
sumber
#cache
pengaturan dalam fungsi build dan hanya menambahkan fungsi publik?Cara termudah untuk melakukan ini adalah dengan mengandalkan sistem konteks plugin / blok.
Lihat jawaban saya untuk Bagaimana cara membuat blok yang menarik konten simpul saat ini?
Anda hanya perlu meletakkan definisi konteks simpul di anotasi blok Anda seperti ini:
Dan kemudian gunakan seperti ini:
$this->getContextValue('node')
Yang menyenangkan tentang ini adalah bahwa Drupal akan mengurus caching untuk Anda. Secara otomatis. Karena ia tahu bahwa konteks default (dan sejauh core saja) node adalah node saat ini. Dan yang tahu dari mana asalnya, sehingga konteks cache dan tag cache ditambahkan secara otomatis.
Melalui
\Drupal\Core\Plugin\ContextAwarePluginBase::getCacheContexts()
dangetCacheTags()
metode yang sesuai , BlockBase / kelas blok Anda memanjang dari itu dan mewarisi metode tersebut.sumber
\Drupal::routeMatch()->getParameter('node')
dengan$this->getContextValue('node')
dan Anda menyelesaikan seluruh masalah caching dengan satu baris kode? Bagus!Jika Anda berasal dari kelas plugin blok
Drupal\Core\Block\BlockBase
Anda, Anda akan memiliki dua metode untuk mengatur tag dan konteks cache.getCacheTags()
getCacheContexts()
Sebagai contoh, blok modul Buku mengimplementasikan metode-metode tersebut sebagai berikut.
Blok modul Forum menggunakan kode berikut.
Dalam kasus Anda, saya akan menggunakan kode berikut.
Anda juga dapat menggunakan metode berikut ini, untuk membuat blok tidak mudah terbakar sama sekali (bahkan jika saya akan menghindarinya). Mungkin bermanfaat dalam kasus lain, mungkin.
Ingatlah untuk menambahkan
use Drupal\Core\Cache\Cache;
di bagian atas file, jika Anda akan menggunakanCache
kelas.sumber
BlockBase
kelas sebagai kelas induk?Saat Anda membuat array render, selalu lampirkan metadata yang benar:
Ini bukan blok spesifik dan metode blok dependensi cache getCacheTags (), getCacheContext () dan getCacheMaxAge () bukan pengganti. Mereka seharusnya hanya digunakan untuk metadata cache tambahan, yang tidak dapat dikirim melalui array render.
Lihat dokumentasi:
https://www.drupal.org/docs/8/api/render-api/cacheability-of-render-arrays
Lihat contoh ini bagaimana Drupal mengharapkan array render untuk menyediakan metadata cache yang diperlukan saat mengoptimalkan caching melalui auto-placeholdering dan lazy-building Masalah pengaturan tag cache spesifik pengguna pada blok khusus dengan konteks pengguna
sumber
#markup
dapat di-cache sama dengan elemen render lainnya. Dalam hal ini bukan markup, tetapi blok, yang di-cache dan di sini masalahnya. Anda tidak dapat menyelesaikannya dengan tag cache, karena mereka hanya akan batal, jika node diubah dalam database.BlockBase
kelas memiliki bahkan metode yang diperlukan.return [ '#markup' => render($output), '#cache' => [ 'contexts' => ['url'] ] ];
berfungsi sangat baik untuk setiap caching URL.Masalahnya di sini adalah bahwa konteks cache tidak menyatakan di tempat yang tepat di fungsi build:
Jika Anda memanggil blok itu di non node, fungsi build mengembalikan array kosong, jadi tidak ada konteks cache untuk blok ini dan perilaku itu akan di-cache oleh drupal: tampilan blok ini tidak akan benar-benar batal atau dibuat.
Solusi hanyalah menginisialisasi $ build dengan konteks cache setiap kali:
sumber
Saya menyadari bahwa saya terlambat untuk percakapan ini, tetapi kode di bawah ini berfungsi untuk saya:
sumber
Sudahkah Anda mencoba menerapkan hook_block_view_BASE_BLOCK_ID_alter?
function hook_block_view_BASE_BLOCK_ID_alter (array & $ build, \ Drupal \ Core \ Block \ BlockPluginInterface $ block) {$ build ['# cache'] ['max-age'] = 0; }
sumber