PayService.php 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. <?php
  2. namespace app\common\Service\Pay;
  3. use think\Log;
  4. use think\Exception;
  5. use app\common\Enum\ChannelEnum;
  6. use app\common\Service\Pay\Provider\Base;
  7. use app\common\exception\BusinessException;
  8. /**
  9. * 支付服务类 - 工厂模式
  10. * 配合 yansongda 支付库
  11. */
  12. class PayService
  13. {
  14. protected $payment;
  15. protected $platform;
  16. protected $channel;
  17. /**
  18. * 构造函数
  19. * @param string $payment 支付方式 (wechat|alipay)
  20. * @param string $platform 平台标识 (可选)
  21. * @param string $channel 渠道标识 (可选)
  22. */
  23. public function __construct($payment, $platform = null, $channel = null)
  24. {
  25. $this->payment = $payment;
  26. $this->platform = $platform ?: $this->getPlatformFromRequest();
  27. $this->channel = $channel ?: $this->getChannelFromRequest();
  28. // 验证平台参数
  29. if (!$this->platform) {
  30. throw new BusinessException('缺少用户端平台参数');
  31. }
  32. // 验证渠道参数
  33. if ($this->channel && !ChannelEnum::isValidChannel($this->channel)) {
  34. throw new BusinessException('无效的渠道参数: ' . $this->channel);
  35. }
  36. // 验证支付方式
  37. if (!in_array($payment, ['wechat', 'alipay','douyin'])) {
  38. throw new BusinessException('不支持的支付方式: ' . $payment);
  39. }
  40. }
  41. /**
  42. * 获取支付提供器
  43. * @param string $payment 支付方式
  44. * @return Base
  45. * @throws Exception
  46. */
  47. public function provider($payment = null)
  48. {
  49. try {
  50. $payment = $payment ?: $this->payment;
  51. $className = "\\app\\common\\Service\\Pay\\Provider\\" . ucfirst(strtolower($payment));
  52. if (!class_exists($className)) {
  53. throw new Exception("支付提供器不存在: {$className}");
  54. }
  55. return new $className($this, $this->platform, $this->channel);
  56. } catch (\Exception $e) {
  57. Log::error('PayService provider error: ' . $e->getMessage());
  58. throw new Exception('支付类型不支持: ' . $payment);
  59. }
  60. }
  61. /**
  62. * 获取当前平台
  63. * @return string
  64. */
  65. public function getPlatform()
  66. {
  67. return $this->platform;
  68. }
  69. /**
  70. * 获取当前渠道
  71. * @return string
  72. */
  73. public function getChannel()
  74. {
  75. return $this->channel;
  76. }
  77. /**
  78. * 获取当前支付方式
  79. * @return string
  80. */
  81. public function getPayment()
  82. {
  83. return $this->payment;
  84. }
  85. /**
  86. * 从请求中获取平台参数
  87. * @return string|null
  88. */
  89. protected function getPlatformFromRequest()
  90. {
  91. $request = request();
  92. return $request->header('platform') ?: $request->param('platform');
  93. }
  94. /**
  95. * 从请求中获取渠道参数
  96. * @return string|null
  97. */
  98. protected function getChannelFromRequest()
  99. {
  100. $request = request();
  101. $channel = $request->header('channel') ?: $request->param('channel');
  102. // 如果没有明确的渠道参数,尝试从平台推断
  103. if (!$channel && $this->platform) {
  104. $channel = $this->inferChannelFromPlatform($this->platform);
  105. }
  106. return $channel;
  107. }
  108. /**
  109. * 从平台推断渠道
  110. * @param string $platform
  111. * @return string|null
  112. */
  113. protected function inferChannelFromPlatform($platform)
  114. {
  115. $platformToChannel = [
  116. 'WechatOfficialAccount' => ChannelEnum::CHANNEL_WECHAT_OFFICIAL_ACCOUNT,
  117. 'WechatMiniProgram' => ChannelEnum::CHANNEL_WECHAT_MINI_PROGRAM,
  118. 'H5' => ChannelEnum::CHANNEL_H5,
  119. 'App' => ChannelEnum::CHANNEL_ANDROID_APP, // 默认Android,可根据具体情况调整
  120. 'PC' => ChannelEnum::CHANNEL_PC,
  121. ];
  122. return $platformToChannel[$platform] ?? null;
  123. }
  124. /**
  125. * 验证支付环境
  126. * @param string $payment 支付方式
  127. * @param string $channel 渠道
  128. * @return bool
  129. * @throws Exception
  130. */
  131. public function validatePaymentEnvironment($payment, $channel = null)
  132. {
  133. $channel = $channel ?: $this->channel;
  134. if (!$channel) {
  135. return true; // 如果没有渠道信息,跳过验证
  136. }
  137. // 微信支付环境验证
  138. if ($payment === 'wechat') {
  139. if (!ChannelEnum::isWechatChannel($channel) && $channel !== ChannelEnum::CHANNEL_H5) {
  140. throw new BusinessException('当前渠道不支持微信支付');
  141. }
  142. }
  143. // 支付功能验证
  144. if (!ChannelEnum::channelSupportsFeature($channel, 'payment')) {
  145. throw new BusinessException('当前渠道不支持支付功能');
  146. }
  147. return true;
  148. }
  149. /**
  150. * 魔术方法,代理到支付提供器
  151. * @param string $funcname
  152. * @param array $arguments
  153. * @return mixed
  154. */
  155. public function __call($funcname, $arguments)
  156. {
  157. return $this->provider()->{$funcname}(...$arguments);
  158. }
  159. }