Richtiges Cachen mit pi_base

ein Artikel von Elmar Hinz, aus dem Original ins Deutsche übersetzt

zuerst die Lösung

PHP
class tx_myExtension extends tslib_pibase{
  var  $pi_checkCHash = TRUE; // if this is a USER plugin
  var  $this->pi_USER_INT_obj; // we don't set it here
  ...
  function someFunction(...){
    ...
    // -----------------------------------------------------------------------------------
    // link to USER
    // -----------------------------------------------------------------------------------
    $cache = 1;
    $this->pi_USER_INT_obj = 0;
    // -----------------------------------------------------------------------------------
    $label = 'Link to USER plugin';  // the link text
    $overrulePIvars = array( ... the parameters we need to send to the target plugin .... );
    $clearAnyway=1;    // the current values of piVars will NOT be preserved
    $altPageId=33;      // ID of the target page, if not on the same page
    $link = $this->pi_linkTP_keepPIvars($label, $overrulePIvars, $cache, $clearAnyway, $altPageId);
    ...
    // -----------------------------------------------------------------------------------
    // link to USER_INT
    // -----------------------------------------------------------------------------------
    $cache = 0;
    $this->pi_USER_INT_obj = 1;
    // -----------------------------------------------------------------------------------
    $label = 'Link to USER_INT plugin';  // the link text
    $overrulePIvars = array( ... the parameters we need to send to the target plugin .... );
    $clearAnyway=1;    // the current values of piVars will NOT be preserved
    $altPageId=33;      // ID of the target page, if not on the same page
    $link = $this->pi_linkTP_keepPIvars($label, $overrulePIvars, $cache, $clearAnyway, $altPageId);
    ...
  }
}

Diskussion

Die Konfiguration für die Linkfunktionen könnte eine einfachere API haben. Es gibt vorallem einen Punkt in der tslib_pibase - ich bezeichne es als einen kleinen Bug - der wohl für die ganze Verwirrung verantwortlich ist.  Es ist nicht falsch, die tslib_pibase zu benutzen, aber es macht das Handling des Caches deutlich komplizierter. Das belegen auch dutzende von Extensions mit suboptimalen Cache im TER. Lasst uns lernen wie man damit umgeht, um ein besseres TER zu erlangen.

Hinweis: Es ist nicht leicht den Bug zu beseitigen, da die Core-Entwickler befürchten, die Abwärtskompatibilität zu verlieren.

Scenario

Wir wollen eine typische Anforderung betrachten, eine Suchform, eine Ergebnisliste und viele Detailansichten. Sicherlich willst Du die Detailseiten gecachet und durchsuchbar haben, aber die Form und die Ergebnisliste sollen nicht gecachet sein. Aber wie ?

Wenn Du eine Extension über den Kickstarter erstellst, musst Du Dich für ein USER-Objekt (gecachet) oder ein USER_INT-Objekt (nicht gecachet) entscheiden. Aber für unser gewähltes Scenario brauchen wir beides. Das ist ganau das Problem.

Ein Anfänger wird sich sicherlich für die USER_INT-Variante entscheiden. Die Detailseiten werden dann nicht gecachet, das ist schlecht für die Performance. Die Seiten werden auch nicht von der Suche indiziert.
Entscheidet er sich hingegen für die USER-Variante, so das die Suchform erst funktioniert, wenn er den no_cache-Parameter hinzufügt (auf eine von mehreren möglichen Arten). Das ist schlecht, dadurch wird die Seite bei jeder Such-Anfrage neu gerendert, natürlich ein Performance-Killer.

Nimm 2

Ich kenne zwei Alternativen, um diese Herausforderung zu lösen. Der einfache Weg ist der Einsatz von zwei Plugins statt einem, natürlich innerhalb der selben Extension. Dieser Weg wurde in diesem Artikel erklärt.

Fortgeschrittene Programmierer mögen sich für einen USER/USER_INT-Schalter im selben Plugin entscheiden. Dieser USER/USER_INT-Schalter  (auch möglich als COA/COA_INT) wurde zuerst vom Typoscript-Guru Jo Hasenau in der Newsgroup vom Extension Coordination Team (ECT) vorgeschlagen. Mittlerweile habe ich diese Idee erfolgreich nachvollzogen und werde es in zukünftigen Projekten einsetzen. Diese fortschrittliche Technik wird ebenso Inhalt eines folgenden Artikels.
Hier in Jo's Original Test-Setup
Artikel auf dieser Seite

