View based caching - ein HOWTO

1. Einführung

Während einer Diskussion im developers-guide.net Forum wurde die Idee des view based caching geboren. Ausgelöst durch einen Einwurf von Alberto begannen wir über Performance-Optimierungen und verschiedene Caching-Methoden zu sprechen. Am Ende der Diskussion kamen die Beteiligten darüber ein, dass das Caching von einzelnen Teilen einer Applikation ein effektives Mittel für die Steigerung der Performance ist.

Dies kann durch eine auf cURL basierende Lösung, die von Alberto vorgestellt wurde oder durch view based caching erreicht werden. Der Vorteil von view based caching ist, dass die Applikation selbst nicht an die Cache-Strategie angepasst werden muss. Dieser Artikel beschreibt die technische Idee und die Umsetzung mit den Mitteln des Adventure PHP Framework.

2. Views?

Um die Idee besser verdeutlichen zu können, zunächst ein paar Worte zum Thema Views. In APF-Terminologie sind Views nichts anderes als Templates, die von anderen eingebunden werden. Ein Webseiten-Layout, das importdesign-Tags beinhaltet definiert bereits Views. Wie im Kapitel Page-Controller beschrieben wird, erzeugt der Page-Controller einen Objektbaum aus den bekannten Tags in einem Template.

Jeder Tag besteht dabei aus seiner Definition - etwa

APF-Template
<my:tag attr1="value1" attr2="value2" />

- und der Implementierung der Funktion des Tags, sog. TagLibs. Jeder Tag muss das folgende Interface implementieren:

PHP-Code
class MyTag extends Document { public function onParseTime() { } public function onAfterAppend() { } public function transform() { } }

Details zur Implementierung von TagLibs und welche Funktionalität sich hinter den einzelnen Methoden versteckt bzw. verstecken müssen, kann im Tutorial Implementierung von Tags nachgelesen werden.

Wie kann diese Information nun genutzt werden um view based caching zu implementieren? Ganz einfach: dank der generischen Page-Controller-Implementierung kann der Entwickler eigene Taglibs erzeugen, die die bisherige Funktion einer Taglib erweitern. Das bedeutet, dass der bisherige Template-Include-Mechanismus einfach um eine Caching-Funktion ergänzt werden muss - die Basis von view based caching!

3. Implementierung

3.1. Let's get started

Wie im Kapitel Standard TagLibs beschrieben ist, kann der <core:importdesign />-Tag dazu verwendet werden, ein Template als Kind des aktuellen DOM-Knoten einzubinden. Hierzu muss lediglich der Namespace des Templates und dessen Namen in den Attributen des Tags spezifiziert werden. Wie bereits weiter oben bemerkt, kann dieser Tag dazu verwendet werden, um einen View innerhalb eines Layout-Templates zu definieren. Ein View kann dabei z.B. den Header, Footer oder die Navigation einer Seite beinhalten. Da wir nur den Inhalt von speziellen Views einer Seite cachebar gestalten wollen, kann diese TagLib als Basis genutzt werden.

Um das zu verdeutlichen, ist in der folgenden Codebox die Implementierung des Tags dargestellt:

