Passed
Push — master ( a1417a...6e4df4 )
by ihomyak
06:46
created

Api   A

Complexity

Total Complexity 30

Size/Duplication

Total Lines 246
Duplicated Lines 0 %

Test Coverage

Coverage 93.51%

Importance

Changes 2
Bugs 1 Features 0
Metric Value
wmc 30
eloc 65
c 2
b 1
f 0
dl 0
loc 246
ccs 72
cts 77
cp 0.9351
rs 10

18 Methods

Rating   Name   Duplication   Size   Complexity  
A isTest() 0 3 1
A setToken() 0 3 1
A getAccount() 0 3 1
A getSecure() 0 3 1
A setSecure() 0 3 1
A setAccount() 0 3 1
A authorize() 0 16 2
A setTest() 0 6 2
A getExpire() 0 3 1
A isExpired() 0 3 1
A __construct() 0 5 1
A getToken() 0 3 1
C request() 0 27 9
A post() 0 3 1
A get() 0 3 1
A delete() 0 3 1
A decodeBody() 0 7 3
A setExpire() 0 3 1
1
<?php
2
3
/**
4
 * Copyright (c) 2019. CDEK-IT. All rights reserved.
5
 * See LICENSE.md for license details.
6
 *
7
 * @author Chizhekov Viktor
8
 */
9
10
namespace CdekSDK2\Http;
11
12
use CdekSDK2\Constants;
13
use CdekSDK2\Exceptions\AuthException;
14
use CdekSDK2\Exceptions\RequestException;
15
use Nyholm\Psr7\Request;
16
use Nyholm\Psr7\Uri;
17
use Psr\Http\Client\ClientExceptionInterface;
18
use Psr\Http\Client\ClientInterface;
19
20
/**
21
 * Class Api
22
 * @package CdekSDK2\Http
23
 */
