Passed
Push — master ( b682e4...9aa869 )
by Carlos
09:31 queued 11s
created

src/Kernel/AccessToken.php (1 issue)

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