Test Failed
Pull Request — master (#1455)
by
unknown
05:19 queued 01:19
created

BaseClient::retryMiddleware()   A

Complexity

Conditions 6
Paths 1

Size

Total Lines 23
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 6

Importance

Changes 0
Metric Value
cc 6
eloc 13
nc 1
nop 0
dl 0
loc 23
ccs 4
cts 4
cp 1
crap 6
rs 9.2222
c 0
b 0
f 0
1
<?php
2
3
/*
4
 * This file is part of the overtrue/wechat.
5
 *
6
 * (c) overtrue <[email protected]>
7
 *
8
 * This source file is subject to the MIT license that is bundled
9
 * with this source code in the file LICENSE.
10
 */
11
12
namespace EasyWeChat\Kernel;
13
14
use EasyWeChat\Kernel\Contracts\AccessTokenInterface;
15
use EasyWeChat\Kernel\Http\Response;
16
use EasyWeChat\Kernel\Traits\HasHttpRequests;
17
use GuzzleHttp\MessageFormatter;
18
use GuzzleHttp\Middleware;
19
use Psr\Http\Message\RequestInterface;
20
use Psr\Http\Message\ResponseInterface;
21
22
/**
23
 * Class BaseClient.
24
 *
25
 * @author overtrue <[email protected]>
26
 */
27
class BaseClient
28
{
29
    use HasHttpRequests { request as performRequest; }
30
31
    /**
32
     * @var \EasyWeChat\Kernel\ServiceContainer
33
     */
34
    protected $app;
35
36
    /**
37
     * @var \EasyWeChat\Kernel\Contracts\AccessTokenInterface
38
     */
39
    protected $accessToken;
40
41
    /**
42
     * @var
43
     */
44
    protected $baseUri;
45
46
    /**
47
     * BaseClient constructor.
48
     *
49
     * @param \EasyWeChat\Kernel\ServiceContainer                    $app
50
     * @param \EasyWeChat\Kernel\Contracts\AccessTokenInterface|null $accessToken
51
     */
52
    public function __construct(ServiceContainer $app, AccessTokenInterface $accessToken = null)
53
    {
54 437
        $this->app = $app;
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 9 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
55
        $this->accessToken = $accessToken ?? $this->app['access_token'];
56 437
    }
57 437
58 437
    /**
59
     * GET request.
60
     *
61
     * @param string $url
62
     * @param array  $query
63
     *
64
     * @return \Psr\Http\Message\ResponseInterface|\EasyWeChat\Kernel\Support\Collection|array|object|string
65
     *
66
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
67
     */
68
    public function httpGet(string $url, array $query = [])
69
    {
70 1
        return $this->request($url, 'GET', ['query' => $query]);
71
    }
72 1
73
    /**
74
     * POST request.
75
     *
76
     * @param string $url
77
     * @param array  $data
78
     *
79
     * @return \Psr\Http\Message\ResponseInterface|\EasyWeChat\Kernel\Support\Collection|array|object|string
80
     *
81
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
82
     */
83
    public function httpPost(string $url, array $data = [])
84
    {
85 1
        return $this->request($url, 'POST', ['form_params' => $data]);
86
    }
87 1
88
    /**
89
     * JSON request.
90
     *
91
     * @param string       $url
92
     * @param string|array $data
93
     * @param array        $query
94
     *
95
     * @return \Psr\Http\Message\ResponseInterface|\EasyWeChat\Kernel\Support\Collection|array|object|string
96
     *
97
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
98
     */
99
    public function httpPostJson(string $url, array $data = [], array $query = [])
100
    {
101 1
        return $this->request($url, 'POST', ['query' => $query, 'json' => $data]);
102
    }
103 1
104
    /**
105
     * Upload file.
106
     *
107
     * @param string $url
108
     * @param array  $files
109
     * @param array  $form
110
     * @param array  $query
111
     *
112
     * @return \Psr\Http\Message\ResponseInterface|\EasyWeChat\Kernel\Support\Collection|array|object|string
113
     *
114
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
115
     */
116
    public function httpUpload(string $url, array $files = [], array $form = [], array $query = [])
117
    {
118 1
        $multipart = [];
119
120 1
        foreach ($files as $name => $path) {
121
            $multipart[] = [
122 1
                'name' => $name,
123 1
                'contents' => fopen($path, 'r'),
124 1
            ];
125 1
        }
126
127
        foreach ($form as $name => $contents) {
128
            $multipart[] = compact('name', 'contents');
129 1
        }
130 1
131
        return $this->request($url, 'POST', ['query' => $query, 'multipart' => $multipart, 'connect_timeout' => 30, 'timeout' => 30, 'read_timeout' => 30]);
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 140 characters; contains 156 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
132
    }
133 1
134
    /**
135
     * @return AccessTokenInterface
136
     */
137
    public function getAccessToken(): AccessTokenInterface
138
    {
139 1
        return $this->accessToken;
140
    }
141 1
142
    /**
143
     * @param \EasyWeChat\Kernel\Contracts\AccessTokenInterface $accessToken
144
     *
145
     * @return $this
146
     */
147
    public function setAccessToken(AccessTokenInterface $accessToken)
148
    {
149 1
        $this->accessToken = $accessToken;
150
151 1
        return $this;
152
    }
153 1
154
    /**
155
     * @param string $url
156
     * @param string $method
157
     * @param array  $options
158
     * @param bool   $returnRaw
159
     *
160
     * @return \Psr\Http\Message\ResponseInterface|\EasyWeChat\Kernel\Support\Collection|array|object|string
161
     *
162
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
163
     */
164
    public function request(string $url, string $method = 'GET', array $options = [], $returnRaw = false)
165
    {
166 1
        if (empty($this->middlewares)) {
167
            $this->registerHttpMiddlewares();
168 1
        }
169 1
170
        $response = $this->performRequest($url, $method, $options);
171
172 1
        return $returnRaw ? $response : $this->castResponseToType($response, $this->app->config->get('response_type'));
173
    }
174 1
175
    /**
176
     * @param string $url
177
     * @param string $method
178
     * @param array  $options
179
     *
180
     * @return \EasyWeChat\Kernel\Http\Response
181
     *
182
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
183
     */
184
    public function requestRaw(string $url, string $method = 'GET', array $options = [])
185
    {
186 1
        return Response::buildFromPsrResponse($this->request($url, $method, $options, true));
187
    }
188 1
189
    /**
190
     * Register Guzzle middlewares.
191
     */
192
    protected function registerHttpMiddlewares()
193
    {
194
        // retry
195
        $this->pushMiddleware($this->retryMiddleware(), 'retry');
196 1
        // access token
197
        $this->pushMiddleware($this->accessTokenMiddleware(), 'access_token');
198 1
        // log
199 1
        $this->pushMiddleware($this->logMiddleware(), 'log');
200
    }
201
202 1
    /**
203
     * Attache access token to request query.
204
     *
205
     * @return \Closure
206
     */
207
    protected function accessTokenMiddleware()
208 1
    {
209
        return function (callable $handler) {
210
            return function (RequestInterface $request, array $options) use ($handler) {
211 1
                if ($this->accessToken) {
212
                    $request = $this->accessToken->applyToRequest($request, $options);
213 1
                }
214
215 1
                return $handler($request, $options);
216 1
            };
217
        };
218
    }
219
220
    /**
221
     * Log the request.
222
     *
223
     * @return \Closure
224
     */
225
    protected function logMiddleware()
226 1
    {
227 1
        $formatter = new MessageFormatter($this->app['config']['http.log_template'] ?? MessageFormatter::DEBUG);
228 1
229
        return Middleware::log($this->app['logger'], $formatter);
230
    }
231 1
232 1
    /**
233 1
     * Return retry middleware.
234
     *
235
     * @return \Closure
236
     */
237
    protected function retryMiddleware()
238
    {
239
        return Middleware::retry(function (
240
            $retries,
241 1
            RequestInterface $request,
242
            ResponseInterface $response = null
243 1
        ) {
244
            // Limit the number of retries to 2
245 1
            if ($retries < $this->app->config->get('http.max_retries', 1) && $response && $body = $response->getBody()) {
246
                // Retry on server errors
247
                $response = json_decode($body, true);
248
249
                if (!empty($response['errcode']) && in_array(abs($response['errcode']), [40001, 40014, 42001], true)) {
250
                    $this->accessToken->refresh();
251
                    $this->app['logger']->debug('Retrying with refreshed access token.');
252
253
                    return true;
254
                }
255 1
            }
256
257
            return false;
258
        }, function () {
259
            return abs($this->app->config->get('http.retry_delay', 500));
260
        });
261 1
    }
262
}
263