24
class Api
25
{
26
    /**
27
     * Аккаунт сервиса интеграции
28
     * @var string
29
     */
30
    private $account;
31
32
    /**
33
     * Секретный пароль сервиса интеграции
34
     * @var string
35
     */
36
    private $secure;
37
38
    /**
39
     * Тестовые настройки интеграции
40
     * @var bool
41
     */
42
    private $test = false;
43
44
    /**
45
     * @var string
46
     */
47
    private $token = '';
48
49
    /**
50
     * @var int
51
     */
52
    private $expire = 0;
53
54
    /**
55
     * @var ClientInterface
56
     */
57
    protected $client;
58
59
    /**
60
     * Api constructor.
61
     * @param ClientInterface $http
62
     * @param string|null $account
63
     * @param string|null $secure
64
     */
65 50
    public function __construct(ClientInterface $http, string $account = null, string $secure = null)
66
    {
67 50
        $this->account = $account ?? '';
68 50
        $this->secure = $secure ?? '';
69 50
        $this->client = $http;
70 50
    }
71
72
    /**
73
     *
74
     * @return string
75
     */
76 4
    public function getAccount(): string
77
    {
78 4
        return $this->account;
79
    }
80
81
    /**
82
     * @param string $account
83
     */
84 2
    public function setAccount(string $account)
85
    {
86 2
        $this->account = $account;
87 2
    }
88
89
    /**
90
     * @return string
91
     */
92 2
    public function getToken(): string
93
    {
94 2
        return $this->token;
95
    }
96
97
    /**
98
     * @param string $token
99
     */
100 1
    public function setToken(string $token)
101
    {
102 1
        $this->token = $token;
103 1
    }
104
105
    /**
106
     * @return string
107
     */
108 3
    public function getSecure(): string
109
    {
110 3
        return $this->secure;
111
    }
112
113
    /**
114
     * @param string $secure
115
     */
116 2
    public function setSecure(string $secure)
117
    {
118 2
        $this->secure = $secure;
119 2
    }
120
121
    /**
122
     * @return bool
123
     */
124 3
    public function isTest(): bool
125
    {
126 3
        return $this->test;
127
    }
128
129
    /**
130
     * @param bool $test
131
     */
132 30
    public function setTest(bool $test)
133
    {
134 30
        $this->test = $test;
135 30
        if ($test) {
136 30
            $this->account = Constants::TEST_ACCOUNT;
137 30
            $this->secure = Constants::TEST_SECURE;
138
        }
139 30
    }
140
141
    /**
142
     * Авторизация клиента в сервисе Интеграции
143
     * @return bool
144
     * @throws AuthException
145
     * @throws RequestException
146
     */
147 27
    public function authorize(): bool
148
    {
149
        $param = [
150 27
            Constants::AUTH_KEY_TYPE => Constants::AUTH_PARAM_CREDENTIAL,
151 27
            Constants::AUTH_KEY_CLIENT_ID => $this->account,
152 27
            Constants::AUTH_KEY_SECRET => $this->secure,
153
        ];
154 27
        $response = $this->post('/oauth/token', $param);
155 27
        if ($response->isOk()) {
156 26
            $token_info = $this->decodeBody($response->getBody());
157 26
            $this->token = $token_info['access_token'] ?? '';
158 26
            $this->expire = $token_info['expires_in'] ?? 0;
159 26
            $this->expire = (int)(time() + $this->expire - 10);
160 26
            return true;
161
        } else {
162 1
            throw new AuthException(Constants::AUTH_FAIL);
163
        }
164
    }
165
166
    /**
167
     * @return bool
168
     */
169 28
    public function isExpired(): bool
170
    {
171 28
        return $this->expire < time();
172
    }
173
174
    /**
175
     * @return int
176
     */
177 2
    public function getExpire(): int
178
    {
179 2
        return $this->expire;
180
    }
181
182
    /**
183
     * @param int $timestamp
184
     */
185 1
    public function setExpire(int $timestamp)
186
    {
187 1
        $this->expire = $timestamp;
188 1
    }
189
190
    /**
191
     * @param string $url
192
     * @param array $params
193
     * @return ApiResponse
194
     * @throws RequestException
195
     */
196 27
    public function post(string $url, array $params = []): ApiResponse
197
    {
198 27
        return $this->request('POST', $url, $params);
199
    }
200
201
    /**
202
     * @param string $url
203
     * @return ApiResponse
204
     * @throws RequestException
205
     */
206 15
    public function get(string $url): ApiResponse
207
    {
208 15
        return $this->request('GET', $url);
209
    }
210
211
    /**
212
     * @param string $url
213
     * @return ApiResponse
214
     * @throws RequestException
215
     */
216 4
    public function delete(string $url): ApiResponse
217
    {
218 4
        return $this->request('DELETE', $url);
219
    }
220
221
    /**
222
     * @param string $method
223
     * @param string $url
224
     * @param array $params
225
     * @return ApiResponse
226
     * @throws RequestException
227
     */
228 27
    protected function request(string $method, string $url, array $params = []): ApiResponse
229
    {
230 27
        $url = ($this->test ? Constants::API_URL_TEST : Constants::API_URL) . $url;
231 27
        $uri = new Uri($url);
232
        try {
233
            $headers = [
234 27
                'Accept' => 'application/json',
235
                'Content-Type' => 'application/json',
236
            ];
237 27
            if ($this->isExpired() && strripos($url, 'oauth/token') === false) {
238 25
                $this->authorize();
239 27
            } elseif (strripos($url, 'oauth/token') !== false) {
240 27
                $headers['Content-Type'] = 'application/x-www-form-urlencoded';
241
            }
242
243 27
            $body = (strripos($url, 'oauth/token') === false)
244 27
                ? (string)json_encode($params) : http_build_query($params);
245 27
            if (!empty($this->token)) {
246 22
                $headers['Authorization'] = 'Bearer ' . $this->token;
247
            }
248 27
            $request = new Request($method, $uri, $headers, $body);
249 27
            $response = $this->client->sendRequest($request);
250 27
            return new ApiResponse($response);
251
        } catch (ClientExceptionInterface $e) {
252
            throw new RequestException($e->getMessage(), (int)$e->getCode());
253
        } catch (\Exception $e) {
254
            throw new RequestException($e->getMessage(), (int)$e->getCode());
255
        }
256
    }
257
258
    /**
259
     * Преобразовываем json в массив
260
     * @param string $body
261
     * @return array
262
     */
263 26
    private function decodeBody(string $body): array
264
    {
265 26
        $decoded_body = json_decode($body, true);
266 26
        if ($decoded_body === null || !is_array($decoded_body)) {
267
            $decoded_body = [];
268
        }
269 26
        return $decoded_body;
270
    }
271
}
272