payService = $payService; $this->platform = $platform; $this->channel = $channel; } /** * yansongda 支付初始化 * @param string $payment 支付类型 * @param array $config 配置参数 * @param string $type 配置类型 * @return void * @throws Exception */ public function init($payment, $config = [], $type = 'normal') { try { $this->config = $this->getConfig($payment, $config, $type); $this->pay = Pay::config($this->config); // 使用自定义 HTTP 客户端(如果可用) Pay::set(HttpClientInterface::class, HttpClient::instance()); } catch (\Exception $e) { Log::error('支付初始化失败: ' . $e->getMessage(), [ 'payment' => $payment, 'platform' => $this->platform, 'channel' => $this->channel ]); throw new Exception('支付初始化失败: ' . $e->getMessage()); } } /** * 获取支付的所有参数 * @param string $payment 支付类型 * @param array $config 额外配置 * @param string $type 配置类型 * @return array * @throws Exception */ protected function getConfig($payment, $config = [], $type = 'normal') { try { // 获取平台配置 $platformConfig = $this->getPlatformConfig(); if (!$platformConfig) { throw new Exception('平台配置获取失败'); } // extract() 函数从数组中将变量导入到当前的符号表。 //该函数使用数组键名作为变量名,使用数组键值作为变量值。针对数组中的每个元素,将在当前符号表中创建对应的一个变量。 //该函数返回成功设置的变量数目。 extract($platformConfig); $params = $this->getPayConfig($payment, $paymentConfig ?? []); // 格式化支付参数 $params['mode'] = (int)($params['mode'] ?? 0); $params = $this->formatConfig($params, ['app_id' => $app_id ?? ''], $type); // 合并传入的参数 $params = array_merge($params, $config); // 合并参数 $config = $this->baseConfig(); $config = array_merge($config, [$payment => ['default' => $params]]); return $config; } catch (\Exception $e) { Log::error('获取支付配置失败: ' . $e->getMessage()); throw new Exception('支付配置获取失败'); } } /** * 获取平台配置参数 * @return array * @throws Exception */ protected function getPlatformConfig() { try { // 优先从渠道获取配置 if ($this->channel) { $platformConfig = $this->getChannelConfig($this->channel); } if (!$platformConfig) { throw new Exception('平台配置不存在'); } $paymentConfig = $platformConfig['payment'] ?? []; $app_id = $platformConfig['app_id'] ?? ''; // compact() 函数创建一个包含变量名和它们的值的数组。 return compact('paymentConfig', 'app_id'); } catch (\Exception $e) { throw new Exception('获取平台配置失败: ' . $e->getMessage()); } } /** * 根据平台以及支付方式获取支付配置表的配置参数 * @param string $payment 支付类型 * @param array $paymentConfig 支付配置 * @return array * @throws Exception */ protected function getPayConfig($payment, $paymentConfig) { try { $methods = $paymentConfig['methods'] ?? []; $payment_config = $paymentConfig[$payment] ?? 0; if (!in_array($payment, $methods)) { throw new Exception('当前平台未开启该支付方式: ' . $payment); } if ($payment_config) { $payConfig = PayConfig::where('id', $payment_config)->find(); if (!$payConfig) { throw new Exception('支付配置不存在,ID: ' . $payment_config); } // 解析参数 $params = $payConfig->params ?? ''; if (is_string($params)) { $params = json_decode($params, true) ?: []; } return $params; } throw new Exception('支付配置参数不存在'); } catch (\Exception $e) { throw new Exception('获取支付配置失败: ' . $e->getMessage()); } } /** * 获取对应的支付方法名 * * @param strign $payment * @return string */ protected function getMethod($payment) { $method = [ 'wechat' => [ 'WechatOfficialAccount' => 'mp', //公众号支付 Collection 'WechatMiniProgram' => 'mini', //小程序支付 Collection 'H5' => 'wap', //手机网站支付 Response 'App' => 'app' // APP 支付 JsonResponse ], 'alipay' => [ 'WechatOfficialAccount' => 'wap', //手机网站支付 Response 'WechatMiniProgram' => 'wap', //小程序支付 'H5' => 'wap', //手机网站支付 Response 'App' => 'app' //APP 支付 JsonResponse ], ]; return $method[$payment][$this->platform]; } /** * yansongda 基础配置 * * @return void */ protected function baseConfig() { $log_path = RUNTIME_PATH . 'log/pay/'; if (!is_dir($log_path)) { @mkdir($log_path, 0755, true); } return [ 'logger' => [ // optional 'enable' => true, 'file' => $log_path . 'pay.log', 'level' => config('app_debug') ? 'debug' : 'info', // 建议生产环境等级调整为 info,开发环境为 debug 'type' => 'daily', // optional, 可选 daily. 'max_file' => 30, // optional, 当 type 为 daily 时有效,默认 30 天 ], 'http' => [ // optional 'timeout' => 5.0, 'connect_timeout' => 5.0, // 更多配置项请参考 [Guzzle](https://guzzle-cn.readthedocs.io/zh_CN/latest/request-options.html) ], ]; } /** * 格式化配置参数(子类需要实现) * @param array $config * @param array $data * @param string $type * @return array */ protected function formatConfig($config, $data = [], $type = 'normal') { // 基础实现,子类可以重写 return array_merge($config, $data); } /** * 根据渠道获取配置 * @param string $channel * @return array|null */ protected function getChannelConfig($channel) { // 根据渠道类型获取对应的配置 if (ChannelEnum::isWechatChannel($channel)) { return $this->getWechatChannelConfig($channel); } elseif (ChannelEnum::isMiniProgramChannel($channel)) { return $this->getMiniProgramChannelConfig($channel); } else { return $this->getDefaultChannelConfig($channel); } } /** * 获取微信渠道配置 * @param string $channel * @return array|null */ protected function getWechatChannelConfig($channel) { return [ 'payment' => [ 'methods' => ['wechat'], 'wechat' => 1, 'alipay' => 0, ], 'app_id' => config('wechat.app_id', ''), ]; } /** * 获取小程序渠道配置 * @param string $channel * @return array|null */ protected function getMiniProgramChannelConfig($channel) { return [ 'payment' => [ 'methods' => ['wechat', 'alipay'], 'wechat' => 1, 'alipay' => 1, ], 'app_id' => config('mini.app_id', ''), ]; } /** * 获取默认渠道配置 * @param string $channel * @return array|null */ protected function getDefaultChannelConfig($channel) { return [ 'payment' => [ 'methods' => ['wechat', 'alipay'], 'wechat' => 1, 'alipay' => 1, ], 'app_id' => '', ]; } /** * 验证支付环境 * @param string $payment * @throws Exception */ protected function validatePaymentEnvironment($payment) { if ($this->channel) { // 验证渠道是否支持支付 if (!ChannelEnum::channelSupportsFeature($this->channel, 'payment')) { throw new Exception('当前渠道不支持支付功能'); } // 微信支付特殊验证 if ($payment === 'wechat') { if (!ChannelEnum::isWechatChannel($this->channel) && $this->channel !== ChannelEnum::CHANNEL_H5) { throw new Exception('当前渠道不支持微信支付'); } } } } /** * 记录支付日志 * @param string $message * @param array $context * @param string $level */ protected function logPayment($message, $context = [], $level = 'info') { $context = array_merge($context, [ 'payment' => $this->payService ? $this->payService->getPayment() : 'unknown', 'platform' => $this->platform, 'channel' => $this->channel, 'timestamp' => date('Y-m-d H:i:s') ]); Log::$level('支付日志: ' . $message, $context); } }