>[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:这个钩子属于那个模块安装的