AccessToken   A
last analyzed

Complexity

Total Complexity 20

Size/Duplication

Total Lines 249
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 3
Bugs 0 Features 0
Metric Value
eloc 47
c 3
b 0
f 0
dl 0
loc 249
ccs 48
cts 48
cp 1
rs 10
wmc 20

12 Methods

Rating   Name   Duplication   Size   Complexity  
A sendRequest() 0 7 2
A getCacheKey() 0 3 1
A getQuery() 0 3 1
A getEndpoint() 0 7 2
A requestToken() 0 11 3
A refresh() 0 5 1
A getRefreshedToken() 0 3 1
A getTokenKey() 0 3 1
A applyToRequest() 0 7 1
A setToken() 0 12 2
A __construct() 0 3 1
A getToken() 0 17 4
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\Exceptions\HttpException;
16
use EasyWeChat\Kernel\Exceptions\InvalidArgumentException;
17
use EasyWeChat\Kernel\Exceptions\RuntimeException;
18
use EasyWeChat\Kernel\Traits\HasHttpRequests;
19
use EasyWeChat\Kernel\Traits\InteractsWithCache;
20
use Psr\Http\Message\RequestInterface;
21
use Psr\Http\Message\ResponseInterface;
22
23
/**
24
 * Class AccessToken.
25
 *
26
 * @author overtrue <[email protected]>
27
 */
