AbstractAPI   A
last analyzed

Complexity

Total Complexity 23

Size/Duplication

Total Lines 204
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 9

Importance

Changes 0
Metric Value
dl 0
loc 204
rs 10
c 0
b 0
f 0
wmc 23
lcom 1
cbo 9

11 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
A getHttp() 0 12 3
A setHttp() 0 6 1
A getAccessToken() 0 4 1
A setAccessToken() 0 6 1
A parseJSON() 0 10 1
A registerHttpMiddlewares() 0 9 1
A accessTokenMiddleware() 0 17 2
A logMiddleware() 0 7 1
C retryMiddleware() 0 26 7
A checkAndThrow() 0 10 4
1
<?php
2
3
namespace EntWeChat\Core;
4
5
use EntWeChat\Core\Exceptions\HttpException;
6
use EntWeChat\Support\Collection;
7
use EntWeChat\Support\Log;
8
use GuzzleHttp\Middleware;
9
use GuzzleHttp\Psr7\Uri;
10
use Psr\Http\Message\RequestInterface;
11
use Psr\Http\Message\ResponseInterface;
12
13
/**
14
 * Class AbstractAPI.
15
 */
16
abstract class AbstractAPI
17
{
18
    /**
19
     * Http instance.
20
     *
21
     * @var \EntWeChat\Core\Http
22
     */
23
    protected $http;
24
25
    /**
26
     * The request token.
27
     *
28
     * @var \EntWeChat\Core\AccessToken
29
     */
30
    protected $accessToken;
31
32
    const GET = 'get';
33
    const POST = 'post';
34
    const JSON = 'json';
35
36
    /**
37
     * Constructor.
38
     *
39
     * @param \EntWeChat\Core\AccessToken $accessToken
40
     */
41
    public function __construct(AccessToken $accessToken)
42
    {
43
        $this->setAccessToken($accessToken);
44
    }
45
46
    /**
47
     * Return the http instance.
48
     *
49
     * @return \EntWeChat\Core\Http
50
     */
51
    public function getHttp()
52
    {
53
        if (is_null($this->http)) {
54
            $this->http = new Http();
55
        }
56
57
        if (count($this->http->getMiddlewares()) === 0) {
58
            $this->registerHttpMiddlewares();
59
        }
60
61
        return $this->http;
62
    }
63
64
    /**
65
     * Set the http instance.
66
     *
67
     * @param \EntWeChat\Core\Http $http
68
     *
69
     * @return $this
70
     */
71
    public function setHttp(Http $http)
72
    {
73
        $this->http = $http;
74
75
        return $this;
76
    }
77
78
    /**
79
     * Return the current accessToken.
80
     *
81
     * @return \EntWeChat\Core\AccessToken
82
     */
83
    public function getAccessToken()
84
    {
85
        return $this->accessToken;
86
    }
87
88
    /**
89
     * Set the request token.
90
     *
91
     * @param \EntWeChat\Core\AccessToken $accessToken
92
     *
93
     * @return $this
94
     */
95
    public function setAccessToken(AccessToken $accessToken)
96
    {
97
        $this->accessToken = $accessToken;
98
99
        return $this;
100
    }
101
102
    /**
103
     * Parse JSON from response and check error.
104
     *
105
     * @param string $method
106
     * @param array  $args
107
     *
108
     * @return \EntWeChat\Support\Collection
109
     */
110
    public function parseJSON($method, array $args)
111
    {
112
        $http = $this->getHttp();
113
114
        $contents = $http->parseJSON(call_user_func_array([$http, $method], $args));
115
116
        $this->checkAndThrow($contents);
117
118
        return new Collection($contents);
119
    }
120
121
    /**
122
     * Register Guzzle middlewares.
123
     */
124
    protected function registerHttpMiddlewares()
125
    {
126
        // log
127
        $this->http->addMiddleware($this->logMiddleware());
128
        // retry
129
        $this->http->addMiddleware($this->retryMiddleware());
130
        // access token
131
        $this->http->addMiddleware($this->accessTokenMiddleware());
132
    }
133
134
    /**
135
     * Attache access token to request query.
136
     *
137
     * @return \Closure
138
     */
139
    protected function accessTokenMiddleware()
140
    {
141
        return function (callable $handler) {
142
            return function (RequestInterface $request, array $options) use ($handler) {
143
                if (!$this->accessToken) {
144
                    return $handler($request, $options);
145
                }
146
147
                $field = $this->accessToken->getQueryName();
148
                $token = $this->accessToken->getToken();
149
150
                $request = $request->withUri(Uri::withQueryValue($request->getUri(), $field, $token));
151
152
                return $handler($request, $options);
153
            };
154
        };
155
    }
156
157
    /**
158
     * Log the request.
159
     *
160
     * @return \Closure
161
     */
162
    protected function logMiddleware()
163
    {
164
        return Middleware::tap(function (RequestInterface $request, $options) {
165
            Log::debug("Request: {$request->getMethod()} {$request->getUri()} ".json_encode($options));
166
            Log::debug('Request headers:'.json_encode($request->getHeaders()));
167
        });
168
    }
169
170
    /**
171
     * Return retry middleware.
172
     *
173
     * @return \Closure
174
     */
175
    protected function retryMiddleware()
176
    {
177
        return Middleware::retry(function (
178
            $retries,
179
            RequestInterface $request,
180
            ResponseInterface $response = null
181
        ) {
182
            // Limit the number of retries to 2
183
            if ($retries <= 2 && $response && $body = $response->getBody()) {
184
                // Retry on server errors
185
                if (stripos($body, 'errcode') && (stripos($body, '40001') || stripos($body, '42001'))) {
186
                    $field = $this->accessToken->getQueryName();
187
                    $token = $this->accessToken->getToken(true);
188
189
                    $request = $request->withUri($newUri = Uri::withQueryValue($request->getUri(), $field, $token));
0 ignored issues
show
Unused Code introduced by
$request is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
190
191
                    Log::debug("Retry with Request Token: {$token}");
192
                    Log::debug("Retry with Request Uri: {$newUri}");
193
194
                    return true;
195
                }
196
            }
197
198
            return false;
199
        });
200
    }
201
202
    /**
203
     * Check the array data errors, and Throw exception when the contents contains error.
204
     *
205
     * @param array $contents
206
     *
207
     * @throws \EntWeChat\Core\Exceptions\HttpException
208
     */
209
    protected function checkAndThrow(array $contents)
210
    {
211
        if (isset($contents['errcode']) && 0 !== $contents['errcode']) {
212
            if (empty($contents['errmsg'])) {
213
                $contents['errmsg'] = 'Unknown';
214
            }
215
216
            throw new HttpException($contents['errmsg'], $contents['errcode']);
217
        }
218
    }
219
}
220