ThinkPHP5.1 Hook(钩子)的理解及应用示例

摘要

  • 近期在对后台系统的优化过程中,
    了解到 ThinkPHP5 框架所提供的 钩子 行为记录的技巧使用
    感觉在代码规范、AOP (面向切面编程)上都很有值得借鉴的地方
    在此进行整理一番,希望帮到有需要的小伙伴

  • 官方文档 - 钩子和行为
    ThinkPHP5.1 Hook(钩子)的理解及应用示例_第1张图片

☞ 实例操作

以我的实际操作为例,演示步骤如下:

第一步、 行为入口定义

行为类的定义很简单,一般来说只需要定义一个行为入口方法 run即可

  • 我在目录 application/cm/behavior 目录中,新建了一个行为类 "CmsLogger"
    源码如下 (具体逻辑可根据自己的需求设定):


namespace app\cms\behavior;

use app\common\lib\BaseException;
use app\common\lib\IAuth;
use app\common\model\XcmsOpLogs;
use think\facade\Request;
use think\facade\Response;

/**
 * 行为日志
 * Class CmsOp
 * @package app\cms\behavior
 */
class CmsLogger
{
    /**
     * @param string $params
     * @throws BaseException
     */
    public function run($params = ''){

        if (empty($params)){
            throw new BaseException(['msg' => '日志信息不能为空']);
        }

        if (is_array($params)){
            list('admin_id' => $admin_id, 'admin_name' => $admin_name, 'msg' => $message) = $params;
        }else{
            list($admin_id,$admin_name) = IAuth::getAdminIDCurrLogged();
            $message = $params;
        }

        $LogData = [
            'message'   => $message,
            'admin_id'  => $admin_id,
            'admin_name'    => $admin_name,
            'status_code'   => Response::getCode(),
            'method'    => Request::method(),
            'path'      => '/' . Request::path(),
        ];
        (new XcmsOpLogs())::create($LogData);
    }
}

第二步、统一定义行为

我直接在应用目录下面定义 tags.php 文件来统一定义行为

ThinkPHP5.1 Hook(钩子)的理解及应用示例_第2张图片

第三步、相关数据记录设计

我习惯将行为日志记录到 mySQL 数据库中(可根据自己的需求选择记录方式)

  • 在此,我设计的一个行为日志表如下:
CREATE TABLE `tp5_xcms_op_logs` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `admin_id` int(10) unsigned NOT NULL DEFAULT '0',
  `admin_name` varchar(24) NOT NULL DEFAULT '',
  `status_code` int(11) unsigned NOT NULL DEFAULT '0',
  `method` varchar(20) NOT NULL DEFAULT '',
  `path` varchar(50) NOT NULL DEFAULT '',
  `message` varchar(300) NOT NULL DEFAULT '',
  `create_time` datetime(3) NOT NULL COMMENT '创建时间',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='CMS 行为日志记录表';

第四步、闭包传参,执行行为

官方提供了两种方式,一种为 闭包支持,另一种为 直接执行行为

  • 在此,我选择的是第一种方式
    最简单的代码参考如下:
    ThinkPHP5.1 Hook(钩子)的理解及应用示例_第3张图片

  • [注]:对于其中的传参一般可以分为 string/array 类型,演示我的调用位置如下:
    ThinkPHP5.1 Hook(钩子)的理解及应用示例_第4张图片

☞ 后续总结

  • 根据前面的步骤,代码逻辑编写完成后,最终会在行为日志表中得到如下记录:
    ThinkPHP5.1 Hook(钩子)的理解及应用示例_第5张图片
  • 该记录,一般用于管理员后台监控
    或者,为登录平台的用户显示其操作日志,方便问题追溯
    后续,可根据自己系统的需求,对该行为日志进行提取即可 …

☛ 附录

经验这种东西,需要自己根据需求,参考后做最适合自己的优化,才是最有效率的!

▷ 参考文章

  • 【理解钩子Hook以及在Thinkphp下利用钩子使用行为扩展】
  • 【Thinkphp5.1钩子与行为的初步学习】

▷ 提供一种自定义公共方法记录行为日志的处理方式

在没有接触 Hook (钩子) 技巧使用前,在此提供一下我所使用的记录日志方式

1、 首先,在公共方法文件 common.php 中,定义如下方法

/**
 * 操作日志 添加记录
 * @param int $opStatus 操作标记位 ,非零则进行日志的记录
 * @param string $opTag 所记录业务日志确定的标签
 *               当前定义 ———— "ARTICLE": 文章操作业务;"TODAY":今日赠言业务;"GOODS":商品操作业务
 * @param int $op_id 所操作的目标记录ID
 * @param string $op_msg 记录操作信息
 * @return bool|int|string
 */
function insertCmsOpLogs($opStatus = 0,$opTag = '',
                                $op_id = 0,$op_msg = ''){
    if (!$opStatus){
        return false;
    }else{
        list($cmsAID) = IAuth::getAdminIDCurrLogged();
        $opData = [
            'op_id' => $op_id,
            'tag' => $opTag,
            'admin_id' => $cmsAID,
            'add_time' => date('Y-m-d H:i:s',time()),
            'op_msg' => $op_msg
        ];
        if ($opTag){
            $opStatus = Db::name('xcmsLogs')->insert($opData);
        }else{
            return false;
        }
        return $opStatus;
    }
}

/**
 * 获取操作日志
 * @param int $op_id
 * @param string $opTag  所记录业务日志确定的标签
 *               当前定义 ———— "ARTICLE": 文章操作业务;"TODAY":今日赠言业务;"GOODS":商品操作业务
 * @return array|PDOStatement|string|\think\Collection
 */
function getCmsOpViewLogs($op_id= 0,$opTag = ''){
    $logs = Db::name('xcmsLogs l')
        ->field('l.*,a.user_name')
        ->join('xadmins a','a.id = l.admin_id')
        ->where([['tag','=',$opTag],['op_id','=',$op_id]])
        ->order('id','desc')
        ->select();
    return isset($logs)?$logs:[];
}
  • 对该方法中,操作的记录数据表,建表语句参考如下:
CREATE TABLE `tp5_xcms_logs` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `tag` varchar(10) NOT NULL COMMENT '标签,为了区分所记录不同业务的日志',
  `op_id` int(11) NOT NULL DEFAULT '0' COMMENT '操作对象 ID',
  `op_msg` varchar(12) NOT NULL COMMENT '操作备案',
  `admin_id` int(11) NOT NULL DEFAULT '0' COMMENT '操作管理员ID',
  `add_time` datetime NOT NULL COMMENT '记录添加时间',
  PRIMARY KEY (`id`),
  KEY `index_op_admin_id` (`op_id`,`admin_id`),
  KEY `tag_index` (`tag`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 COMMENT='业务 行为记录日志表';

2、然后,确定在代码逻辑中,需要记录日志的位置,调用 insertCmsOpLogs()

ThinkPHP5.1 Hook(钩子)的理解及应用示例_第6张图片

3、在需要展示操作日志的时候,调用getCmsOpViewLogs()

  • 我对简单业务处理的操作日志展示如下:
    ThinkPHP5.1 Hook(钩子)的理解及应用示例_第7张图片

★ 对比总结

1. 相对来说,实现最终的功能可以有多种方式,不必纠结
2. 多数自己设计的公共方法,对自己业务而言,更灵活
3. ThinkPHP5 提供的 Hook 技巧,具有的切面思想是最值得借鉴的;
	同时,在新的行为设计出现后,方便进行扩展,相对框架来说更具有规范性;
	最大的优势,在于受众面的宽阔,便于交流

你可能感兴趣的:(ThinkPHP)