>[danger] 碎片模块主要实现的功能是在对应的地方执行一个片段的代码,碎片本质其实就是在对应的地方放一个钩子,在这个钩子上动态关联多个行为的过程,那么钩子就是碎片的分类,行为就是要实现的碎片代码。
>[info] 在COWCMS系统中默认放了一些系统的钩子,比如管理员登录(admin\_login),管理员退出(admin\_quit)等,了解更多的系统碎片钩子 [点击这里](http://doc.cowcms.com/950402)。
> 使用场景:管理员登录的时候,在 **A** 模块中要实现-写入管理员登录记录,在 **B** 模块要实现-记录管理员登录次数。
> 因为在管理员登录的时候,系统默认监听了管理员登录钩子(admin\_login),我们只需要给这个钩子关联( **A** 模块和 **B** 模块)中实现功能的2碎片代码就可以,当程序执行到管理员登录的时候,程序自动会执行他所关联的行为碎片。
>[danger] 实例如下:
>第一步:创建模块,在 application 目录下,创建一个 **A** 模块 和一个 **B** 模块。
>第二步:关联行为, 在 **A B** 模块下分别创建 exec 目录,在这个目录下分别创建 event.php,结构如下:
A/exec/event.php
~~~php
return [
'action_0_0'=>['name'=>'A_record','order_num'=>0,'hook_name'=>'admin_login','install_module'=>'A','describe'=>'写入管理员登录记录','class_name'=>''],
];
~~~
B/exec/event.php
~~~php
return [
'action_0_0'=>['name'=>'B_record','order_num'=>0,'hook_name'=>'admin_login','install_module'=>'B','describe'=>'记录管理员登录次数','class_name'=>''],
];
~~~
key为action\_0\_0的值,表示要在某个钩子上关联碎片(行为)
* [x] name:行为的名称,也就是函数的名称
* [x] order\_num:显示和执行的顺序,如一个钩子关联多个行为,先执行那个行为
* [x] describe:行为说明
* [x] install\_module:这个行为属于那个模块安装的
* [x] hook\_name:钩子的标识,如hook\_name为admin\_login,就表示在管理员登录的时候执行该碎片(行为)
* [x] class\_name:行为执行的代码片段的位置
>第三步:编写行为代码,第二步关联了对应的行为,但是这个时候还没有编写行为代码, 上边关联的行为代码的位置为:
A模块关联的代码在 /application/A/event/A.php
B模块关联的代码在 /application/B/event/B.php
代码如下:
```
namespace app\A\event;
class A
{
/*此处的函数名称,正是在关联行为时填写的 key为name的 值*/
public function A_record($admin)
{
// $admin : 登录管理员的信息,每个钩子所对应的参数是不一样的,具体参数请到到钩子预览表中去查看
// 此处编写需要的代码
$adminId = $admin['id'];
.............................................
}
//以下的代码为A模块关联的其它钩子的行为,和本实例没关系,可以直接删除
public function actionName()
{
//代码段
}
}
```
```
namespace app\B\event;
class B
{
//此处的函数名称,正是在关联行为时填写的 key为name的 值
public function B_record()
{
// $admin : 登录管理员的信息,每个钩子所对应的参数是不一样的,具体参数请到到钩子预览表中去查看
// 此处编写需要的代码
$adminId = $admin['id'];
.............................................
}
}
```
#### 这样当 A B模块被安装后,在有管理员登录的时候,就会执行对应的 A_record B_record 这2个方法了
>[danger]如果有些模块在关联行为的时候,并不是关联的本模块种的行为,如在登录的时候,A模块关联了一个行为,这个行为是想让他执行B模块中的B_record行为,我们可以做如下关联,
A/exec/event.php
~~~php
return [
'action_0_0'=>['name'=>'B_record','order_num'=>0,'hook_name'=>'admin_login','install_module'=>'A','describe'=>'写入管理员登录记录','class_name'=>'\\app\\B\\event\\B'],
];
~~~
这样在管理员登录的时候,就会执行B模块下的B_record方法,其实这个原来很简单。
>[danger] 钩子行为执行的原理,分为几个步骤:注意:install_module为安装模块名
> 第一步:当程序执行到钩子处,检测钩子是否启用,如果启用执行,没启用将跳过
> 第二步:去数据表中查找和该钩子关联的行为
> 第三步:如果行为中 class_name值为真 , 执行 $hook = new $class_name(); $hook->name();
> 第四步:如果 class_name不为真,执行 $hook = new \\app\\install_module\\event\\install_module(); $hook->name();
所以 class_name 可以为任何可执行的类(注意命名空间)
>[danger] **注意:如果系统预设的钩子无法满足时,如何给自己的模块添加钩子**
第一步:首先在模块的exec目录里创建event.php,在文件中按格式写入自己的钩子
~~~php
return [
'hook_0'=>['name'=>'app_init','title'=>'模块初始化','order_num'=>0,'describe'=>"在模块中开始执行时执行行为",'class'=>1,'install_module'=>'A'],
];
~~~
第二步:在模块开始运行的代码处放入如下代码
```
//代码段
$param = [$moduleName]
eventAdd("app_init",$param)
```
>[info]eventAdd第一个参数为钩子的标识(name),第二个参数为数组,是钩子调用行为时传递的参数,比如为$moduleName为模块名称,那么在行为的中第一个参数就可以获得$moduleName变量值。这样当有人安装了这个模块后,就可以在任何模块中针对app_init钩子编写行为了
key为hook\_0的值,表示要添加的碎片的分组(钩子),这个主要作用是当系统预设的钩子无法满足需求时,在模块中要添加自己的钩子时,可以这样写
* [x] title:钩子的名称,如管理登录,管理员退出,只是方便管理,在程序中无作用
* [x] name:钩子标识,监听钩子时用到的标识,如果管理员登录时为(admin\_login)
* [x] order\_num:钩子显示的排序,只使用于后台显示,方便关联
* [x] describe:钩子说明
* [x] class:必填为1,区分时钩子还是行为
* [x] install\_module:这个钩子属于那个模块安装的