AccessToken::getToken()   A
last analyzed

Complexity

Conditions 3
Paths 2

Size

Total Lines 14
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 7
nc 2
nop 1
dl 0
loc 14
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * This file is part of the dingtalk.
4
 * User: Ilham Tahir <[email protected]>
5
 * This source file is subject to the MIT license that is bundled
6
 * with this source code in the file LICENSE.
7
 */
8
9
namespace Aplisin\DingTalk\Kernel;
10
11
use Aplisin\DingTalk\Kernel\Contracts\AccessTokenInterface;
12
use Aplisin\DingTalk\Kernel\Traits\HasHttpRequests;
13
use Aplisin\DingTalk\Kernel\Traits\InteractsWithCache;
14
use Pimple\Container;
15
use Psr\Http\Message\RequestInterface;
16
use Psr\Http\Message\ResponseInterface;
17
use Aplisin\DingTalk\Kernel\Exceptions\HttpException;
18
use Aplisin\DingTalk\Kernel\Exceptions\InvalidArgumentException;
19
20
abstract class AccessToken implements AccessTokenInterface
21
{
22
    use HasHttpRequests, InteractsWithCache;
0 ignored issues
show
Bug introduced by
The trait Aplisin\DingTalk\Kernel\Traits\HasHttpRequests requires the property $baseUri which is not provided by Aplisin\DingTalk\Kernel\AccessToken.
Loading history...
23
24
    protected $app;
25
26
    protected $requestMethod = 'GET';
27
28
    protected $endpointToGetToken;
29
30
    protected $queryName;
31
32
    protected $token;
33
34
    protected $safeSeconds = 500;
35
36
    protected $tokenKey = 'access_token';
37
38
    protected $cachePrefix = 'aplisindingtalk.kernel.access_token.';
39
40
    public function __construct(Container $app)
41
    {
42
        $this->app = $app;
43
    }
44
45
    public function getRefreshedToken(): array
46
    {
47
        return $this->getToken(true);
48
    }
49
50
    /**
51
     * @param bool $refresh
52
     * @return array
53
     * @throws Exceptions\InvalidConfigException
54
     * @throws HttpException
55
     * @throws InvalidArgumentException
56
     * @throws \GuzzleHttp\Exception\GuzzleException
57
     * @throws \Psr\SimpleCache\InvalidArgumentException
58
     */
59
    public function getToken(bool $refresh = false): array
60
    {
61
        $cacheKey = $this->getCacheKey();
62
        $cache = $this->getCache();
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 4 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...
63
64
        if (!$refresh && $cache->has($cacheKey)) {
65
            return $cache->get($cacheKey);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $cache->get($cacheKey) could return the type null which is incompatible with the type-hinted return array. Consider adding an additional type-check to rule them out.
Loading history...
66
        }
67
68
        $token = $this->requestToken($this->getCredentials(), true);
69
70
        $this->setToken($token[$this->tokenKey], $token['expires_in'] ?? 7200);
71
72
        return $token;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $token could return the type Aplisin\DingTalk\Kernel\...ssage\ResponseInterface which is incompatible with the type-hinted return array. Consider adding an additional type-check to rule them out.
Loading history...
73
    }
74
75
    /**
76
     * @param string $token
77
     * @param int $lifetime
78
     * @return AccessTokenInterface
79
     * @throws \Psr\SimpleCache\InvalidArgumentException
80
     */
81
    public function setToken(string $token, int $lifetime = 7200): AccessTokenInterface
82
    {
83
        $this->getCache()->set($this->getCacheKey(), [
84
            $this->tokenKey => $token,
85
            'expires_in' => $lifetime,
86
        ], $lifetime - $this->safeSeconds);
87
88
        return $this;
89
    }
90
91
    /**
92
     * @return AccessTokenInterface
93
     * @throws Exceptions\InvalidConfigException
94
     * @throws HttpException
95
     * @throws InvalidArgumentException
96
     * @throws \GuzzleHttp\Exception\GuzzleException
97
     * @throws \Psr\SimpleCache\InvalidArgumentException
98
     */
99
    public function refresh(): AccessTokenInterface
100
    {
101
        $this->getToken(true);
102
103
        return $this;
104
    }
105
106
    /**
107
     * @param array $credentials
108
     * @param bool $toArray
109
     * @return Http\Response|Support\Collection|array|mixed|ResponseInterface
110
     * @throws Exceptions\InvalidConfigException
111
     * @throws HttpException
112
     * @throws InvalidArgumentException
113
     * @throws \GuzzleHttp\Exception\GuzzleException
114
     */
115
    public function requestToken(array $credentials, $toArray = false)
116
    {
117
        $response = $this->sendRequest($credentials);
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 2 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...
118
        $result = json_decode($response->getBody()->getContents(), true);
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 4 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...
119
        $formatted = $this->castResponseToType($response, $this->app['config']->get('response_type'));
120
121
        if (empty($result[$this->tokenKey])) {
122
            throw new HttpException(
123
                'Request access_token fail: '.json_encode($result, JSON_UNESCAPED_UNICODE),
124
                $response,
125
                $formatted
126
            );
127
        }
128
129
        return $toArray ? $result : $formatted;
130
    }
131
132
133
    public function applyToRequest(RequestInterface $request, array $requestOptions = []): RequestInterface
134
    {
135
        parse_str($request->getUri()->getQuery(), $query);
136
137
        $query = http_build_query(array_merge($this->getQuery(), $query));
138
139
        return $request->withUri($request->getUri()->withQuery($query));
140
    }
141
142
    /**
143
     * @param array $credentials
144
     * @return ResponseInterface
145
     * @throws InvalidArgumentException
146
     * @throws \GuzzleHttp\Exception\GuzzleException
147
     */
148
    protected function sendRequest(array $credentials): ResponseInterface
149
    {
150
        $options = [
151
            ('GET' === $this->requestMethod) ? 'query' : 'json' => $credentials,
152
        ];
153
154
        return $this->setHttpClient($this->app['http_client'])
155
            ->request($this->getEndpoint(), $this->requestMethod, $options);
156
    }
157
158
    protected function getCacheKey()
159
    {
160
        return $this->cachePrefix.md5(json_encode($this->getCredentials()));
161
    }
162
163
    /**
164
     * @return array
165
     * @throws Exceptions\InvalidConfigException
166
     * @throws HttpException
167
     * @throws InvalidArgumentException
168
     * @throws \GuzzleHttp\Exception\GuzzleException
169
     * @throws \Psr\SimpleCache\InvalidArgumentException
170
     */
171
    protected function getQuery(): array
172
    {
173
        return [$this->queryName ?? $this->tokenKey => $this->getToken()[$this->tokenKey]];
174
    }
175
176
    /**
177
     * @return string
178
     * @throws InvalidArgumentException
179
     */
180
    public function getEndpoint(): string
181
    {
182
        if (empty($this->endpointToGetToken)) {
183
            throw new InvalidArgumentException('No endpoint for access token request.');
184
        }
185
186
        return $this->endpointToGetToken;
187
    }
188
189
    abstract protected function getCredentials(): array;
190
}
191