Ich habe diesen sehr einfachen Block, der nur die ID des aktuellen Knotens anzeigt.
<?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']);
}
}
Einmal zwischengespeichert, bleibt der Block jedoch derselbe, unabhängig davon, welchen Knoten ich besuche. Wie kann ich das Ergebnis pro Knoten-ID korrekt zwischenspeichern?
getCacheTags()
Sie sich BlockBase an, Sie müssen nur ein Tag hinzufügen, das Ihren Knoten darstellt (node: {nid}). Tut mir leid, ich habe es jetzt eilig, ich kann es später besser erklärenAntworten:
Dies ist ein voll funktionsfähiger Code mit Kommentaren.
Ich habe es getestet. Es klappt.
Legen Sie den Code einfach in eine Datei mit dem Namen NodeCachedBlock.php in Ihrem Modulordner, ändern Sie den Namespace {Modulname}, leeren Sie den Cache und verwenden Sie ihn.
quelle
#cache
Einstellungen in der Build-Funktion zu entfernen und einfach die öffentlichen Funktionen hinzuzufügen.Der mit Abstand einfachste Weg, dies zu tun, besteht darin, sich auf das Plugin / Block-Kontext-System zu verlassen.
Siehe meine Antwort für Wie erstelle ich einen Block, der den aktuellen Knoteninhalt abruft?
Sie müssen lediglich eine Knotenkontextdefinition wie folgt in Ihre Blockanmerkung einfügen:
Und dann benutze es so:
$this->getContextValue('node')
Das Schöne daran ist, dass Drupal sich dann um das Caching für Sie kümmert. Automatisch. Weil bekannt ist, dass der Standardknotenkontext (und nur der Kern) der aktuelle Knoten ist. Und das weiß, woher es kommt, sodass der Cache-Kontext und die Cache-Tags automatisch hinzugefügt werden.
Durch
\Drupal\Core\Plugin\ContextAwarePluginBase::getCacheContexts()
und die entsprechendengetCacheTags()
Methoden erweitert sich BlockBase / Ihre Blockklasse davon und erbt diese Methoden.quelle
\Drupal::routeMatch()->getParameter('node')
mit$this->getContextValue('node')
und Sie lösen das gesamte Caching-Problem mit einer Codezeile? Groß!Wenn Sie die Klasse Ihres Block-Plugins ableiten
Drupal\Core\Block\BlockBase
, haben Sie zwei Methoden, um Cache-Tags und -Kontexte festzulegen.getCacheTags()
getCacheContexts()
Beispielsweise implementiert der Buchmodulblock diese Methoden wie folgt.
Der Forum-Modulblock verwendet den folgenden Code.
In Ihrem Fall würde ich den folgenden Code verwenden.
Sie können auch die folgende Methode verwenden, um den Block überhaupt nicht zwischenspeicherbar zu machen (auch wenn ich ihn vermeiden würde). Es könnte vielleicht in anderen Fällen nützlich sein.
Denken Sie daran,
use Drupal\Core\Cache\Cache;
oben in die Datei einzufügen, wenn Sie dieCache
Klasse verwenden möchten.quelle
BlockBase
Klasse auch als übergeordnete Klasse?Wenn Sie ein Render-Array erstellen, hängen Sie immer die richtigen Metadaten an:
Dies ist nicht blockspezifisch und die Cache-Abhängigkeitsmethoden getCacheTags (), getCacheContext () und getCacheMaxAge () der Block-Plugins sind kein Ersatz. Sie sollten nur für zusätzliche Cache-Metadaten verwendet werden, die nicht über das Render-Array bereitgestellt werden können.
Siehe die Dokumentation:
https://www.drupal.org/docs/8/api/render-api/cacheability-of-render-arrays
Sehen Sie dieses Beispiel , wie Drupal Array einen Render erwartet , dass die notwendigen Cache - Metadaten zu liefern , wenn das Caching durch Auto-placeholdering Optimierung und lazy-Aufbau Problem Einstellung benutzerspezifischen Cache - Tags auf benutzerdefinierten Block mit Benutzerkontext
quelle
#markup
kann wie jedes andere Renderelement zwischengespeichert werden. In diesem Fall ist es nicht das Markup, sondern der Block, der zwischengespeichert wird und hier liegt das Problem. Sie können es nicht mit Cache-Tags lösen, da diese nur ungültig werden, wenn der Knoten in der Datenbank geändert wird.BlockBase
Klasse hat sogar die notwendigen Methoden.return [ '#markup' => render($output), '#cache' => [ 'contexts' => ['url'] ] ];
funktioniert das super prima per URL-Caching.Das Problem hierbei ist, dass die Cache-Kontexte in der Build-Funktion nicht an der richtigen Stelle deklariert werden:
Wenn Sie diesen Block auf einem Nicht-Knoten aufrufen, gibt die Erstellungsfunktion ein leeres Array zurück, sodass für diesen Block kein Cache-Kontext vorhanden ist und dieses Verhalten von Drupal zwischengespeichert wird: Die Anzeige dieses Blocks wird nicht ordnungsgemäß ungültig gemacht oder gerendert.
Die Lösung besteht darin, den $ build jedes Mal mit den Cache-Kontexten zu initialisieren:
quelle
Mir ist klar, dass ich zu spät zu dieser Unterhaltung komme, aber der folgende Code hat bei mir funktioniert:
quelle
Haben Sie versucht, hook_block_view_BASE_BLOCK_ID_alter zu implementieren?
function hook_block_view_BASE_BLOCK_ID_alter (Array & $ build, \ Drupal \ Core \ Block \ BlockPluginInterface $ block) {$ build ['# cache'] ['max-age'] = 0; }
quelle