您的位置:首页 > 其它

SugarCRM源码分析之钩子

2016-01-21 21:03 411 查看
        本篇主要分析下SugarCRM的钩子源码实现,即使一开始对SugarCRM不熟,掌握了钩子的用法,也能写写相关的功能。

// 调用钩子
LogicHook::initialize()->call_custom_logic('', 'entry_point_variables_setting');

// 返回实例
// ./include/utils/LogicHook.php
static function initialize() {
if (empty($GLOBALS['logic_hook']))
$GLOBALS['logic_hook'] = new LogicHook();
return $GLOBALS['logic_hook'];
}

// 调用钩子,$module_dir为空调用application,不为空调用module
// 当$module_dir为空时,$this->bean为null
function call_custom_logic($module_dir, $event, $arguments = array()) {

// $this->bean默认为null
// 如果传过来的$module_dir为空,那么下面的BeanFactory::getBean($module_dir)返回的还是null
/*
// ./data/SugarBean.php
public static function getBean($module, $id = null, $params = array(), $deleted = true)
{
```
$beanClass = self::getBeanName($module);
if (empty($beanClass) || !class_exists($beanClass)) return null;
```
}

// 获取bean名称,如果为空,返回false
// 否则返回已有的$bean_classes
// 或是$beanList里的类【该数组在./include/modules.php里】
public static function getBeanName($module)
{
if(!empty(self::$bean_classes[$module])) {
return self::$bean_classes[$module];
}
global $beanList;
if (empty($beanList[$module]))  {
return false;
}

return $beanList[$module];
}
*/
$origBean = $this->bean;
if ($origBean === null) {
$bean = BeanFactory::getBean($module_dir);
if ($bean instanceOf SugarBean) {
$this->setBean($bean);
}
}

// declare the hook array variable, it will be defined in the included file.
// 写过钩子都是通过此数组定义
$hook_array = null;

// 看到上篇日志管理那篇博客应该知道下面debug方法不会执行
// 除非在config.php把日志级别配置为debug
if (isset($GLOBALS['log'])) {
$GLOBALS['log']->debug("Hook called: $module_dir::$event");
}

// 如果$module_dir不为空,那么调用的是模块钩子
// 这里的模块,就是页面导航栏中的具体菜单项
if (!empty($module_dir)) {
// This will load an array of the hooks to process
$hooks = $this->getHooks($module_dir);
if (!empty($hooks)) {
$this->process_hooks($hooks, $event, $arguments);
}
}

// 否则调用的是应用钩子
// 获取全部的应用钩子
$hooks = $this->getHooks('');
if (!empty($hooks)) {

// 执行钩子逻辑
$this->process_hooks($hooks, $event, $arguments);
}

// 如果$module_dir为空,$origBean便为null
// 那么就是把$this->bean置为null
if ($origBean === null) {
$this->setBean($origBean);
}
}

// 获取钩子
public function getHooks($module_dir, $refresh = false) {

if ($refresh || !isset(self::$hooks[$module_dir])) {
self::$hooks[$module_dir] = $this->loadHooks($module_dir);
}
return self::$hooks[$module_dir];
}

// 在指定文件中加载钩子
public function loadHooks($module_dir) {
$hook_array = array();
if (!empty($module_dir)) {
$custom = "custom/modules/$module_dir";
} else {
$custom = "custom/modules";
}

// 这一步可以看出当$module_dir为空时,查找的是application的钩子文件
// 否则查找的是指定模块的钩子文件
foreach (SugarAutoLoader::existing(
"$custom/logic_hooks.php", SugarAutoLoader::loadExtension("logichooks", empty($module_dir) ? "application" : $module_dir)
) as $file) {
if (isset($GLOBALS['log'])) {
$GLOBALS['log']->debug('Including hook file: ' . $file);
}
include $file;
}
return $hook_array;
}

