Lavorare con il database in Drupal 7 – Lezione 6 – Modifica dinamica delle query (hook_query_alter)
Una caratteristica importante delle query dinamiche di selezione in Drupal è la possibilità per altri moduli di modificare una query “al volo”. Ciò consente ad altri moduli di aggiungere istruzioni personalizzate alla query, influenzando così il suo comportamento o applicando modifiche durante l’esecuzione, ad esempio per definire restrizioni di accesso ai nodi. Esistono tre componenti principali per la modifica dinamica delle query: tagging, meta data e hook_query_alter().
Tagging
Qualsiasi query di selezione dinamica può essere “taggata” con una o più stringhe. Questi tag servono a identificare il tipo di query, in modo che sia possibile riconoscerla in seguito e applicare determinate azioni. I tag devono essere in formato alfanumerico minuscolo, seguendo le stesse regole delle variabili PHP. Per aggiungere un tag a una query, si utilizza il metodo addTag():
<?php $query->addTag('node_access'); ?>
Per verificare se una query ha un determinato tag, sono disponibili tre metodi:
<?php // Restituisce TRUE se la query ha il tag specificato. $query->hasTag('example'); // Restituisce TRUE se la query ha tutti i tag specificati. $query->hasAllTags('example1', 'example2'); // Restituisce TRUE se la query ha almeno uno dei tag specificati. $query->hasAnyTag('example1', 'example2'); ?>
I metodi hasAllTags() e hasAnyTag() accettano più parametri e il loro ordine non è importante. L’uso dei tag è semplice, e Drupal fornisce già diversi tag predefiniti. Ecco alcuni esempi:
- node_access
- La query deve applicare restrizioni di accesso ai nodi.
- translatable
- La query deve includere contenuti traducibili.
- term_access
- La query deve applicare restrizioni di accesso sui termini di tassonomia.
- views
- La query è creata o modificata dal modulo Views.
Meta data
Le query possono anche contenere meta data (metadati) associati. Questi forniscono informazioni aggiuntive utili per la modifica “al volo” della query. I metadati possono essere qualsiasi tipo di valore PHP, associato a una chiave stringa.
<?php $node = node_load($nid); // ... Creazione dell'oggetto $query. $query->addMetaData('node', $node); ?>
I metadati non hanno un effetto diretto sull’oggetto della query: esistono solo per fornire informazioni supplementari a hook_query_alter(). Sono utilizzati principalmente in combinazione con i tag. Per accedere ai valori memorizzati nei metadati, si usa il metodo getMetaData():
<?php $node = $query->getMetaData('node'); ?>
Se non ci sono metadati associati a quella chiave, verrà restituito NULL.
hook_query_alter()
Tag e meta data di per sé non modificano la query. Servono invece come strumenti informativi per hook_query_alter(), che è in grado di modificare dinamicamente un oggetto query di selezione. Tutte le query dinamiche vengono passate a questo hook prima dell’esecuzione, cioè subito prima che vengano compilate. Questo dà ai moduli la possibilità di manipolare la query in qualsiasi modo. hook_query_alter() riceve un solo parametro: l’oggetto query.
<?php /** * Implementazione di hook_query_alter(). */ function example_query_alter(QueryAlterableInterface $query) { // ... } ?>
È anche possibile limitare le modifiche solo alle query con un determinato tag, implementando hook_query_TAG_NAME_alter(). Ad esempio, il seguente codice verrà eseguito solo per le query con il tag node_access:
<?php function example_query_node_access_alter(QueryAlterableInterface $query) { // ... } ?>
Ci sono due osservazioni importanti riguardo a hook_query_alter():
- Il parametro
$query
non deve essere passato per riferimento. Poiché si tratta di un oggetto, in PHP 5 e versioni successive viene sempre passato per riferimento implicito. L’hook non restituisce alcun valore. - Il tipo del parametro è definito esplicitamente come QueryAlterableInterface. Questa tipizzazione fornisce maggiore sicurezza, impedendo di passare tipi di variabili errati, e garantisce compatibilità futura anche con altri tipi di query oltre a SelectQuery.
hook_query_alter() può eseguire qualsiasi azione sull’oggetto query, a eccezione dell’esecuzione stessa, poiché ciò causerebbe un loop infinito. Può utilizzare i tag e i metadati associati alla query per determinare quale azione intraprendere. Gli sviluppatori possono anche usare metodi aggiuntivi dell’oggetto query per aggiungere campi, join, condizioni, ordinamenti e così via, oppure applicare restrizioni di accesso ai dati. È perfino possibile rimuovere o modificare parti della query originale direttamente tramite l’hook.
<?php $fields =& $query->getFields(); $expressions =& $query->getExpressions(); $tables =& $query->getTables(); $order =& $query->getOrderBy(); $where =& $query->conditions(); $having =& $query->havingConditions(); ?>
È importante notare che questi valori vengono restituiti per riferimento, quindi l’hook di alterazione accede direttamente agli stessi dati interni della query. Tutti i metodi sopra restituiscono array, le cui strutture sono descritte nella documentazione di SelectQuery nel file includes/database/select.inc.