Abfragen auf Relationen in Silverstripe in den Cache auslagern

In Silverstripe arbeitet man für gewöhnlich viel mit Objekten, die über Relationen miteinander verknüpft sind. Diese Art der Programmierung ist sehr angenehm, bringt aber auch den Nachteil mit sich, dass komplexe Beziehungen über mehrere Objekte die Performance beeinträchtigen können.

Aus diesem Grund bietet Silverstripe einen sehr einfach benutzbaren Cachingmechanismus an, der im folgenden beschrieben wird.

 

 Beispiel zum Einbau des Caches

 

Das Ausgangsobjekt

Angenommen, wir haben ein Objekt "MotherOfAllAttachments", das hunderte von Anhängen (Attachments) hat. Um die zugeordneten Attachments zu bekommen, benutzt man folgenden Aufruf:

$motherOfAllAttachments = DataObject::get_by_id(
'MotherOfAllAttachments',
1
);
$attachments = $motherOfAllAttachments->Attachments();

Hier holen wir uns zuerst über "DataObject::get_by_id" eine Objektinstanz der Klasse "MotherOfAllAttachments", die über Daten verfügt; der Einfachheit halber sei hier vorausgesetzt, dass es eine solche Instanz mit der ID 1 gibt.

Anschließend greifen wir auf die Relation "Attachments" zu, mit der wir alle zugeordneten Attachments bekommen.

 

Eine neue Methode zum Abfangen der Abfrage auf die Relation

Dieser Aufruf kann bei vielen Attachments zu Performanceproblemen führen, weshalb es sich anbietet, das Ergebnis nach dem ersten Aufruf in den Cache zu legen.

Dazu schreibt man einfach eine neue Methode in der Klasse "MotherOfAllAttachments", die genau das erledigt:

public function getAttachments() {
      $cachekey = 'Attachments'.$this->ID;
      $cache       = SS_Cache::factory($cachekey);
      $result     = $cache->load($cachekey);

      if ($result) {
              $result = unserialize($result);
      } else {
              $result = $this->Attachments();
              $cache->save(serialize($result));
      }

      return $result;
}

Hier erzeugen wir zuerst einen Bezeichner ($cachekey), unter dem die Daten in den Cache gelegt und wiederhergestellt werden können. Da die Abfrage sich auf das Objekt "MotherOfAllAttachments" bezieht, benutzen wir dessen ID zur eindeutigen Identifizierung der Cache-Datei.

Anschließend holen wir uns anhand des eben erzeugten Bezeichners ein Cache-Objekt; dieses wird über eine Factory-Methode erzeugt, der als Parameter der Bezeichner übergeben wird.

Den gleichen Bezeichnis verwenden wir, um die Inhalte des Cache-Objekts über "$cache->load" zu laden.
Wenn dieser Aufruf ein Ergebnis liefert, erzeugen wir über die PHP Methode "unserialize" PHP-Objekte aus den Rohdaten. Andernfalls holen wir die Ergebnisse aus der Datenbank und speichern sie im Cache. Da es sich um Objekte handelt, müssen diese über die PHP Methode "serialize" serialisiert werden, bevor sie in die Cache-Datei gelegt werden.

Bei diesem Beispiel sollte der Zugewinn an Performance noch relativ niedrig sein. Werden jedoch Relationen in der zweiten, dritten oder noch tieferen Ebene benötigt, ist eine deutliche Steigerung messbar.

 

 Beispiel zur Anwendung des Caches

 

Aufruf aus Templates

Wird in einem Template auf die Relation "Attachments" des Objekts "MotherOfAllAttachments" zugegriffen, müssen wir nichts ändern. Durch die Silverstripe "Magie" werden Template-Aufrufe auf Relationen durch gleichnamige Methoden mit dem Präfix "get" abgefangen.

Der Aufruf

<% control Attachments %>
<% end_control %>

ist also gleichwertig zu dem Aufruf

<% control getAttachments %>
<% end_control %>

 

Aufruf aus Controllern und DataObjects

Diese Magie funktioniert leider (oder zum Glück) nicht im PHP-Code der Controller und DataObjects. Das heißt, dass wir dort den Aufruf

$attachments = $motherOfAllAttachments->Attachments();

ersetzen müssen durch

$attachments = $motherOfAllAttachments->getAttachments();

 

 Links

Dokumentation der Methode "serialize" auf de.php.net:
http://de.php.net/manual/de/function.serialize.php

Dokumentation der Methode "unserialize" auf de.php.net:
http://de.php.net/manual/de/function.unserialize.php

Dokumentation der Silverstripe Cache Klasse auf api.silverstripe.org:
http://api.silverstripe.org/2.4/sapphire/core/SS_Cache.html

 

Tags: