[gelöst] referenzierten Inhalt in Paragraph-Twig ausgeben - ohne clear_all_cache
Eingetragen von tetri999 (153)
am 14.02.2019 - 14:26 Uhr in
am 14.02.2019 - 14:26 Uhr in
Hallo,
ich habe einen Content-Type mit einem Paragraph-Element, das u.a. eine Entity-Refenzierung auf andere Inhalte enthält.
Die Ausgabe baue ich in einem speziellen Template zusammen: "paragraph--SPECIAL-TEASER.html.twig".
Dem übergebe ich aus der "MY_THEME_preprocess_paragraph(&$variables)" die nötigen Elemente aus dem refenzierten Inhalt:
...
if( $paragraph->bundle()=='SPECIAL-TEASER' ) {
$lang = \Drupal::languageManager()->getCurrentLanguage()->getId();
$paragraph = $variables['paragraph'];
$nid = $paragraph->field_entity_ref->target_id;
$node = \Drupal::entityManager()->getStorage('node')->load($nid)->getTranslation($lang);
$SPECIAL_ELEMS = new MY_MODUL_CLASS($node);
$variables['elems'] = $SPECIAL_ELEMS;
...
ABER: Wenn ich den referenzierten Inhalt bearbeite, wird die Änderung im aufrufenden Inhalt erst nach clear_all_cache wirksam.
Hat jemand eine Idee, woran das liegt bzw. wie man das umgehen kann?
mfG, Michael
- Anmelden oder Registrieren um Kommentare zu schreiben
Ja, das liegt daran, dass
am 14.02.2019 - 15:43 Uhr
Ja, das liegt daran, dass Drupal die Ausgabe cached und manuell verarbeitete Änderungen (hier im preprocess) nicht automatisch für die Invalidierung von Inhalten nutzen kann. Hier musst du selbst sogenannte Cache tags mitliefern. Das sorgt dafür, dass dein paragraph invalidiert wird, wenn der node geändert wurde.
Beispielsweise
<?php
$variables['elems']['#cache']['tags'] = $node->getCacheTags();
?>
Das klappt aber nur, wenn
$variables['elems']
ein ordentliches Drupal Render Array ist und in deinem twig so gerendert wird. Ansonsten müsste der Cache Tag an ein anderes Element angehängt werden.Wenn
$variables['elems']
schon cache-tags besitzt müsstest du diese mergen.Hier findest du eine ausführliche Beschreibung: https://www.drupal.org/docs/8/api/cache-api/cache-tags
EDIT: vielen Dank für den Hinweis,
am 14.02.2019 - 18:01 Uhr
aber so einfach, wie Du geschrieben hast, ging's nicht - wahrscheinlich ist mein $variables['elems'] kein ordentliches Drupal Render Array.
(ich habe in MY_MODUL_CLASS einfach ein Array mit mehreren Elementen erzeugt, und die dann im TWIG mit {{ elems.val_1}} {{ elems.val_2}} usw. eingebaut)
Was ist ein "ordentliches Drupal Render Array"?
Ich hab dann mal gegoogelt und das gefunden, woraus ich mir folgendes zusammengereimt habe:
hook_node_presave() und hook_node_delete() habe ich in die MY_THEME.theme eingebaut, und dann das:
function MY_THEME_invalidate_node(NodeInterface $node) {
$tags = [];
if ($node->getType() == '[CONT-TYPE]'){
$tags[] = '[CONT-TYPE]:' . $node->label; // d.h. den Node-Titel, der ist ja immer da
}
if (!empty($tags)) {
Cache::invalidateTags($tags);
}
}
Das ist hoffentlich richtig so?, oder zu umständlich?, oder gibt's damit möglicherweise andere Probleme?
Michael
EDIT:
Kommando zurück.
Ich weiß nicht, wieso es vorhin ging - jetzt nicht mehr.
Zitat: Was ist ein
am 14.02.2019 - 20:25 Uhr
Was ist ein "ordentliches Drupal Render Array"?
https://www.drupal.org/docs/8/api/render-api/render-arrays
Mit dem oben genannten Code gewinnst du nichts. Da invalidierst du quasi den Node manuell. Das passiert allerdings beim Speichern eines Nodes ohnehin. Das Problem ist, dass die Cache-Tags eben nicht beim rendern des Paragraphs gesetzt sind und damit der Paragraph nicht mit invalidiert wird.
Lange Rede…
Du hast entweder die Möglichkeit die Elemente deiner MY_MODUL_CLASS in ein Drupal Render array zu packen und dieses dann in Twig zu rendern. Andersweitig können die Cache Tags auch auf andere Elemente gesetzt werden. Diese Elemente müssen halt eben gerendert werden. Da wir dein Twig-File nicht kennen, wissen wir nicht welche Elemente dort gerendert werden.
Wenn du beispielsweise im Paragraph Twig file
{{ content }}
renderst, kannst du das Cache-Tag folgendermaßen setzen.<?php
$cache_tags = isset($variables['content']['#cache']['tags']) ? $variables['content']['#cache']['tags'] : [];
$variables['content']['#cache']['tags'] = \Drupal\Core\Cache\Cache::mergeTags($cache_tags, $node->getCacheTags());
?>
Zitat:wissen wir nicht
am 15.02.2019 - 13:05 Uhr
wissen wir nicht welche Elemente dort gerendert werden
Ich hatte in meiner MY_MODUL_CLASS die Elemente einfach in ein Array geschrieben und diese dann im paragraph--SPECIAL-TEASER.html.twig mit html-tags ausgegeben:
z.B. so:
<div class="title"><a href="{{ elems.url }}">{{ elems.title }}</a></div>
Jetzt habe ich die Elemente gleich in einen HTML-String geschrieben und diesen in MY_THEME_preprocess_paragraph(&$variables) als $variables['content']['#markup'] zugewiesen.
Mit den zwei Zeilen für die Cache-Tags funktioniert es jetzt.
kint($variables['content']['#cache']['tags']); gibt dann:
$args array(1)
→array(1)
string(6) "node:9"
Aber noch eine Frage: Wenn ich das richtig verstehe, wird der Paragraph jetzt bei jedem Aufruf neu gecached.
Sollte das nicht besser nur dann passieren, wenn der referenzierte Node modifiziert wird?
Vielen Dank für die geduldige Hilfe,
Michael
Ja. Das ist richtig so. Du
am 16.02.2019 - 15:54 Uhr
Ja. Das ist richtig so. Du solltest aber nochmal schauen, ob es vorher nicht schon Cachetags für das Element gab. Wenn ja, musst du sie zusammenführen.
Der Paragraph wird so nicht bei jedem Aufruf neu gecached. Es wird immer die gecachte Variante ausgeliefert. Nur im Fall, dass du den Paragraph selbst aktualisierst oder den Node, den du als Cachetag mitgegeben hast wird der Paragraph beim nächsten Aufruf neu generiert und neu gecached und fortan wird wieder nur die gecachte Variante ausgeliefert.