Completed
Push — master ( cdafa1...c7d4dc )
by Carlos
09:26
created

AbstractAPI::setHttp()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 6
ccs 3
cts 3
cp 1
rs 9.4285
cc 1
eloc 3
nc 1
nop 1
crap 1
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
/**
13
 * AbstractAPI.php.
14
 *
15
 * This file is part of the wechat-components.
16
 *
17
 * (c) overtrue <[email protected]>
18
 *
19
 * This source file is subject to the MIT license that is bundled
20
 * with this source code in the file LICENSE.
21
 */
22
namespace EasyWeChat\Core;
23
24
use EasyWeChat\Core\Exceptions\HttpException;
25
use EasyWeChat\Support\Collection;
26
use EasyWeChat\Support\Log;
27
use GuzzleHttp\Middleware;
28
use GuzzleHttp\Psr7\Uri;
29
use Psr\Http\Message\RequestInterface;
30
use Psr\Http\Message\ResponseInterface;
31
32
/**
33
 * Class AbstractAPI.
34
 */
35
abstract class AbstractAPI
36
{
37
    /**
38
     * Http instance.
39
     *
40
     * @var \EasyWeChat\Core\Http
41
     */
42
    protected $http;
43
44
    /**
45
     * The reqeust token.
46
     *
47
     * @var \EasyWeChat\Core\AccessToken
48
     */
49
    protected $accessToken;
50
51
    const GET = 'get';
52
    const POST = 'post';
53
    const JSON = 'json';
54
55
    /**
56
     * Constructor.
57
     *
58
     * @param \EasyWeChat\Core\AccessToken $accessToken
59
     */
60 80
    public function __construct(AccessToken $accessToken)
61
    {
62 80
        $this->setAccessToken($accessToken);
63
64 80
        $this->registerHttpMiddleware();
65 80
    }
66
67
    /**
68
     * Return the http instance.
69
     *
70
     * @return \EasyWeChat\Core\Http
71
     */
72 80
    public function getHttp()
73
    {
74 80
        return $this->http ?: $this->http = new Http();
75
    }
76
77
    /**
78
     * Set the http instance.
79
     *
80
     * @param \EasyWeChat\Core\Http $http
81
     *
82
     * @return $this
83
     */
84 9
    public function setHttp(Http $http)
85
    {
86 9
        $this->http = $http;
87
88 9
        return $this;
89
    }
90
91
    /**
92
     * Return the current accessToken.
93
     *
94
     * @return \EasyWeChat\Core\AccessToken
95
     */
96 5
    public function getAccessToken()
97
    {
98 5
        return $this->accessToken;
99
    }
100
101
    /**
102
     * Set the request token.
103
     *
104
     * @param \EasyWeChat\Core\AccessToken $accessToken
105
     *
106
     * @return $this
107
     */
108 80
    public function setAccessToken(AccessToken $accessToken)
109
    {
110 80
        $this->accessToken = $accessToken;
111
112 80
        return $this;
113
    }
114
115
    /**
116
     * Parse JSON from response and check error.
117
     *
118
     * @param string $method
119
     * @param array  $args
120
     *
121
     * @return \EasyWeChat\Support\Collection
122
     */
123 5
    public function parseJSON($method, array $args)
124
    {
125 5
        $http = $this->getHttp();
126
127 5
        $contents = $http->parseJSON(call_user_func_array([$http, $method], $args));
128
129 5
        $this->checkAndThrow($contents);
130
131 5
        return new Collection($contents);
132
    }
133
134
    /**
135
     * Set request access_token query.
136
     */
137 80
    protected function registerHttpMiddleware()
138
    {
139
        // access token
140 80
        $this->getHttp()->addMiddleware($this->accessTokenMiddleware());
141
        // log
142 80
        $this->getHttp()->addMiddleware($this->logMiddleware());
143
        // retry
144 80
        $this->getHttp()->addMiddleware($this->retryMiddleware());
145 80
    }
146
147
    /**
148
     * Attache access token to request query.
149
     *
150
     * @return \Closure
151
     */
152 80
    public function accessTokenMiddleware()
153
    {
154
        return function (callable $handler) {
155
            return function (RequestInterface $request, array $options) use ($handler) {
156
                if (!$this->accessToken) {
157
                    return $handler($request, $options);
158
                }
159
160
                $field = $this->accessToken->getQueryName();
161
                $token = $this->accessToken->getToken();
162
163
                $request = $request->withUri(Uri::withQueryValue($request->getUri(), $field, $token));
164
165
                return $handler($request, $options);
166
            };
167 80
        };
168
    }
169
170
    /**
171
     * Log the request.
172
     *
173
     * @return \Closure
174
     */
175 80
    public function logMiddleware()
176
    {
177
        return Middleware::tap(function (RequestInterface $request) {
178
            Log::debug("Request: {$request->getMethod()} {$request->getUri()}");
179
            Log::debug("Request Body: {$request->getBody()}");
180 80
        });
181
    }
182
183
    /**
184
     * Return retry middleware.
185
     *
186
     * @return \Closure
187
     */
188
    protected function retryMiddleware()
189
    {
190 80
        return Middleware::retry(function (
191
                                          $retries,
192
                                          RequestInterface $request,
193
                                          ResponseInterface $response = null
194
                                       ) {
195
            // Limit the number of retries to 2
196
            if ($retries <= 2 && $response && $body = $response->getBody()) {
197
                // Retry on server errors
198
                if (stripos($body, 'errcode') && (stripos($body, '40001') || stripos($body, '42001'))) {
199
                    $field = $this->accessToken->getQueryName();
200
                    $token = $this->accessToken->getToken();
201
202
                    $request = $request->withUri($newUri = Uri::withQueryValue($request->getUri(), $field, $token));
203
204
                    Log::debug("Retry with Request Token: {$token}");
205
                    Log::debug("Retry with Request Uri: {$newUri}");
206
207
                    return true;
208
                }
209
            }
210
211
            return false;
212 80
        });
213
    }
214
215
    /**
216
     * Check the array data erros, and Throw expcetion when the contents cotnains error.
217
     *
218
     * @param array $contents
219
     *
220
     * @throws \EasyWeChat\Core\Exceptions\HttpException
221
     */
222 6
    protected function checkAndThrow(array $contents)
223
    {
224 6
        if (isset($contents['errcode']) && 0 !== $contents['errcode']) {
225
            if (empty($contents['errmsg'])) {
226
                $contents['errmsg'] = 'Unknown';
227
            }
228
229
            throw new HttpException($contents['errmsg'], $contents['errcode']);
230
        }
231 6
    }
232
}
233