Pay.php 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. <?php
  2. declare(strict_types=1);
  3. namespace Yansongda\Pay;
  4. use Closure;
  5. use Illuminate\Container\Container as LaravelContainer;
  6. use Psr\Container\ContainerInterface;
  7. use Psr\Container\NotFoundExceptionInterface;
  8. use Throwable;
  9. use Yansongda\Pay\Contract\DirectionInterface;
  10. use Yansongda\Pay\Contract\PackerInterface;
  11. use Yansongda\Pay\Contract\ServiceProviderInterface;
  12. use Yansongda\Pay\Direction\CollectionDirection;
  13. use Yansongda\Pay\Exception\ContainerException;
  14. use Yansongda\Pay\Exception\ContainerNotFoundException;
  15. use Yansongda\Pay\Exception\ServiceNotFoundException;
  16. use Yansongda\Pay\Packer\JsonPacker;
  17. use Yansongda\Pay\Provider\Alipay;
  18. use Yansongda\Pay\Provider\Unipay;
  19. use Yansongda\Pay\Provider\Wechat;
  20. use Yansongda\Pay\Service\AlipayServiceProvider;
  21. use Yansongda\Pay\Service\ConfigServiceProvider;
  22. use Yansongda\Pay\Service\ContainerServiceProvider;
  23. use Yansongda\Pay\Service\EventServiceProvider;
  24. use Yansongda\Pay\Service\HttpServiceProvider;
  25. use Yansongda\Pay\Service\LoggerServiceProvider;
  26. use Yansongda\Pay\Service\UnipayServiceProvider;
  27. use Yansongda\Pay\Service\WechatServiceProvider;
  28. /**
  29. * @method static Alipay alipay(array $config = [], $container = null)
  30. * @method static Wechat wechat(array $config = [], $container = null)
  31. * @method static Unipay unipay(array $config = [], $container = null)
  32. */
  33. class Pay
  34. {
  35. /**
  36. * 正常模式.
  37. */
  38. public const MODE_NORMAL = 0;
  39. /**
  40. * 沙箱模式.
  41. */
  42. public const MODE_SANDBOX = 1;
  43. /**
  44. * 服务商模式.
  45. */
  46. public const MODE_SERVICE = 2;
  47. /**
  48. * @var string[]
  49. */
  50. protected array $service = [
  51. AlipayServiceProvider::class,
  52. WechatServiceProvider::class,
  53. UnipayServiceProvider::class,
  54. ];
  55. /**
  56. * @var string[]
  57. */
  58. private array $coreService = [
  59. ContainerServiceProvider::class,
  60. ConfigServiceProvider::class,
  61. LoggerServiceProvider::class,
  62. EventServiceProvider::class,
  63. HttpServiceProvider::class,
  64. ];
  65. /**
  66. * @var null|Closure|ContainerInterface
  67. */
  68. private static $container;
  69. /**
  70. * @param null|Closure|ContainerInterface $container
  71. *
  72. * @throws ContainerException
  73. */
  74. private function __construct(array $config, $container = null)
  75. {
  76. $this->registerServices($config, $container);
  77. Pay::set(DirectionInterface::class, CollectionDirection::class);
  78. Pay::set(PackerInterface::class, JsonPacker::class);
  79. }
  80. /**
  81. * @return mixed
  82. *
  83. * @throws ContainerException
  84. * @throws ServiceNotFoundException
  85. */
  86. public static function __callStatic(string $service, array $config)
  87. {
  88. if (!empty($config)) {
  89. self::config(...$config);
  90. }
  91. return self::get($service);
  92. }
  93. /**
  94. * @param null|Closure|ContainerInterface $container
  95. *
  96. * @throws ContainerException
  97. */
  98. public static function config(array $config = [], $container = null): bool
  99. {
  100. if (self::hasContainer() && !($config['_force'] ?? false)) {
  101. return false;
  102. }
  103. new self($config, $container);
  104. return true;
  105. }
  106. /**
  107. * @codeCoverageIgnore
  108. *
  109. * @param mixed $value
  110. *
  111. * @throws ContainerException
  112. */
  113. public static function set(string $name, $value): void
  114. {
  115. try {
  116. $container = Pay::getContainer();
  117. if ($container instanceof LaravelContainer) {
  118. $container->singleton($name, $value instanceof Closure ? $value : static fn () => $value);
  119. return;
  120. }
  121. if (method_exists($container, 'set')) {
  122. $container->set(...func_get_args());
  123. return;
  124. }
  125. } catch (ContainerNotFoundException $e) {
  126. throw $e;
  127. } catch (Throwable $e) {
  128. throw new ContainerException($e->getMessage());
  129. }
  130. throw new ContainerException('Current container does NOT support `set` method');
  131. }
  132. /**
  133. * @codeCoverageIgnore
  134. *
  135. * @return mixed
  136. *
  137. * @throws ContainerException
  138. */
  139. public static function make(string $service, array $parameters = [])
  140. {
  141. try {
  142. $container = Pay::getContainer();
  143. if (method_exists($container, 'make')) {
  144. return $container->make(...func_get_args());
  145. }
  146. } catch (ContainerNotFoundException $e) {
  147. throw $e;
  148. } catch (Throwable $e) {
  149. throw new ContainerException($e->getMessage());
  150. }
  151. $parameters = array_values($parameters);
  152. return new $service(...$parameters);
  153. }
  154. /**
  155. * @return mixed
  156. *
  157. * @throws ServiceNotFoundException
  158. * @throws ContainerException
  159. */
  160. public static function get(string $service)
  161. {
  162. try {
  163. return Pay::getContainer()->get($service);
  164. } catch (NotFoundExceptionInterface $e) {
  165. throw new ServiceNotFoundException($e->getMessage());
  166. } catch (ContainerNotFoundException $e) {
  167. throw $e;
  168. } catch (Throwable $e) {
  169. throw new ContainerException($e->getMessage());
  170. }
  171. }
  172. /**
  173. * @throws ContainerNotFoundException
  174. */
  175. public static function has(string $service): bool
  176. {
  177. return Pay::getContainer()->has($service);
  178. }
  179. /**
  180. * @param null|Closure|ContainerInterface $container
  181. */
  182. public static function setContainer($container): void
  183. {
  184. self::$container = $container;
  185. }
  186. /**
  187. * @throws ContainerNotFoundException
  188. */
  189. public static function getContainer(): ContainerInterface
  190. {
  191. if (self::$container instanceof ContainerInterface) {
  192. return self::$container;
  193. }
  194. if (self::$container instanceof Closure) {
  195. return (self::$container)();
  196. }
  197. throw new ContainerNotFoundException('`getContainer()` failed! Maybe you should `setContainer()` first', Exception\Exception::CONTAINER_NOT_FOUND);
  198. }
  199. public static function hasContainer(): bool
  200. {
  201. return self::$container instanceof ContainerInterface || self::$container instanceof Closure;
  202. }
  203. public static function clear(): void
  204. {
  205. self::$container = null;
  206. }
  207. /**
  208. * @param mixed $data
  209. *
  210. * @throws ContainerException
  211. */
  212. public static function registerService(string $service, $data): void
  213. {
  214. $var = new $service();
  215. if ($var instanceof ServiceProviderInterface) {
  216. $var->register($data);
  217. }
  218. }
  219. /**
  220. * @param null|Closure|ContainerInterface $container
  221. *
  222. * @throws ContainerException
  223. */
  224. private function registerServices(array $config, $container = null): void
  225. {
  226. foreach (array_merge($this->coreService, $this->service) as $service) {
  227. self::registerService($service, ContainerServiceProvider::class == $service ? $container : $config);
  228. }
  229. }
  230. }