9.2. 在 Drupal 中,“hook” 是什么意思?
本文旨在让您熟悉 Drupal,我们将在添加自定义模块后编写代码示例。
Drupal 并不是一个完美无缺、无需改动的单体系统。客户经常会要求在网站上添加某些功能。为了在保持 Drupal 核心代码完整的同时扩展其功能,我们使用模块(module)。模块化系统使得 Drupal 的功能得以扩展。但如果我们想要扩展一个现成的第三方计数器模块怎么办?当然,我们可以在 drupal.org 上创建一个 issue,申请添加我们需要的功能,也许一个月、两个月……甚至一年或两年后,才能在该模块中获得我们所需的功能。但我们也可以换一种方式——自己编写需要的代码。为了扩展 Drupal 附加模块及其自身的功能,我们会在自己的模块中使用钩子(hook)和插件(plugin)。
核心思想是:我们不需要直接维护 Drupal 核心或附加模块的代码,这样能在开发成本上节省大量支出。为了能够轻松更新 Drupal 核心与模块代码,绝不能修改核心代码或第三方模块。否则,当模块或核心升级时,您的所有更改都会被覆盖。
为了实现模块与 Drupal 核心之间,以及模块与模块之间的交互,Drupal 拥有一个钩子系统(hook system)。钩子本质上是一个函数回调(callback),即当代码执行到某个钩子时,会调用我们在模块中定义的对应函数代码。通过这种方式,我们可以在任何时候处理用户数据、菜单、分类法、以及不同内容类型的节点(如修改、添加、删除或加载显示等)。Drupal 8 中的钩子数量相当多,但比 Drupal 7 少了一些,因为许多钩子被 Symfony 组件替代实现:
https://api.drupal.org/api/drupal/core%21core.api.php/group/hooks/8.2.x
如果查看 Drupal 7 的版本,你会发现需要滚动很久:
https://api.drupal.org/api/drupal/includes%21module.inc/group/hooks/7.x
但这并不意味着 Drupal 8 功能减弱了,只是原本通过 hook 实现的功能,在 Drupal 8 中需要通过添加合适的插件(plugin)来实现。
如果仔细查看 Drupal 8 中的钩子列表,会发现许多钩子名称结尾是 _alter
,这表示该钩子用于修改变量的值。例如:
hook_form_alter()
— 允许在 Drupal 处理表单时修改表单数组。稍后我们会分析 Drupal 如何通过数组生成表单。要在模块中应用此钩子,与其他钩子一样,我们只需编写如下函数:
function mymodule_form_alter() {
// 修改表单数组
}
我在示例中简化了代码,未写出函数参数或命名空间。现在我们只需理解钩子的工作原理。mymodule
是我们模块的名称,我们将单词 “hook” 替换为模块名,Drupal 会自动识别并执行该函数,从而修改表单数组。
它是如何实现的?在 prepareForm
方法中,会调用另一个 alter()
方法:
$this->moduleHandler->alter($hooks, $form, $form_state, $form_id);
这意味着,每个实现了 hook_form_alter()
的模块都会在此处插入自己的代码。由此可见,如果我们想在 Drupal 中某处插入自定义代码,首先应考虑使用钩子;其次考虑使用插件;只有在确实无法通过插件实现时,才会去修改(打补丁 / hack)模块代码(虽然这通常是不得已的做法)。目前,我们还未遇到需要修改插件的任务,所以接下来让我们学习如何编写自己的模块。