作者:老葛,北京亚艾元软件有限责任公司,http://www.yaiyuan.com
Drupal7对钩子函数的缓加载,还是有改进的,Drupal7里面是这样改进的,通过hook_hook_info,我们就可以把多个钩子函数划分成一组,比如组名叫做rules,那么我们就可以把rules相关的钩子实现,都放到mymodule.rules.inc文件中去。这样当,调用rules相关的钩子时,才会加载mymodule.rules.inc文件。不过,不是很多程序员都了解这个机制,就是很多资深的Drupal开发者,也不了解这个机制。比如,Ubercart里面就没有类似的实现,不过我在uc_ctools模块里面,帮助Ubercart实现hook_hook_info钩子。我们来看看我的实现:
/**
* Implementation of hook_hook_info().
*/
function uc_ctools_hook_info() {
//Hooks provided by uc_cart
foreach (array('add_to_cart', 'add_to_cart_data', 'cart_display', 'cart_pane', 'cart_pane_alter', 'checkout_complete', 'checkout_pane', 'checkout_pane_alter', 'update_cart_item') as $hook) {
$hooks['uc_' . $hook] = array(
'group' => 'ubercart',
);
}
//Hooks provided by uc_file
foreach (array('download_authorize', 'file_action', 'file_transfer_alter') as $hook) {
$hooks['uc_' . $hook] = array(
'group' => 'ubercart',
);
}
//Hooks provided by uc_order
foreach (array('invoice_templates', 'line_item', 'line_item_alter', 'line_item_data_alter', 'order', 'order_actions', 'order_pane', 'order_pane_alter', 'order_product_alter', 'order_product_delete', 'order_product_can_ship', 'order_state') as $hook) {
$hooks['uc_' . $hook] = array(
'group' => 'ubercart',
);
}
//Hooks provided by uc_product
foreach (array('alter', 'class', 'default_classes', 'description', 'description_alter', 'models', 'types') as $hook) {
$hooks['uc_product_' . $hook] = array(
'group' => 'ubercart',
);
}
//Hooks provided by uc_stock
$hooks['uc_stock_adjusted'] = array(
'group' => 'ubercart',
);
//Hooks provided by uc_store
$hooks['tapir_table_alter'] = array(
'group' => 'ubercart',
);
foreach (array('form_alter', 'message', 'store_status') as $hook) {
$hooks['uc_' . $hook] = array(
'group' => 'ubercart',
);
}
//Hooks provided by uc_taxes
$hooks['uc_calculate_tax'] = array(
'group' => 'ubercart',
);
//Hooks provided by uc_payment
foreach (array('payment_entered', 'payment_gateway', 'payment_gateway_alter', 'payment_method', 'payment_method_alter') as $hook) {
$hooks['uc_' . $hook] = array(
'group' => 'ubercart',
);
}
//Hooks provided by uc_quote
foreach (array('shipping_method', 'shipping_type') as $hook) {
$hooks['uc_' . $hook] = array(
'group' => 'ubercart',
);
}
//Hooks provided by uc_shipping
$hooks['uc_shipment'] = array(
'group' => 'ubercart',
);
return $hooks;
}
我把Ubercart核心自带的钩子,都合并到了ubercart这个组里面了,如果你的模块需要实现Ubercart的钩子函数,只需要将具体实现放到mymodule.ubercart.inc文件里面就可以了。
这样,我们就可以缓加载钩子函数了,这是一个办法,一个折中的办法。如果,你了解这一点的话,当你遇到token相关的钩子实现时,就可以放到mymodule.tokens.inc里面,当遇到rules的钩子实现时,把对应的钩子函数放到mymodule.rules.inc里面。
我也是在接触了Drupal7一年以后,才了解到这个机制。开始我都不明白,为什么可以把rules相关的钩子函数放到mymodule.rules.inc里面,我们来看一下rules的实现:
/**
* Implementation of hook_hook_info().
*/
function rules_hook_info() {
foreach(array('plugin_info', 'data_info', 'condition_info', 'action_info', 'event_info', 'file_info', 'evaluator_info', 'data_processor_info') as $hook) {
$hooks['rules_' . $hook] = array(
'group' => 'rules',
);
$hooks['rules_' . $hook . '_alter'] = array(
'group' => 'rules',
);
}
$hooks['default_rules_configuration'] = array(
'group' => 'rules_defaults',
);
$hooks['default_rules_configuration_alter'] = array(
'group' => 'rules_defaults',
);
return $hooks;
}
我们看到,这里分成了两个组,一个是rules,一个是rules_defaults。如果进一步了解的话,还是看一看module_invoke_all, module_implements这两个函数,前者调用了后者,而在module_implements函数里面,参看api.drupal.org。里面包含这样的几段代码:
cache_clear_all('hook_info', 'cache_bootstrap');
…
$hook_info = module_hook_info();
…
$include_file = isset($hook_info[$hook]['group']) && module_load_include('inc', $module, $module . '.' . $hook_info[$hook]['group']);
…
if ($group) {
module_load_include('inc', $module, "$module.$group");
}
读懂了这里的代码,我们就基本上彻底的了解这个机制。有兴趣的读者可以进一步的读一下module_hook_info这个函数里面的代码。在api.drupal.org上面阅读即可。我原来一直以为token模块实现了钩子hook_hook_info,但是在token模块里面找了又找,就是找不到,后来,发现它的实现放到了system模块里面:
function system_hook_info() {
$hooks['token_info'] = array(
'group' => 'tokens',
);
$hooks['token_info_alter'] = array(
'group' => 'tokens',
);
$hooks['tokens'] = array(
'group' => 'tokens',
);
$hooks['tokens_alter'] = array(
'group' => 'tokens',
);
return $hooks;
}
我就是借鉴了这里的用法,在uc_ctools模块里面,把Ubercart的相关钩子归成了一个组。
hook_hook_info这种方式,部分解决了问题,由于知道的人不多,很多人仍然将相应的钩子实现放到module文件里面。