logo

额外区块类型 (EBT) - 全新的布局构建器体验❗

额外区块类型 (EBT) - 样式化、可定制的区块类型:幻灯片、标签页、卡片、手风琴等更多类型。内置背景、DOM Box、JavaScript 插件的设置。立即体验布局构建的未来。

演示 EBT 模块 下载 EBT 模块

❗额外段落类型 (EPT) - 全新的 Paragraphs 体验

额外段落类型 (EPT) - 类似的基于 Paragraph 的模块集合。

演示 EPT 模块 滚动

滚动

在 Drupal 7 中操作数据库 - 第6课 - 动态修改查询(hook_query_alter)

14/10/2025, by Ivan

动态选择查询(SELECT)的一个重要特性是,其他模块可以在运行时修改查询。这允许模块向查询中插入自己的指令,从而影响查询的行为,或在执行时进行修改,例如为节点(node)添加访问权限过滤。实现动态修改查询的机制包括三个部分:tagging(标签)meta data(元数据)hook_query_alter()

Tagging(标签)

任何动态查询都可以添加一个或多个标签(tag)。这些标签用于标识查询类型,使其他模块能够识别并对其进行相应的处理。标签应为小写字母和数字的组合,遵循与 PHP 变量相同的命名规则。要为查询添加标签,请使用 addTag() 方法:

<?php
$query->addTag('node_access');
?>

可以使用以下三种方法来检测查询对象中是否存在标签:

<?php
// 如果查询对象具有指定标签,则返回 TRUE。
$query->hasTag('example');

// 如果查询对象包含所有指定标签,则返回 TRUE。
$query->hasAllTags('example1', 'example2');

// 如果查询对象包含任意一个指定标签,则返回 TRUE。
$query->hasAnyTag('example1', 'example2');
?>

hasAllTags()hasAnyTag() 接受多个参数,参数顺序无关。使用标签非常简单,Drupal 核心和常用模块中已定义了一些标准标签,例如:

node_access
该查询应考虑节点访问权限。
translatable
该查询应包含可翻译字符串。
term_access
该查询应考虑分类术语(taxonomy term)的访问控制。
views
该查询由 Views 模块生成。

Meta data(元数据)

查询还可以附加元数据,用于在运行时提供额外信息。元数据可以是任何 PHP 数据类型,并使用字符串键进行标识:

<?php
$node = node_load($nid);
// 创建查询对象。
$query->addMetaData('node', $node);
?>

元数据本身不会直接影响查询执行,仅作为辅助信息在 hook_query_alter() 中被使用。可以通过 getMetaData() 方法获取已设置的元数据:

<?php
$node = $query->getMetaData('node');
?>

如果未设置对应键的元数据,则返回 NULL

hook_query_alter()

标签(tags)和元数据(meta data)本身不会修改查询,而是为 hook_query_alter() 提供上下文信息。所有动态查询对象在执行 execute() 之前都会触发此钩子,使模块能够在查询编译之前对其进行修改。该钩子接收一个参数——查询对象。

<?php
/**
 * 实现 hook_query_alter().
 */
function example_query_alter(QueryAlterableInterface $query) {
  // ...
}
?>

您还可以通过特定标签过滤,只处理带有指定标签的查询。例如,以下代码仅处理带有 node_access 标签的查询:

<?php
function example_query_node_access_alter(QueryAlterableInterface $query) {
  // ...
}
?>

关于 hook_query_alter() 有两个重要注意事项:

  1. 参数 $query 无需按引用传递。因为它是对象(在 PHP 5 及以上版本中,对象总是按引用传递),因此不需要使用 &。
  2. 参数类型明确指定为 QueryAlterableInterface。这可以防止传入错误类型的参数,同时确保在未来更好的兼容性。

hook_query_alter() 可以对查询对象执行任何操作(除了执行查询本身,否则可能导致无限循环)。该钩子可以利用标签和元数据来判断应采取的修改方式。开发者可以通过查询对象的方法添加字段、连接(join)、条件(condition)等,或控制访问权限等逻辑。以下代码示例展示如何通过引用修改查询结构:

<?php
$fields =& $query->getFields();
$expressions =& $query->getExpressions();
$tables =& $query->getTables();
$order =& $query->getOrderBy();
$where =& $query->conditions();
$having =& $query->havingConditions();
?>

请注意,这些方法返回的值均为引用,这意味着 alter 钩子直接操作的就是查询对象的内部结构。所有这些方法返回数组,其结构定义可参考 includes/database/select.inc 文件中关于 SelectQuery 的文档。