Mam ten bardzo podstawowy blok, który pokazuje tylko bieżący identyfikator węzła.
<?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']);
}
}
Ale po buforowaniu blok pozostaje taki sam, niezależnie od tego, który węzeł odwiedzam. Jak poprawnie buforować wynik według identyfikatora węzła?
getCacheTags()
BlockBase, wystarczy dodać tag reprezentujący twój węzeł (node: {nid}). Przepraszam, spieszy mi się, mogę później wyjaśnić lepiejOdpowiedzi:
To jest pełny działający kod z komentarzami.
Przetestowałem to; to działa.
Wystarczy umieścić kod w pliku o nazwie NodeCachedBlock.php w folderze modułu, zmienić jego przestrzeń nazw {nazwa_modułu}, wyczyścić pamięć podręczną i użyć go.
źródło
#cache
ustawień w funkcji kompilacji i dodaniu funkcji publicznych?Zdecydowanie najłatwiejszym sposobem na to jest poleganie na systemie kontekstowym wtyczki / bloku.
Zobacz moją odpowiedź na temat Jak utworzyć blok, który pobiera bieżącą zawartość węzła?
Musisz tylko umieścić definicję kontekstu węzła w adnotacji bloku w następujący sposób:
A następnie użyj go w następujący sposób:
$this->getContextValue('node')
Zaletą tego jest to, że Drupal zajmie się dla ciebie buforowaniem. Automatycznie. Ponieważ wie, że domyślnym (i jeśli chodzi o rdzeń) kontekstem węzła jest bieżący węzeł. I to wie, skąd pochodzi, więc kontekst pamięci podręcznej i tagi pamięci podręcznej są dodawane automatycznie.
Poprzez
\Drupal\Core\Plugin\ContextAwarePluginBase::getCacheContexts()
i odpowiedniegetCacheTags()
metody BlockBase / twoja klasa bloków rozszerza się i dziedziczy te metody.źródło
\Drupal::routeMatch()->getParameter('node')
z$this->getContextValue('node')
i rozwiązać cały problem buforowania z jednej linii kodu? Świetny!Jeśli wywodzisz się z klasy wtyczki blokowej
Drupal\Core\Block\BlockBase
, będziesz mieć dwie metody ustawiania tagów pamięci podręcznej i kontekstów.getCacheTags()
getCacheContexts()
Na przykład blok modułu Book implementuje te metody w następujący sposób.
Blok modułu Forum używa następującego kodu.
W twoim przypadku użyłbym następującego kodu.
Możesz także użyć poniższej metody, aby blok był w ogóle nieusuwalny (nawet gdybym tego uniknął). Może to może być przydatne w innych przypadkach.
Pamiętaj, aby dodać
use Drupal\Core\Cache\Cache;
na górze pliku, jeśli zamierzasz korzystać zCache
klasy.źródło
BlockBase
klasy jako klasy nadrzędnej?Podczas budowania tablicy renderowania zawsze dołączaj poprawne metadane:
Nie jest to specyficzne dla bloku, a metody zależności buforowania wtyczek blokowych getCacheTags (), getCacheContext () i getCacheMaxAge () nie są zamiennikami. Powinny być używane tylko do dodatkowych metadanych pamięci podręcznej, których nie można dostarczyć przez tablicę renderującą.
Zobacz dokumentację:
https://www.drupal.org/docs/8/api/render-api/cacheability-of-render-arrays
Zobacz ten przykład, w jaki sposób Drupal spodziewa się, że tablica renderująca zapewni niezbędne metadane pamięci podręcznej podczas optymalizacji buforowania poprzez automatyczne zastępowanie i budowanie z opóźnieniem Problem z ustawieniem specyficznych dla użytkownika znaczników pamięci podręcznej w niestandardowym bloku z kontekstem użytkownika
źródło
#markup
może być buforowany tak samo jak każdy inny element renderujący. W tym przypadku nie jest to znacznik, ale blok, który jest buforowany i tutaj jest problem. Nie można go rozwiązać za pomocą tagów pamięci podręcznej, ponieważ są unieważniane tylko wtedy, gdy węzeł zostanie zmieniony w bazie danych.BlockBase
Klasa ma jeszcze niezbędnych metod.return [ '#markup' => render($output), '#cache' => [ 'contexts' => ['url'] ] ];
działa bardzo dobrze dla buforowania adresów URL.Problem polega na tym, że konteksty pamięci podręcznej nie są deklarowane we właściwym miejscu w funkcji kompilacji:
Jeśli wywołasz ten blok w innym węźle, funkcja kompilacji zwróci pustą tablicę, więc nie ma kontekstu pamięci podręcznej dla tego bloku, a to zachowanie zostanie buforowane przez drupal: wyświetlanie tego bloku nie zostanie poprawnie unieważnione lub wyrenderowane.
Rozwiązaniem jest po prostu zainicjowanie kompilacji $ za pomocą kontekstów pamięci podręcznej za każdym razem:
źródło
Zdaję sobie sprawę, że spóźniłem się na tę rozmowę, ale poniższy kod działał dla mnie:
źródło
Czy próbowałeś wdrożyć hook_block_view_BASE_BLOCK_ID_alter?
funkcja hook_block_view_BASE_BLOCK_ID_alter (tablica i $ build, \ Drupal \ Core \ Block \ BlockPluginInterface $ block) {$ build ['# cache'] ['max-age'] = 0; }
źródło