123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348 |
- <?php
- namespace app\common\Service\Order;
- use app\common\Enum\OrderActionEnum;
- use think\Exception;
- /**
- * 订单操作装饰器 - 实现AOP模式自动记录操作
- */
- class OrderActionDecorator
- {
- /**
- * 被装饰的服务对象
- */
- protected $service;
- /**
- * 当前操作上下文
- */
- protected $context = [];
- /**
- * 构造函数
- * @param object $service 被装饰的服务对象
- */
- public function __construct($service)
- {
- $this->service = $service;
- }
- /**
- * 设置操作上下文
- * @param array $context 上下文信息
- */
- public function setContext($context)
- {
- $this->context = array_merge($this->context, $context);
- }
- /**
- * 获取操作上下文
- * @return array
- */
- public function getContext()
- {
- return $this->context;
- }
- /**
- * 魔术方法,代理所有方法调用
- * @param string $method 方法名
- * @param array $args 参数
- * @return mixed
- */
- public function __call($method, $args)
- {
- // 前置处理
- $this->beforeAction($method, $args);
- try {
- // 调用原始方法
- $result = call_user_func_array([$this->service, $method], $args);
- // 后置处理
- $this->afterAction($method, $args, $result);
- return $result;
- } catch (Exception $e) {
- // 异常处理
- $this->onException($method, $args, $e);
- throw $e;
- }
- }
- /**
- * 前置处理
- * @param string $method 方法名
- * @param array $args 参数
- */
- protected function beforeAction($method, $args)
- {
- // 记录方法调用开始
- $this->context['method'] = $method;
- $this->context['args'] = $args;
- $this->context['start_time'] = microtime(true);
- $this->context['start_memory'] = memory_get_usage();
- }
- /**
- * 后置处理
- * @param string $method 方法名
- * @param array $args 参数
- * @param mixed $result 结果
- */
- protected function afterAction($method, $args, $result)
- {
- // 记录方法调用结束
- $this->context['end_time'] = microtime(true);
- $this->context['end_memory'] = memory_get_usage();
- $this->context['execution_time'] = $this->context['end_time'] - $this->context['start_time'];
- $this->context['memory_usage'] = $this->context['end_memory'] - $this->context['start_memory'];
- $this->context['result'] = $result;
- // 根据方法名自动记录操作
- $this->autoRecordAction($method, $args, $result);
- }
- /**
- * 异常处理
- * @param string $method 方法名
- * @param array $args 参数
- * @param Exception $e 异常对象
- */
- protected function onException($method, $args, $e)
- {
- // 记录异常
- $this->context['exception'] = $e->getMessage();
- $this->context['exception_code'] = $e->getCode();
- $this->context['exception_trace'] = $e->getTraceAsString();
- // 可以在这里记录异常日志
- \think\Log::error('订单操作异常: ' . $e->getMessage(), [
- 'method' => $method,
- 'args' => $args,
- 'context' => $this->context
- ]);
- }
- /**
- * 自动记录操作
- * @param string $method 方法名
- * @param array $args 参数
- * @param mixed $result 结果
- */
- protected function autoRecordAction($method, $args, $result)
- {
- // 方法名到操作类型的映射
- $methodActionMap = [
- 'create' => OrderActionEnum::ACTION_CREATE,
- 'pay' => OrderActionEnum::ACTION_PAY,
- 'ship' => OrderActionEnum::ACTION_SHIP,
- 'receive' => OrderActionEnum::ACTION_RECEIVE,
- 'cancel' => OrderActionEnum::ACTION_CANCEL,
- 'refund' => OrderActionEnum::ACTION_REFUND,
- 'return' => OrderActionEnum::ACTION_RETURN,
- 'complete' => OrderActionEnum::ACTION_COMPLETE,
- 'comment' => OrderActionEnum::ACTION_COMMENT,
- 'modify' => OrderActionEnum::ACTION_MODIFY,
- 'remind' => OrderActionEnum::ACTION_REMIND,
- ];
- // 查找匹配的操作类型
- $actionType = null;
- foreach ($methodActionMap as $keyword => $action) {
- if (stripos($method, $keyword) !== false) {
- $actionType = $action;
- break;
- }
- }
- if (!$actionType) {
- return; // 没有匹配的操作类型,不记录
- }
- // 尝试从参数中提取订单编号
- $orderSn = $this->extractOrderSn($args);
- if (!$orderSn) {
- return; // 没有订单编号,不记录
- }
- // 获取操作者信息
- $operator = $this->context['operator'] ?? 'unknown';
- $userType = $this->context['user_type'] ?? OrderActionEnum::USER_TYPE_ADMIN;
- $userId = $this->context['user_id'] ?? 0;
- // 构建备注信息
- $memo = $this->buildMemo($method, $args, $result);
- // 构建额外数据
- $extra = [
- 'method' => $method,
- 'execution_time' => $this->context['execution_time'],
- 'memory_usage' => $this->context['memory_usage'],
- 'user_agent' => request()->server('HTTP_USER_AGENT', ''),
- 'ip' => request()->ip(),
- ];
- // 记录操作
- try {
- switch ($userType) {
- case OrderActionEnum::USER_TYPE_CUSTOMER:
- OrderActionService::recordUserAction($orderSn, $actionType, $operator, $memo, $userId, $extra);
- break;
- case OrderActionEnum::USER_TYPE_ADMIN:
- OrderActionService::recordAdminAction($orderSn, $actionType, $operator, $memo, $userId, $extra);
- break;
- case OrderActionEnum::USER_TYPE_SYSTEM:
- OrderActionService::recordSystemAction($orderSn, $actionType, $memo, $extra);
- break;
- }
- } catch (Exception $e) {
- // 记录操作失败不应该影响主流程
- \think\Log::error('自动记录订单操作失败: ' . $e->getMessage());
- }
- }
- /**
- * 从参数中提取订单编号
- * @param array $args 参数数组
- * @return string|null
- */
- protected function extractOrderSn($args)
- {
- // 尝试从不同位置提取订单编号
- foreach ($args as $arg) {
- if (is_string($arg) && preg_match('/^[A-Z0-9]{10,}$/', $arg)) {
- return $arg; // 假设订单编号是10位以上的大写字母和数字组合
- }
- if (is_array($arg) && isset($arg['order_sn'])) {
- return $arg['order_sn'];
- }
- if (is_array($arg) && isset($arg['out_trade_no'])) {
- return $arg['out_trade_no'];
- }
- if (is_object($arg) && property_exists($arg, 'order_sn')) {
- return $arg->order_sn;
- }
- }
- return null;
- }
- /**
- * 构建备注信息
- * @param string $method 方法名
- * @param array $args 参数
- * @param mixed $result 结果
- * @return string
- */
- protected function buildMemo($method, $args, $result)
- {
- $memo = "执行方法: {$method}";
-
- // 添加执行时间信息
- if (isset($this->context['execution_time'])) {
- $memo .= sprintf(", 耗时: %.3fs", $this->context['execution_time']);
- }
- // 添加内存使用信息
- if (isset($this->context['memory_usage'])) {
- $memo .= sprintf(", 内存: %s", $this->formatBytes($this->context['memory_usage']));
- }
- // 添加自定义备注
- if (isset($this->context['memo'])) {
- $memo .= ", " . $this->context['memo'];
- }
- return $memo;
- }
- /**
- * 格式化字节数
- * @param int $bytes 字节数
- * @return string
- */
- protected function formatBytes($bytes)
- {
- if ($bytes >= 1024 * 1024) {
- return sprintf('%.2fMB', $bytes / (1024 * 1024));
- } elseif ($bytes >= 1024) {
- return sprintf('%.2fKB', $bytes / 1024);
- } else {
- return $bytes . 'B';
- }
- }
- /**
- * 创建装饰器实例
- * @param object $service 被装饰的服务对象
- * @param array $context 上下文信息
- * @return OrderActionDecorator
- */
- public static function create($service, $context = [])
- {
- $decorator = new static($service);
- $decorator->setContext($context);
- return $decorator;
- }
- /**
- * 装饰服务方法的静态工厂方法
- * @param object $service 被装饰的服务对象
- * @param string $operator 操作者
- * @param string $userType 用户类型
- * @param int $userId 用户ID
- * @param array $extra 额外上下文
- * @return OrderActionDecorator
- */
- public static function decorate($service, $operator, $userType = OrderActionEnum::USER_TYPE_ADMIN, $userId = 0, $extra = [])
- {
- $context = array_merge([
- 'operator' => $operator,
- 'user_type' => $userType,
- 'user_id' => $userId,
- ], $extra);
- return self::create($service, $context);
- }
- /**
- * 为用户操作创建装饰器
- * @param object $service 被装饰的服务对象
- * @param string $operator 操作者
- * @param int $userId 用户ID
- * @param array $extra 额外上下文
- * @return OrderActionDecorator
- */
- public static function forUser($service, $operator, $userId = 0, $extra = [])
- {
- return self::decorate($service, $operator, OrderActionEnum::USER_TYPE_CUSTOMER, $userId, $extra);
- }
- /**
- * 为管理员操作创建装饰器
- * @param object $service 被装饰的服务对象
- * @param string $operator 操作者
- * @param int $adminId 管理员ID
- * @param array $extra 额外上下文
- * @return OrderActionDecorator
- */
- public static function forAdmin($service, $operator, $adminId = 0, $extra = [])
- {
- return self::decorate($service, $operator, OrderActionEnum::USER_TYPE_ADMIN, $adminId, $extra);
- }
- /**
- * 为系统操作创建装饰器
- * @param object $service 被装饰的服务对象
- * @param array $extra 额外上下文
- * @return OrderActionDecorator
- */
- public static function forSystem($service, $extra = [])
- {
- return self::decorate($service, 'system', OrderActionEnum::USER_TYPE_SYSTEM, 0, $extra);
- }
- }
|