Wesentliches über Cache

no_cache

Es gibt mehrere Wege, den Parameter no_cache=1 zu setzen. Wie auch immer ist die Benutzung dieses Parameters nicht empfohlen und  solte nur in Entwicklungs- oder Testumgebung genutzt werden. Der Effekt dieses Parameters ist, das die ganze Seite (nicht nur das Plugin) bei jedem Aufruf neu gerendert wird. Sie wird weder vom Cache gelesen noch in diesem gespeichert. Das kostet eine Menge Resourcen und bietet eine schlechte Performance.

USER_INT

Dieses Objekt wird nie gecachet, aber die Seiten, in denen es sich befindet, werden normalerweise gecachet. Weil ein USER_INT-Objekt nie gecachet wird, braucht es keine verschiedenen Versionen der Seite.

USER

Die Ausgabe dieses Objektes wird mit der kompletten Seite gecachet, wenn alles sauber konfiguriert ist. Da die Ausgabe dynamisch erfolgt, ergeben sich mehrere Varianten jeder dieser Seiten. Diese Unterschiede werden durch unterschiedliche Urlparameter beim Aufruf der Seite bestimmt.

Die variable $pi_checkCHash sollte immer gesetzt werden, wenn wir das USER-Objekt benutzen, um das cachen zu ermöglichen.

  • var $pi_checkCHash = TRUE;

Links zu USER und zu USER_INT

Nun kommen wir zum Höhepunkt dieser kurzen Einführung über richtiges cachen. Wir haben bereits gelernt, wie wichtig die Link-Parameter sind um zu den verschiedenen Varianten der Seite mit USER-Objekt zu kommen. Nun, welche Parameter sind dafür verantwortlich, die die Linkerzeugung mit den pi_base-Funktionen beeinflussen?

  • der Funktionsparameter $cache
  • die Object-Variable $this->pi_USER_INT_obj

Der Grund, warum wir 2 verschiedene Parameter für diese einfache Aufgabe haben, ist eher geschichtlicher als logischer natur. Nimm es wie es ist und lerne, damit umzugehen. Für unsere Anwendung arbeiten wir mit einem Paar von USER und USER_INT-Objekten.

Abhängig vom Zielobjekt benötigen wir besondere Arten der Linkerzeugung. Ich wiederhole: Es ist abhängig vom Zielobjekt, nicht vom Quellobjekt. Es können Links zum selben Objekt sein (Ergebnislisten-Links). Dann ist das Zielobjekt identisch mit dem Quellobjekt.

cHash links zu USER objects

Links zu einem USER-Objekt brauchen einen cHash, wenn Du willst, das das Zielobjekt gecachet wird. Der cHash ist eine Versicherung, das der Aufruf gültige Parameter besitzt und die Datenbank in der Lage ist, die gewünschte Ansicht zu cachen. Um dieses zu erreichen musst Du folgendes setzen:

  • $cache =1
  • $this->pi_USER_INT_obj = 0

Einfache Links zu USER_INT-Objekten

USER_INT Objekte werden niemals gecachet. So würde es auch keinen Sinn machen, sie mit einem cHash aufzurufen. Obwohl dieses keinen Sinn machen würde, kann man den cHash für diesen Fall verhindern.

  • $cache =0
  • $this->pi_USER_INT_obj = 1

Zusammenfassung

  1. Wir haben gesehen, das es normalerweise nicht ausreicht, nur mit einem Plugin zu arbeiten, wenn wir eine Kombination von gecachten und ungecachten Seiten mit einer Anwendung benötigen. Wir brauchen mindestens 2 Plugins, was zur Folge hat, das der Benutzer der Extension 2 Plugins einfügen und konfigurieren muss.
  2. Wir haben gelernt, das die Art der Linkerzeugung nicht von dem Quellobjekt sondern vom Zielobjekt abhängt.
  3. Der Clou des Ganzen: die Objekt-Variable $this->pi_USER_INT_obj ist keineswegs statisch, wie ihr Name und ihr Typ es impliziert. Sie muss auf den richtigen Wert gesetzt werden, und dieses vor der jeweiligen Linkerzeugung, abhängig vom Zielobjekt.

Ich hoffe, das diese kleine Zusammenfassung der Typo3-Gemeinde helfen wird, besser Cache-fähige Extensions zu erstellen.

Elmar

P.S.

Man kann USER- oder USER_INT-Objekte im TS-Template erzeugen.

Man kann ebenso folgende Funktion benutzen: t3lib_extMgm::addPItoST43(…)
Abhängig vom letzten Parameter wird entschieden, welches Objekt erzeugt wird (1=USER, 0=USER_INT).

6 Kommentare
#6 Johannes schrieb am 13.01.2011 18:34

Leider funktioniert die obere Beschreibung nicht, zumindest nicht bei meinem System unter TYPO3 4.4.6.

Was aber auf funktioniert ist folgender Teil TypoScript, den ich für die lokale Extension test_cache geschrieben hatte:

 

[globalVar = GP:tx_testcache_pi1|nichtsuchen = 1]

tt_content.list.20 = CASE

tt_content.list.20 {

key.field = list_type

test_cache_pi1 = USER_INT

test_cache_pi1 {

includeLibs = typo3conf/ext/test_cache/pi1/class.tx_test_cache_pi1.php

userFunc = tx_testcache_pi1->main

}

}

[end]

#5 Simon schrieb am 20.04.2010 13:17

Hallo.

 

Habe eine Referenzliste bei der ich mir am Caching die Zähne ausbeisse.

 

Habe dafür 2 Extensions geschrieben, eine für die Navi und eine für eine Listen- bzw. Detailansicht der Referenzen.

 

Beide werden über die $_GET Parameter gesteuert.

 

Jetzt habe ich das Problem, dass er alle Links aus der Navi problemlos cachet und alle Detailseiten nicht. In beiden Extensions erzeuge ich die Links genau gleich über Typolink mit cHash.

 

An den Parametern glaube ich nicht, dass es liegt - die der Navi sehen z.B. so aus:

domain.de/index.php

Die in der Liste, die zum Detail führen, sehen so aus:

domain.de/index.php

 

Ich befürchte, dass meine Frage viel zu allgemein ist, aber wenn jemand einen Tip hätte wäre ich sehr dankbar.

 

Grüße

Simon

#4 martin krung schrieb am 30.11.2009 17:20

danke, das war sehr hilfreich

 

es hat fehler im code, wahrscheinlich wegen dem parsing der code darstellung.

 

$this-pi_linkTP_keepPIvars(...

 

es sollte natürlich heissen:

 

$this->pi_linkTP_keepPIvars(...

#3 Jonas schrieb am 29.09.2009 14:07

Danke für diesen super Artikel! Caching ist wirklich ein Thema in dem viele Extensentwickler nachholbedarf haben.

 

Kennst Du die Möglichkeit via TypoScript Condition anhand eines bestimmten Parameters auf USER_INT umzustellen?

 

Dies ist extrem praktisch wenn man in einem piX hauptsächlich gecachten Inhalt zeigt, aber z.B. ein einzelnes Formular als USER_INT interpretiert werden soll...

 

Hier wird oft nocache verwendet, oder mittels kaputtem cHash nocache erzwungen, was aber performance technisch viel viel viel schlechter ist als USER_INT.

#1 Sven schrieb am 17.04.2008 12:42

Wie kann ich denn kontrollieren ob das Caching korrekt funktioniert? Ich versuche es einzubinden, sehe aber nicht ob es funzt...

Wäre cool, wenn du mir da weiterhelfen könntest oder das Tutorial noch ein bisschen erweiterst :-)

Danke!

#2 steffen schrieb am 17.04.2008 13:00

Lösche allen cache, öffne phpmyadmin, besuch die Seite im FE. Refresh die Ansicht in phpmyadmin. Wurde ein cache-Eintrag erzeugt, wurde die Seite gecacht, sonst nicht.

einen Kommentar schreiben
Typo3