Working with a DB in Drupal 7 - Lesson 6 - Changing a Query on the Fly (hook_query_alter)
An important feature of dynamic SELECT queries is that other modules can alter these queries on the fly. This allows modules to insert their own instructions into a query, influencing its behavior or applying changes during execution—such as enforcing node access permissions. There are three components involved in altering queries on the fly: tagging, meta data, and hook_query_alter()
.
Tagging
Any dynamic SELECT query can be “tagged” with one or more strings. These tags help identify the type of query and can be used to trigger actions based on them. Tags should be alphanumeric, lowercase, and follow PHP variable naming conventions. Use the addTag()
method to add a tag to a query:
addTag('node_access'); ?>
You can check for a tag on a query object using these methods:
hasTag('example'); // TRUE if query has all listed tags. $query->hasAllTags('example1', 'example2'); // TRUE if query has any of the listed tags. $query->hasAnyTag('example1', 'example2'); ?>
hasAllTags()
and hasAnyTag()
both accept multiple arguments regardless of order. Tags are easy to use and several standard tags exist, such as:
- node_access
- This query should enforce node access permissions.
- translatable
- This query includes translatable strings.
- term_access
- This query should enforce taxonomy term access permissions.
- views
- This query is generated by the Views module.
Meta Data
Queries can also carry meta data—arbitrary PHP values attached via string keys. Meta data provides additional information for query alteration.
addMetaData('node', $node); ?>
Meta data has no direct effect on the query object. It exists solely to aid query alteration, especially when used with tags. Access meta data with:
getMetaData('node'); ?>
If the specified key does not exist, NULL
is returned.
hook_query_alter()
Neither tags nor meta data alter the query directly. Instead, they provide context to hook_query_alter()
, which can modify any dynamic SELECT query. This hook is called before execute()
is invoked, just before the query is compiled. It allows modules to manipulate the query however they need.
You can also write a hook that targets a specific tag using hook_query_TAG_NAME_alter()
. For example, this hook handles queries tagged with "node_access":
Two important notes about hook_query_alter()
:
- $query is not passed by reference. Since it's an object in PHP 5+, passing by reference is unnecessary.
- The parameter type is strictly defined as
QueryAlterableInterface
, notSelectQuery
. This ensures future compatibility.
hook_query_alter()
can perform any action on the query object except executing it, to avoid infinite loops. It can use tags and meta data to determine what actions to take. Developers can add fields, joins, conditions, etc., or even strip parts of the original query using the following methods:
getFields(); $expressions =& $query->getExpressions(); $tables =& $query->getTables(); $order =& $query->getOrderBy(); $where =& $query->conditions(); $having =& $query->havingConditions(); ?>
These methods return arrays by reference, allowing the hook to access and modify the query’s internal structure directly. Full documentation for these methods can be found in the SelectQuery
class in includes/database/select.inc
.