Drupal的钩子系统
Drupal的很多功能都是可以定制的。以导航菜单为例,blog模块需要在菜单上添加一些功能,comment模块需要在菜单上添加一些功能,我们开发的自定义模块也需要在菜单上添加一些功能。Drupal开发者为了达到这样的扩展目的,设计了钩子系统,导航菜单就是其中一个名为menu的钩子。有了钩子系统,开发人员就可以在blog模块定义一个钩子函数从而实现menu钩子。Drupal要求钩子函数的命名必须要求以模块名开始,以钩子名为后缀。
function block_menu() {
$items['admin/structure/block/manage/%/%'] = array(
'title' => 'Configure block',
'page callback' => 'drupal_get_form',
'page arguments' => array('block_admin_configure', 4, 5),
'access arguments' => array('administer blocks'),
'file' => 'block.admin.inc',
);
$items['admin/structure/block/manage/%/%/configure'] = array(
'title' => 'Configure block',
'type' => MENU_DEFAULT_LOCAL_TASK,
'context' => MENU_CONTEXT_INLINE,
);
$items['admin/structure/block/manage/%/%/delete'] = array(
'title' => 'Delete block',
'page callback' => 'drupal_get_form',
'page arguments' => array('block_custom_block_delete', 4, 5),
'access arguments' => array('administer blocks'),
'type' => MENU_LOCAL_TASK,
'context' => MENU_CONTEXT_NONE,
'file' => 'block.admin.inc',
);
... ...
return $items;
}
module_hook_info()函数查询所有可以实现的钩子,实质上也是使用的钩子方式:
function module_hook_info() {
$hook_info = array();
foreach (module_list() as $module) {
$function = $module . '_hook_info'; // hook_info钩子
if (function_exists($function)) {
$result = $function();
if (isset($result) && is_array($result)) {
$hook_info = array_merge_recursive($hook_info, $result);
}
}
}
// We can't use drupal_alter() for the same reason as above.
foreach (module_list() as $module) {
$function = $module . '_hook_info_alter'; // hook_info_alter钩子
if (function_exists($function)) {
$function($hook_info);
}
}
return $hook_info;
}
自定义的钩子可以在hook_info中注册,也可以不注册。注册的好处是可以为钩子实现人员提供更详细的详细,另外一个目的是可以为钩子分组。例如,定义了很多admin有关的钩子,这些钩子函数我们想把它们单独放在一个PHP文件里面,而不用都挤在模块主文件。
module_implements()函数返回实现某个钩子的所有函数,它用module_list()遍历当前激活的所哟模块:
function module_implements($hook, $sort = FALSE, $reset = FALSE) {
$implementations = &$drupal_static_fast['implementations'];
if (!isset($implementations[$hook])) {
$hook_info = module_hook_info(); // 查询钩子信息
$implementations[$hook] = array();
$list = module_list(FALSE, FALSE, $sort);
foreach ($list as $module) {
// 注意这里额外载入了钩子分组文件
$include_file = isset($hook_info[$hook]['group']) && module_load_include('inc', $module, $module . '.' . $hook_info[$hook]['group']);
// Since module_hook() may needlessly try to load the include file again,
// function_exists() is used directly here.
if (function_exists($module . '_' . $hook)) {
$implementations[$hook][$module] = $include_file ? $hook_info[$hook]['group'] : FALSE;
}
}
// Allow modules to change the weight of specific implementations but avoid
// an infinite loop.
if ($hook != 'module_implements_alter') {
drupal_alter('module_implements', $implementations[$hook], $hook);
}
}
else {
foreach ($implementations[$hook] as $module => $group) {
// If this hook implementation is stored in a lazy-loaded file, so include
// that file first.
if ($group) {
// 注意这里额外载入了钩子分组文件
module_load_include('inc', $module, "$module.$group");
}
// It is possible that a module removed a hook implementation without the
// implementations cache being rebuilt yet, so we check whether the
// function exists on each request to avoid undefined function errors.
// Since module_hook() may needlessly try to load the include file again,
// function_exists() is used directly here.
if (!function_exists($module . '_' . $hook)) {
// Clear out the stale implementation from the cache and force a cache
// refresh to forget about no longer existing hook implementations.
unset($implementations[$hook][$module]);
$implementations['#write_cache'] = TRUE;
}
}
}
return array_keys($implementations[$hook]);
}
module_invoke_all()则调用所有实现某个钩子的所有函数,这是Drupal钩子系统的最外层接口:
function module_invoke_all($hook) {
$args = func_get_args();
// Remove $hook from the arguments.
unset($args[0]);
$return = array();
foreach (module_implements($hook) as $module) {
$function = $module . '_' . $hook;
if (function_exists($function)) {
$result = call_user_func_array($function, $args); // 调用钩子函数
if (isset($result) && is_array($result)) {
$return = array_merge_recursive($return, $result); // 返回结果的处理方式
}
elseif (isset($result)) {
$return[] = $result; // 返回结果的处理方式
}
}
}
return $return;
}
例如,我们要调用menu钩子,简单的调用module_invoke_all()就可以了:
$items = module_invoke_all('menu');
Drupal的钩子系统的更多相关文章
- Docker——基于Docker安装Drupal博客系统
Docker--基于Docker安装Drupal博客系统 向脚本文件追加内容 cat << EOF > build.sh #设置主机名 hostnamectl set-hostnam ...
- Drupal 7.23:函数drupal_alter()注释
/** * Passes alterable variables to specific hook_TYPE_alter() implementations. * * This dispatch fu ...
- drupal node机制理解
[1]根据结构的功能结构的不同,drupal划分为,node,user,comment等不同的结构,他们的结构是不同的.他们可以作为四个不同的抽象类,根据这个抽象类,分别有一套hook函数去控制实现的 ...
- Drupal theme_hook
模板语言和主题引擎 用Drupal的行话来说,主题就是一组负责你站点外观的文件.你可以从http://drupal.org/project/Themes下载第 3方主题,或者你可以自己动手创建一个主题 ...
- PHP钩子机制
什么是钩子 大家想必听过插件,wordpress插件特别多,这个就是用钩子机制实现的. 当代码在运行的过程中,我们预先在运行的几个特殊点里执行一些特殊方法:例如在运行方法(例如Blog::add的ad ...
- 高校应该使用 Drupal 的10大理由
使用 Drupal 已经成为全球顶尖高校中的一种潮流,它已经被全球数以百计的院校选择并应用,无论是哈佛.斯坦福.杜克.布朗.罗格斯.剑桥.耶鲁还是其它众多知名高校,都已经选择 Drupal 作为它们理 ...
- PHP之运用CI用钩子实现URL权限控制————————【Badboy】
<span style="background-color: rgb(247, 252, 255); font-family: Verdana, Arial, Helvetica, s ...
- 谈PHP中的钩子
钩子,英文为hooks.在程序中应用相当广泛,但是究竟什么是钩子呢?本人介绍一下目前本人对钩子的理解和相关心得. 假如有这么一段程序流: function fun(){ funA(); funB(); ...
- [Drupal]主题教程
drupal6和drupal7的主题开发有很大不同,本指南包含了这些不同 drupal7的默认主题是Bartik,6的是Garland drupal的主题系统是如何工作的 这部分内容主要讲述的是dru ...
随机推荐
- HashMap的实现原理 HashMap底层实现,hashCode如何对应bucket?
韩梦飞沙 韩亚飞 313134555@qq.com yue31313 han_meng_fei_sha 数组和链表组合成的链表散列结构,通过hash算法,尽量将数组中的数据分布均匀,如果has ...
- Minimum Height Trees -- LeetCode
For a undirected graph with tree characteristics, we can choose any node as the root. The result gra ...
- NOIP2018训练题集
1. CZday3C 给定有m个数的集合,从其中任选一个子集满足全部&后不为零,问方案数. 考虑对二进制位容斥,问题转化为求包含某个二进制位集合的数的个数,通过类似FMT的DP求解. #inc ...
- [BZOJ3238][AHOI2013]差异(后缀数组)
求和式的前两项可以直接算,问题是对于每对i,j计算LCP. 一个比较显然的性质是,LCP(i,j)是h[rk[i]+1~rk[j]]中的最小值. 从h的每个元素角度考虑,就是对每个h计算有多少对i,j ...
- 【20181019T2】硬币【矩阵快速幂优化DP】
题面 [错解] 哎\(N \leq 50\)?双向搜索? 切了切-- 等下,好像要求方案数-- 好像搜不了 哎他给\(V_{i} | V_{i+1}\)干嘛? 肯定有用啊 为了体现条件的用处,我在搜下 ...
- Codeforces Round #453 ( Div. 2) Editorial ABCD
A. Visiting a Friend time limit per test 1 second memory limit per test 256 megabytes input standard ...
- 【贪心】【multiset】Tinkoff Challenge - Final Round (Codeforces Round #414, rated, Div. 1 + Div. 2) C. Naming Company
考虑两个人,先把各自的集合排个序,丢掉一半,因为比较劣的那一半一定用不到. 然后贪心地放,只有两种决策,要么把一个最优的放在开头,要么把一个最劣的放在结尾. 如果我的最优的比对方所有的都劣(或等于), ...
- python 数据分析 Matplotlib常用图表
Matplotlib绘图一般用于数据可视化 常用的图表有: 折线图 散点图/气泡图 条形图/柱状图 饼图 直方图 箱线图 热力图 需要学习的不只是如何绘图,更要知道什么样的数据用什么图表展示效果最好 ...
- Delphi 实现多线程编程的线程类 TThread
http://blog.csdn.net/henreash/article/details/3183119 Delphi中有一个线程类TThread是用来实现多线程编程的,这个绝大多数Delphi书藉 ...
- [bug]超时时间已到。超时时间已到,但是尚未从池中获取连接。出现这种情况可能是因为所有池连接均在使用,并且达到了最大池大小。
引言 自己弄了一个小项目——日程管理系统,在初始化日期时,查询了数据库,每个日期就会查询一次数据库,就导致了这个问题. 问题 出现这种情况可能是因为所有池连接均在使用,并且达到了最大池大小. Desc ...