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