You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
ymww_backend/addons/epay/library/v3/Yansongda/Pay/Provider/AbstractProvider.php

160 lines
5.0 KiB

1 year ago
<?php
declare(strict_types=1);
namespace Yansongda\Pay\Provider;
use GuzzleHttp\Psr7\Utils;
use Psr\Http\Client\ClientInterface;
use Psr\Http\Message\MessageInterface;
use Throwable;
use Yansongda\Pay\Contract\HttpClientInterface;
use Yansongda\Pay\Contract\PluginInterface;
use Yansongda\Pay\Contract\ProviderInterface;
use Yansongda\Pay\Contract\ShortcutInterface;
use Yansongda\Pay\Direction\ArrayDirection;
use Yansongda\Pay\Event;
use Yansongda\Pay\Exception\ContainerException;
use Yansongda\Pay\Exception\Exception;
use Yansongda\Pay\Exception\InvalidConfigException;
use Yansongda\Pay\Exception\InvalidParamsException;
use Yansongda\Pay\Exception\InvalidResponseException;
use Yansongda\Pay\Exception\ServiceNotFoundException;
use Yansongda\Pay\Logger;
use Yansongda\Pay\Pay;
use Yansongda\Pay\Rocket;
use Yansongda\Supports\Collection;
use Yansongda\Supports\Pipeline;
use function Yansongda\Pay\should_do_http_request;
abstract class AbstractProvider implements ProviderInterface
{
/**
* @return null|array|Collection|MessageInterface
*
* @throws ContainerException
* @throws InvalidParamsException
* @throws ServiceNotFoundException
*/
public function call(string $plugin, array $params = [])
{
if (!class_exists($plugin) || !in_array(ShortcutInterface::class, class_implements($plugin))) {
throw new InvalidParamsException(Exception::SHORTCUT_NOT_FOUND, "[{$plugin}] is not incompatible");
}
/* @var ShortcutInterface $money */
$money = Pay::get($plugin);
$plugins = $money->getPlugins($params);
if (empty($params['_no_common_plugins'])) {
$plugins = $this->mergeCommonPlugins($plugins);
}
return $this->pay($plugins, $params);
}
/**
* @return null|array|Collection|MessageInterface
*
* @throws ContainerException
* @throws InvalidParamsException
*/
public function pay(array $plugins, array $params)
{
Logger::info('[AbstractProvider] 即将进行 pay 操作', func_get_args());
Event::dispatch(new Event\PayStarted($plugins, $params, null));
$this->verifyPlugin($plugins);
/* @var Pipeline $pipeline */
$pipeline = Pay::make(Pipeline::class);
/* @var Rocket $rocket */
$rocket = $pipeline
->send((new Rocket())->setParams($params)->setPayload(new Collection()))
->through($plugins)
->via('assembly')
->then(fn ($rocket) => $this->ignite($rocket))
;
Event::dispatch(new Event\PayFinish($rocket));
$destination = $rocket->getDestination();
if (ArrayDirection::class === $rocket->getDirection() && $destination instanceof Collection) {
return $destination->toArray();
}
return $destination;
}
/**
* @throws ContainerException
* @throws ServiceNotFoundException
* @throws InvalidResponseException
* @throws InvalidConfigException
*/
public function ignite(Rocket $rocket): Rocket
{
if (!should_do_http_request($rocket->getDirection())) {
return $rocket;
}
/* @var HttpClientInterface $http */
$http = Pay::get(HttpClientInterface::class);
if (!$http instanceof ClientInterface) {
throw new InvalidConfigException(Exception::HTTP_CLIENT_CONFIG_ERROR);
}
Logger::info('[AbstractProvider] 准备请求支付服务商 API', $rocket->toArray());
Event::dispatch(new Event\ApiRequesting($rocket));
try {
$response = $http->sendRequest($rocket->getRadar());
$contents = (string) $response->getBody();
$rocket->setDestination($response->withBody(Utils::streamFor($contents)))
->setDestinationOrigin($response->withBody(Utils::streamFor($contents)))
;
} catch (Throwable $e) {
Logger::error('[AbstractProvider] 请求支付服务商 API 出错', ['message' => $e->getMessage(), 'rocket' => $rocket->toArray(), 'trace' => $e->getTrace()]);
throw new InvalidResponseException(Exception::REQUEST_RESPONSE_ERROR, $e->getMessage(), [], $e);
}
Logger::info('[AbstractProvider] 请求支付服务商 API 成功', ['response' => $response, 'rocket' => $rocket->toArray()]);
Event::dispatch(new Event\ApiRequested($rocket));
return $rocket;
}
abstract public function mergeCommonPlugins(array $plugins): array;
/**
* @throws InvalidParamsException
*/
protected function verifyPlugin(array $plugins): void
{
foreach ($plugins as $plugin) {
if (is_callable($plugin)) {
continue;
}
if ((is_object($plugin)
|| (is_string($plugin) && class_exists($plugin)))
&& in_array(PluginInterface::class, class_implements($plugin))) {
continue;
}
throw new InvalidParamsException(Exception::PLUGIN_ERROR, "[{$plugin}] is not incompatible");
}
}
}