// ./include/utils/autoloader.php
// self::$extensions存储的是./ModuleInstall.php中的数据,在SugarAutoLoader::init()中加载执行
// 执行完此方法后,返回的是 custom/modules/application/Ext/LogicHoooks/logichooks.ext.php文件
public static function loadExtension($extname, $module = "application") {
if (empty(self::$extensions[$extname]))
return false;
$ext = self::$extensions[$extname];
if (empty($ext['file']) || empty($ext['extdir'])) {
// custom rebuilds, can't handle
return false;
}
if (isset($ext["module"])) {
$module = $ext["module"];
}
if ($module == "application") {
$file = "custom/application/Ext/{$ext["extdir"]}/{$ext["file"]}";
} else {
$file = "custom/modules/{$module}/Ext/{$ext["extdir"]}/{$ext["file"]}";
}
if (self::fileExists($file)) {
return $file;
}
return false;
}

// 执行钩子逻辑
/*

Array
(
[before_save] => Array
(
[0] => Array
(
[0] => 1
[1] => BeforeSaveHooksMethod
[2] => custom/modules/ptsdb_double_points_rule/DoublePointsRuleHooks.php
[3] => DoublePointsRuleHooks
[4] => beforeSaveHooksMethod
)

)

[after_save] => Array
(
[0] => Array
(
[0] => 1
[1] => AfterSaveHooksMethod
[2] => custom/modules/ptsdb_double_points_rule/DoublePointsRuleHooks.php
[3] => DoublePointsRuleHooks
[4] => afterSaveHooksMethod
)

)

[after_delete] => Array
(
[0] => Array
(
[0] => 1
[1] => AfterDeleteHooksMethod
[2] => custom/modules/ptsdb_double_points_rule/DoublePointsRuleHooks.php
[3] => DoublePointsRuleHooks
[4] => afterDeleteHooksMethod
)

)

)
*/
function process_hooks($hook_array, $event, $arguments) {

// 如果已经定义了相关的钩子,那么在这就可以开始执行了
// 钩子是按照index从小到大的次序来执行的
// Now iterate through the array for the appropriate hook
if (!empty($hook_array[$event])) {

// Apply sorting to the hooks using the sort index.
// Hooks with matching sort indexes will be processed in no particular order.
$sorted_indexes = array();
foreach ($hook_array[$event] as $idx => $hook_details) {
$order_idx = $hook_details[0];
$sorted_indexes[$idx] = $order_idx;
}
asort($sorted_indexes);

$process_order = array_keys($sorted_indexes);

foreach ($process_order as $hook_index) {
$hook_details = $hook_array[$event][$hook_index];

// 如果钩子执行文件不存在,记日志报错【不会执行】,进入下一次循环
if (!file_exists($hook_details[2])) {
if (isset($GLOBALS['log'])) {
$GLOBALS['log']->error('Unable to load custom logic file: ' . $hook_details[2]);
}
continue;
}

// 加载钩子执行文件
include_once($hook_details[2]);

// 钩子执行类
$hook_class = $hook_details[3];

// 钩子执行方法
$hook_function = $hook_details[4];

// Make a static call to the function of the specified class
// TODO Make a factory for these classes.  Cache instances accross uses
// 如果类和方法一样,直接new钩子类,把钩子方法及参数传进去
if ($hook_class == $hook_function) {
if (isset($GLOBALS['log'])) {
$GLOBALS['log']->debug('Creating new instance of hook class ' . $hook_class . ' with parameters');
}

// $this->bean不为空,大都是数据库相关的操作 类
if (!is_null($this->bean))
$class = new $hook_class($this->bean, $event, $arguments);

// 不是的话,就不用传
else
$class = new $hook_class($event, $arguments);

// 类和方法不同名
}else {
if (isset($GLOBALS['log'])) {
$GLOBALS['log']->debug('Creating new instance of hook class ' . $hook_class . ' without parameters');
}

// 实例化钩子类
$class = new $hook_class();

// 执行钩子
if (!is_null($this->bean)) {
$callback = array($class, $hook_function);
// & is here because of BR-1345 and old broken hooks
// that use &$bean in args.
// 这里主要是兼容以前版本的写法,基本上$params还是&$this->bean, $event, $arguments
$params = array_merge(array(&$this->bean, $event, $arguments), array_slice($hook_details, 5));
call_user_func_array($callback, $params);
} else
$class->$hook_function($event, $arguments);
}
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: