Arbeiten mit der Datenbank in Drupal 7 – Lektion 6 – Laufende Änderung von Abfragen (hook_query_alter)
Eine wichtige Eigenschaft dynamischer Select-Abfragen ist die Möglichkeit für andere Module, Abfragen zur Laufzeit zu verändern. Dies erlaubt anderen Modulen, eigene Anweisungen in die Abfrage einzufügen, wodurch das Verhalten der Abfrage beeinflusst oder zur Laufzeit Änderungen vorgenommen werden können, beispielsweise um Zugriffsbeschränkungen für Nodes zu setzen. Es gibt drei Komponenten für die Laufzeitänderung von Abfragen: Tagging, Metadaten und hook_query_alter().
Tagging
Jede dynamische Select-Abfrage kann mit einem oder mehreren Strings „getaggt“ werden. Diese Tags dienen dazu, die Art der Abfrage zu identifizieren und bei der Rückgabe zu erkennen, um bestimmte Aktionen hinzuzufügen. Tags sollten in alphanumerischer Form in Kleinbuchstaben vergeben werden, gemäß denselben Regeln wie PHP-Variablen. Um einer Abfrage ein Tag hinzuzufügen, verwenden Sie die Methode addTag():
<?php $query->addTag('node_access'); ?>
Um zu prüfen, ob ein Tag für ein gegebenes Objekt gesetzt ist, gibt es drei Methoden:
<?php // TRUE, wenn die Abfrage das Tag hat. $query->hasTag('example'); // TRUE, wenn die Abfrage alle angegebenen Tags hat. $query->hasAllTags('example1', 'example2'); // TRUE, wenn die Abfrage mindestens eines der angegebenen Tags hat. $query->hasAnyTag('example1', 'example2'); ?>
Die Methoden hasAllTags() und hasAnyTag() akzeptieren zwei Parameter, deren Reihenfolge egal ist. Tags zu verwenden ist unkompliziert, und es gibt bereits vordefinierte Tags, zum Beispiel:
- node_access
- Diese Abfrage benötigt Node-Zugriffsbeschränkungen.
- translatable
- Diese Abfrage unterstützt Übersetzungen.
- term_access
- Diese Abfrage erfordert Zugriffsbeschränkungen für Taxonomie-Terme.
- views
- Diese Abfrage wurde vom Views-Modul getaggt.
Metadaten
Abfragen können auch Metadaten zugeordnet werden, die zusätzliche Informationen für die Laufzeitänderung liefern. Metadaten können beliebige PHP-Werte mit einem Schlüssel vom Typ String sein.
<?php $node = node_load($nid); // ... Erzeuge ein $query-Objekt. $query->addMetaData('node', $node); ?>
Metadaten haben keine interne Bedeutung und beeinflussen die Abfrage nicht direkt. Sie dienen ausschließlich als Zusatzinformation für die Laufzeitänderung und werden hauptsächlich bei Abfragen mit Tags verwendet. Auf Metadaten kann mit der Methode getMetaData() zugegriffen werden:
<?php $node = $query->getMetaData('node'); ?>
Wenn keine Metadaten mit dem Schlüssel existieren, wird NULL zurückgegeben.
hook_query_alter()
Weder Tags noch Metadaten wirken direkt auf die Abfrage. Beide liefern lediglich Informationen für hook_query_alter(), mit dem beliebige Manipulationen an dynamischen Select-Abfrageobjekten vorgenommen werden können. Alle dynamischen Select-Abfragen, die durch hook_query_alter() übergeben werden, sind direkt vor dem Aufruf von execute() und kurz vor der Kompilierung der Abfrage. Dadurch haben Module die Möglichkeit, die Abfrage beliebig zu manipulieren. hook_query_alter() erhält einen Parameter: das Abfrageobjekt.
<?php /** * Implementierung von hook_query_alter(). */ function example_query_alter(QueryAlterableInterface $query) { // ... } ?>
Es ist auch möglich, nur Abfragen mit einem bestimmten Tag zu bearbeiten, indem man hook_query_TAG_NAME_alter() implementiert. Der folgende Code wird für Abfragen mit dem Tag "node_access" aufgerufen:
<?php function example_query_node_access_alter(QueryAlterableInterface $query) { // ... } ?>
Zwei wichtige Anmerkungen zu hook_query_alter():
- Der Parameter $query wird nicht per Referenz übergeben. Da es sich um ein Objekt handelt, wird dieses in PHP 5 nicht kopiert. Eine Übergabe per Referenz ist daher nicht notwendig. hook_query_alter() gibt keinen Rückgabewert zurück.
- Der Parametertyp ist explizit als QueryAlterableInterface deklariert. Dies bietet besseren Schutz gegen falsche Parameter und gewährleistet Kompatibilität zu künftigen Versionen. Der Typ ist allgemeiner als SelectQuery.
hook_query_alter() kann beliebige Aktionen am Abfrageobjekt durchführen, außer es auszuführen, um Endlosschleifen zu vermeiden. Es kann Tags und Metadaten nutzen, um zu entscheiden, welche Aktionen durchgeführt werden. Entwickler können weitere Methoden auf dem Abfrageobjekt aufrufen, wie Hinzufügen von Feldern, Joins, Bedingungen etc., oder Zugriffsbeschränkungen implementieren, um Daten direkt zu kontrollieren. Sie können auch die ursprüngliche Abfrage modifizieren oder komplett entfernen.
<?php $fields =& $query->getFields(); $expressions =& $query->getExpressions(); $tables =& $query->getTables(); $order =& $query->getOrderBy(); $where =& $query->conditions(); $having =& $query->havingConditions(); ?>
Wichtig ist, dass die Werte per Referenz zurückgegeben werden, sodass der Alter-Hook direkten Zugriff auf die Objektdatenstruktur hat. Alle genannten Methoden liefern Arrays, deren Struktur hauptsächlich in der Dokumentation zu SelectQuery in includes/database/select.inc beschrieben ist.