PHP-Code
class ImportTemplateTag extends Document { public function onParseTime(){ $namespace = trim($this->getAttribute('namespace'); $template = trim($this->getAttribute('template'); $context = $this->getAttribute('context'); if($context !== null){ $this->context = trim($context); } $language = $this->getAttribute('language'); if ($language !== null) { $this->setLanguage($language); } $incParam = $this->getAttribute('incparam'); if ($incParam === null) { $incParam = 'pagepart'; } ... $this->loadContentFromFile($namespace, $template); $this->extractDocumentController(); $this->extractTagLibTags(); } }

Die eigentliche Funktion des Tags besteht darin, die Attribute des Tags zu analysieren, den Inhalt des gewünschten Templates zu laden und den Inhalt zu analysieren. Hierzu werden die Methoden extractDocumentController() und extractTagLibTags() genutzt, die bereits im der Klasse Document definiert sind. Es fehlt also nur noch der Caching-Part!

3.2. Der CacheManager

Das Framework beinhaltet mit dem CacheManager eine flexible Caching-Komponente mit verschiedenen Backends. In diesem Fall ist jedoch ein einfacher Text-Cache-Mechanismus ausreichend, der im Kapitel Text-Cache-Provider der CacheManager-Dokumentation beschrieben ist. Um diesen verwenden zu können, ist es notwendig, eine Konfiguration anzulegen. Diese hat gemäß der Dokumentation die folgende Gestalt:

APF-Konfiguration
[view_based_cache] Provider = "APF\tools\cache\provider\TextCacheProvider" Active = "true" BaseFolder = "/path/to/my/cache/base/folder" Namespace = "view\one"

Zum Schreiben und Lesen des Caches kann der folgende Code verwendet werden:

PHP-Code
// get the cache manager $cMF = &$this->getServiceObject('APF\tools\cache\CacheManagerFabric'); $cM = &$cMF->getCacheManager('view_based_cache'); // calculate cache key $cacheKey = /* ... */; // read the cache $cacheContent = $cM->getFromCache($cacheKey); // write to the cache if($cacheContent === null){ $cacheContent = /* generate content */; $cM->writeToCache($cacheKey,$cacheContent); }

3.3. Endmontage

Um den Inhalt eines Views cachen zu können, werden nun die beiden Teile aus Kapitel 3.1 und 3.2 zusammengefügt:

PHP-Code
namespace EXAMPLE\vbc\pres\taglib; use APF\core\pagecontroller\ImportTemplateTag; use APF\tools\cache\CacheManagerFabric; use APF\tools\cache\key\SimpleCacheKey; class CachedImportTemplateTag extends ImportTemplateTag { private $cacheContent = null; public function onParseTime() { // gather tag configuration $cacheConfig = $this->getAttribute('cacheconfig'); $cacheKey = new SimpleCacheKey($this->getAttribute('cachekey')); // get the cache manager /* @var $cMF CacheManagerFabric */ $cMF = & $this->getServiceObject('APF\tools\cache\CacheManagerFabric'); $cM = & $cMF->getCacheManager($cacheConfig); // clear the cache if desired if (isset($_REQUEST['clearcache']) && $_REQUEST['clearcache'] == 'true') { $cM->clearCache($cacheKey); } // try to read from the cache $this->cacheContent = $cM->getFromCache($cacheKey); // check if the document was cached before. If not // execute the parent's onParseTime() if ($this->cacheContent === null) { parent::onParseTime(); } } public function transform() { // generate the node's output or return the cached content if ($this->cacheContent === null) { // gather tag configuration $cacheConfig = $this->getAttribute('cacheconfig'); $cacheKey = new SimpleCacheKey($this->getAttribute('cachekey')); // get the cache manager /* @var $cMF CacheManagerFabric */ $cMF = & $this->getServiceObject('APF\tools\cache\CacheManagerFabric'); $cM = & $cMF->getCacheManager($cacheConfig); // generate output and cache it $output = parent::transform(); $cM->writeToCache($cacheKey, $output); // return the tag's output return $output; } return $this->cacheContent; } }

Wie im Code-Block zu sehen ist, wurden die Methoden onParseTime() und transform() um das Cache-Handling ergänzt. Um innerhalb der Klasse erkennen zu können, ob der Inhalt aus dem Cache gelesen werden kann, wurde die private Variable cacheContent eingeführt. Bitte beachten Sie, dass der Code teilweise redundant vorhanden ist. Diese wurde jedoch nur zu Demonstrationszwecken so gewählt.

4. Anwendung

Die Anwendung der Caching-TagLib unterscheidet sich kaum von der Verwendung des <core:importdesign /> Tags. Der einzige Unterschied ist, dass eine Konfigurationssektion für den CacheManager existieren muss:

APF-Template
<core:addtaglib class="EXAMPLE\vbc\pres\taglib\CachedImportTemplateTag" prefix="cache" name="importdesign" /> <cache:importdesign namespace="VENDOR\..\namespace" template="my_template" />

5. Zusammenfassung und Ausblick

Dank der Page-Controller-Implementierung des APF ist es sehr einfach, view based caching auf Basis von TagLibs zu implementieren. Um eine wiederverwendbare und in allen Bereichen einsetzbare TagLib zu erhalten, sollte die in Kapitel 3.3 abgedruckte Klasse noch um ein oder zwei weitere Attribute erweitert werden, die die Cache-Konfiguration und den Cache-Schlüssel übergeben. Das stellt sicher, dass die TagLib innerhalb der Applikation einfacher an unterschiedlichen Stellen gleichzeitig genutzt werden kann.

Beim Thema Cache-Verwaltung hat der Entwickler zwei Möglichkeiten: manuelles Leeren des Caches oder der Einsatz eines Caching-Backends, das Cache-Lebenszeit unterstützt. Falls die Notwendigkeit besteht, sich selbst erneuernden Cache zu haben, so kann der CacheManager wie im Kapitel Erweiterung aufgezeigt erweitert werden.

6. Download

Um das oben gezeigte Konzept lokal ausprobieren zu können, habe ich eine Beispiel-Implementierung für PHP 5 erstellt, die die in Kapitel 5 besprochenen Optimierungen bereits enthalten. Um das Beispiel lokal auszuführen, bitte die Datei apf-vbc-example-* von der Downloads-Seite herunterladen und im DOCUMENT_ROOT des Webservers entpacken. Bitte beachten Sie dabei, dass der Benutzer, unter dem der Webserver ausgeführt wird, Schreibrechte auf das aktuelle Verzeichnis besitzt. Falls ein anderer Ordner als Cache-Basis-Ordner verwendet werden soll, einfach die Datei /APF/config/tools/cache/sites/vbc/DEFAULT_cacheconfig.ini anpassen.

Kommentare

Möchten Sie den Artikel eine Anmerkung hinzufügen, oder haben Sie ergänzende Hinweise? Dann können Sie diese hier einfügen. Die bereits verfassten Anmerkungen und Kommentare finden Sie in der untenstehenden Liste.
Für diesen Artikel liegen aktuell keine Kommentare vor.