28
abstract class AccessToken implements AccessTokenInterface
29
{
30
    use HasHttpRequests;
0 ignored issues
show
Bug introduced by
The trait EasyWeChat\Kernel\Traits\HasHttpRequests requires the property $baseUri which is not provided by EasyWeChat\Kernel\AccessToken.
Loading history...
31
    use InteractsWithCache;
32
33
    /**
34
     * @var \EasyWeChat\Kernel\ServiceContainer
35
     */
36
    protected $app;
37
38
    /**
39
     * @var string
40
     */
41
    protected $requestMethod = 'GET';
42
43
    /**
44
     * @var string
45
     */
46
    protected $endpointToGetToken;
47
48
    /**
49
     * @var string
50
     */
51
    protected $queryName;
52
53
    /**
54
     * @var array
55
     */
56
    protected $token;
57
58
    /**
59
     * @var string
60
     */
61
    protected $tokenKey = 'access_token';
62
63
    /**
64
     * @var string
65
     */
66
    protected $cachePrefix = 'easywechat.kernel.access_token.';
67
68
    /**
69
     * AccessToken constructor.
70
     *
71
     * @param \EasyWeChat\Kernel\ServiceContainer $app
72
     */
73 49
    public function __construct(ServiceContainer $app)
74
    {
75 49
        $this->app = $app;
76 49
    }
77
78
    /**
79
     * @return array
80
     *
81
     * @throws \EasyWeChat\Kernel\Exceptions\HttpException
82
     * @throws \Psr\SimpleCache\InvalidArgumentException
83
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
84
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException
85
     * @throws \EasyWeChat\Kernel\Exceptions\RuntimeException
86
     */
87 1
    public function getRefreshedToken(): array
88
    {
89 1
        return $this->getToken(true);
90
    }
91
92
    /**
93
     * @param bool $refresh
94
     *
95
     * @return array
96
     *
97
     * @throws \EasyWeChat\Kernel\Exceptions\HttpException
98
     * @throws \Psr\SimpleCache\InvalidArgumentException
99
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
100
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException
101
     * @throws \EasyWeChat\Kernel\Exceptions\RuntimeException
102
     */
103 1
    public function getToken(bool $refresh = false): array
104
    {
105 1
        $cacheKey = $this->getCacheKey();
106 1
        $cache = $this->getCache();
107
108 1
        if (!$refresh && $cache->has($cacheKey) && $result = $cache->get($cacheKey)) {
109 1
            return $result;
110
        }
111
112
        /** @var array $token */
113 1
        $token = $this->requestToken($this->getCredentials(), true);
114
115 1
        $this->setToken($token[$this->tokenKey], $token['expires_in'] ?? 7200);
116
117 1
        $this->app->events->dispatch(new Events\AccessTokenRefreshed($this));
118
119 1
        return $token;
120
    }
121
122
    /**
123
     * @param string $token
124
     * @param int    $lifetime
125
     *
126
     * @return \EasyWeChat\Kernel\Contracts\AccessTokenInterface
127
     *
128
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException
129
     * @throws \EasyWeChat\Kernel\Exceptions\RuntimeException
130
     * @throws \Psr\SimpleCache\InvalidArgumentException
131
     */
132 1
    public function setToken(string $token, int $lifetime = 7200): AccessTokenInterface
133
    {
134 1
        $this->getCache()->set($this->getCacheKey(), [
135 1
            $this->tokenKey => $token,
136 1
            'expires_in' => $lifetime,
137
        ], $lifetime);
138
139 1
        if (!$this->getCache()->has($this->getCacheKey())) {
140 1
            throw new RuntimeException('Failed to cache access token.');
141
        }
142
143 1
        return $this;
144
    }
145
146
    /**
147
     * @return \EasyWeChat\Kernel\Contracts\AccessTokenInterface
148
     *
149
     * @throws \EasyWeChat\Kernel\Exceptions\HttpException
150
     * @throws \Psr\SimpleCache\InvalidArgumentException
151
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
152
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException
153
     * @throws \EasyWeChat\Kernel\Exceptions\RuntimeException
154
     */
155 1
    public function refresh(): AccessTokenInterface
156
    {
157 1
        $this->getToken(true);
158
159 1
        return $this;
160
    }
161
162
    /**
163
     * @param array $credentials
164
     * @param bool  $toArray
165
     *
166
     * @return \Psr\Http\Message\ResponseInterface|\EasyWeChat\Kernel\Support\Collection|array|object|string
167
     *
168
     * @throws \EasyWeChat\Kernel\Exceptions\HttpException
169
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
170
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException
171
     */
172 1
    public function requestToken(array $credentials, $toArray = false)
173
    {
174 1
        $response = $this->sendRequest($credentials);
175 1
        $result = json_decode($response->getBody()->getContents(), true);
176 1
        $formatted = $this->castResponseToType($response, $this->app['config']->get('response_type'));
177
178 1
        if (empty($result[$this->tokenKey])) {
179 1
            throw new HttpException('Request access_token fail: '.json_encode($result, JSON_UNESCAPED_UNICODE), $response, $formatted);
180
        }
181
182 1
        return $toArray ? $result : $formatted;
183
    }
184
185
    /**
186
     * @param \Psr\Http\Message\RequestInterface $request
187
     * @param array                              $requestOptions
188
     *
189
     * @return \Psr\Http\Message\RequestInterface
190
     *
191
     * @throws \EasyWeChat\Kernel\Exceptions\HttpException
192
     * @throws \Psr\SimpleCache\InvalidArgumentException
193
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
194
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException
195
     * @throws \EasyWeChat\Kernel\Exceptions\RuntimeException
196
     */
197 1
    public function applyToRequest(RequestInterface $request, array $requestOptions = []): RequestInterface
198
    {
199 1
        parse_str($request->getUri()->getQuery(), $query);
200
201 1
        $query = http_build_query(array_merge($this->getQuery(), $query));
202
203 1
        return $request->withUri($request->getUri()->withQuery($query));
204
    }
205
206
    /**
207
     * Send http request.
208
     *
209
     * @param array $credentials
210
     *
211
     * @return ResponseInterface
212
     *
213
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException
214
     * @throws \GuzzleHttp\Exception\GuzzleException
215
     */
216 1
    protected function sendRequest(array $credentials): ResponseInterface
217
    {
218
        $options = [
219 1
            ('GET' === $this->requestMethod) ? 'query' : 'json' => $credentials,
220
        ];
221
222 1
        return $this->setHttpClient($this->app['http_client'])->request($this->getEndpoint(), $this->requestMethod, $options);
223
    }
224
225
    /**
226
     * @return string
227
     */
228 1
    protected function getCacheKey()
229
    {
230 1
        return $this->cachePrefix.md5(json_encode($this->getCredentials()));
231
    }
232
233
    /**
234
     * The request query will be used to add to the request.
235
     *
236
     * @return array
237
     *
238
     * @throws \EasyWeChat\Kernel\Exceptions\HttpException
239
     * @throws \Psr\SimpleCache\InvalidArgumentException
240
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
241
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException
242
     * @throws \EasyWeChat\Kernel\Exceptions\RuntimeException
243
     */
244 1
    protected function getQuery(): array
245
    {
246 1
        return [$this->queryName ?? $this->tokenKey => $this->getToken()[$this->tokenKey]];
247
    }
248
249
    /**
250
     * @return string
251
     *
252
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException
253
     */
254 2
    public function getEndpoint(): string
255
    {
256 2
        if (empty($this->endpointToGetToken)) {
257 1
            throw new InvalidArgumentException('No endpoint for access token request.');
258
        }
259
260 2
        return $this->endpointToGetToken;
261
    }
262
263
    /**
264
     * @return string
265
     */
266 1
    public function getTokenKey()
267
    {
268 1
        return $this->tokenKey;
269
    }
270
271
    /**
272
     * Credential for get token.
273
     *
274
     * @return array
275
     */
276
    abstract protected function getCredentials(): array;
277
}
278