Passed
Push — master ( 9713c0...15fcb4 )
by Songda
03:12 queued 01:13
created

AbstractProvider::verifyPlugin()   B

Complexity

Conditions 7
Paths 4

Size

Total Lines 14
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 8
c 1
b 0
f 0
dl 0
loc 14
rs 8.8333
cc 7
nc 4
nop 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yansongda\Pay\Provider;
6
7
use Psr\Http\Client\ClientInterface;
8
use Psr\Http\Message\MessageInterface;
9
use Throwable;
10
use Yansongda\Pay\Contract\HttpClientInterface;
11
use Yansongda\Pay\Contract\PluginInterface;
12
use Yansongda\Pay\Contract\ProviderInterface;
13
use Yansongda\Pay\Contract\ShortcutInterface;
14
use Yansongda\Pay\Event;
15
use Yansongda\Pay\Exception\ContainerException;
16
use Yansongda\Pay\Exception\Exception;
17
use Yansongda\Pay\Exception\InvalidConfigException;
18
use Yansongda\Pay\Exception\InvalidParamsException;
19
use Yansongda\Pay\Exception\InvalidResponseException;
20
use Yansongda\Pay\Exception\ServiceNotFoundException;
21
use Yansongda\Pay\Logger;
22
use Yansongda\Pay\Pay;
23
use Yansongda\Pay\Rocket;
24
use Yansongda\Supports\Collection;
25
use Yansongda\Supports\Pipeline;
26
27
use function Yansongda\Pay\should_do_http_request;
28
29
abstract class AbstractProvider implements ProviderInterface
30
{
31
    /**
32
     * @throws ContainerException
33
     * @throws InvalidParamsException
34
     * @throws ServiceNotFoundException
35
     */
36
    public function shortcut(string $shortcut, array $params = []): null|Collection|MessageInterface|Rocket
37
    {
38
        if (!class_exists($shortcut) || !in_array(ShortcutInterface::class, class_implements($shortcut))) {
39
            throw new InvalidParamsException(Exception::PARAMS_SHORTCUT_NOT_FOUND, "参数异常: [{$shortcut}] 未实现 `ShortcutInterface`");
40
        }
41
42
        /* @var ShortcutInterface $shortcutInstance */
43
        $shortcutInstance = Pay::get($shortcut);
44
45
        return $this->pay($shortcutInstance->getPlugins($params), $params);
46
    }
47
48
    /**
49
     * @throws ContainerException
50
     * @throws InvalidParamsException
51
     */
52
    public function pay(array $plugins, array $params): null|Collection|MessageInterface|Rocket
53
    {
54
        Logger::info('[AbstractProvider] 即将进行 pay 操作', func_get_args());
55
56
        Event::dispatch(new Event\PayStarted($plugins, $params, null));
57
58
        $this->verifyPlugin($plugins);
59
60
        /* @var Pipeline $pipeline */
61
        $pipeline = Pay::make(Pipeline::class);
62
63
        /* @var Rocket $rocket */
64
        $rocket = $pipeline
65
            ->send((new Rocket())->setParams($params)->setPayload(new Collection()))
66
            ->through($plugins)
67
            ->via('assembly')
68
            ->then(fn ($rocket) => $this->ignite($rocket));
69
70
        Event::dispatch(new Event\PayFinish($rocket));
71
72
        if (!empty($params['_return_rocket'])) {
73
            return $rocket;
74
        }
75
76
        return $rocket->getDestination();
77
    }
78
79
    /**
80
     * @throws ContainerException
81
     * @throws ServiceNotFoundException
82
     * @throws InvalidResponseException
83
     * @throws InvalidConfigException
84
     */
85
    public function ignite(Rocket $rocket): Rocket
86
    {
87
        if (!should_do_http_request($rocket->getDirection())) {
88
            return $rocket;
89
        }
90
91
        /* @var HttpClientInterface $http */
92
        $http = Pay::get(HttpClientInterface::class);
93
94
        if (!$http instanceof ClientInterface) {
0 ignored issues
show
introduced by
$http is always a sub-type of Psr\Http\Client\ClientInterface.
Loading history...
95
            throw new InvalidConfigException(Exception::CONFIG_HTTP_CLIENT_INVALID, '配置异常: 配置的 ClientInterface 不符合 PSR 规范');
96
        }
97
98
        Logger::info('[AbstractProvider] 准备请求支付服务商 API', $rocket->toArray());
99
100
        Event::dispatch(new Event\ApiRequesting($rocket));
101
102
        try {
103
            $response = $http->sendRequest($rocket->getRadar());
0 ignored issues
show
Bug introduced by
It seems like $rocket->getRadar() can also be of type null; however, parameter $request of Psr\Http\Client\ClientInterface::sendRequest() does only seem to accept Psr\Http\Message\RequestInterface, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

103
            $response = $http->sendRequest(/** @scrutinizer ignore-type */ $rocket->getRadar());
Loading history...
104
105
            $rocket->setDestination(clone $response)
106
                ->setDestinationOrigin(clone $response);
107
        } catch (Throwable $e) {
108
            Logger::error('[AbstractProvider] 请求支付服务商 API 出错', ['message' => $e->getMessage(), 'rocket' => $rocket->toArray(), 'trace' => $e->getTrace()]);
109
110
            throw new InvalidResponseException(Exception::REQUEST_RESPONSE_ERROR, '响应异常: 请求支付服务商 API 出错 - '.$e->getMessage(), [], $e);
111
        }
112
113
        Logger::info('[AbstractProvider] 请求支付服务商 API 成功', ['response' => ['status' => $response->getStatusCode(), 'headers' => $response->getHeaders(), 'body' => (string) $response->getBody()], 'rocket' => $rocket->toArray()]);
114
115
        Event::dispatch(new Event\ApiRequested($rocket));
116
117
        return $rocket;
118
    }
119
120
    abstract public function mergeCommonPlugins(array $plugins): array;
121
122
    /**
123
     * @throws InvalidParamsException
124
     */
125
    protected function verifyPlugin(array $plugins): void
126
    {
127
        foreach ($plugins as $plugin) {
128
            if (is_callable($plugin)) {
129
                continue;
130
            }
131
132
            if ((is_object($plugin)
0 ignored issues
show
introduced by
Consider adding parentheses for clarity. Current Interpretation: (is_object($plugin) || i...ss_implements($plugin)), Probably Intended Meaning: is_object($plugin) || (i...s_implements($plugin)))
Loading history...
133
                    || (is_string($plugin) && class_exists($plugin)))
134
                && in_array(PluginInterface::class, class_implements($plugin))) {
135
                continue;
136
            }
137
138
            throw new InvalidParamsException(Exception::PARAMS_PLUGIN_INCOMPATIBLE, "参数异常: [{$plugin}] 插件未实现 `PluginInterface`");
139
        }
140
    }
141
}
142