Passed
Push — master ( a8856e...86e1ec )
by Yao
01:33
created

Sobot::checkConfig()   A

Complexity

Conditions 5
Paths 3

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 5
c 1
b 0
f 0
dl 0
loc 8
rs 9.6111
cc 5
nc 3
nop 2
1
<?php
2
3
4
namespace MuCTS\Sobot\Contracts;
5
6
7
use Exception;
8
use GuzzleHttp\Client;
9
use GuzzleHttp\Exception\RequestException;
10
use MuCTS\Sobot\Code;
11
use MuCTS\Sobot\Exceptions\ConfigException;
12
use MuCTS\Sobot\Exceptions\NotFoundException;
13
use MuCTS\Sobot\Exceptions\ResponseException;
14
use MuCTS\Sobot\Exceptions\SobotException;
15
use MuCTS\Sobot\Token\Token;
16
use Psr\Http\Message\StreamInterface;
17
18
/**
19
 * Class Sobot
20
 * @property-read Request $request
21
 * @package MuCTS\Sobot\Contracts
22
 */
23
abstract class Sobot
24
{
25
    /** @var array */
26
    private $config;
27
    /** @var string */
28
    private $host;
29
    /** @var Cache|null */
30
    protected $cache;
31
    /** @var int 超时时间 */
32
    protected $timeout = 15;
33
    /** @var array */
34
    protected $headers = [];
35
    /** @var string */
36
    protected $contentType = 'json';
37
    /** @var bool 尝试次数 */
38
    private $updatingToken = false;
39
40
    const METHOD_GET = 'get';
41
    const METHOD_POST = 'post';
42
    const METHOD_PUT = 'put';
43
    const METHOD_DELETE = 'delete';
44
45
    /**
46
     * Sobot constructor.
47
     * @param array $config
48
     * @param Cache|null $cache
49
     * @throws ConfigException
50
     */
51
    public function __construct(array $config, ?Cache $cache = null)
52
    {
53
        $this->setConfig($config);
54
        $this->host = 'https://www.sobot.com';
55
        $this->cache = $cache;
56
    }
57
58
    /**
59
     * 校验配置参数
60
     *
61
     * @param string $key
62
     * @param bool $isRequired
63
     * @throws ConfigException
64
     */
65
    public function checkConfig(string $key, bool $isRequired = true)
66
    {
67
        $value = array_get($this->config, $key);
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $value is correct as array_get($this->config, $key) seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
68
        if ($isRequired && empty($value)) {
69
            throw new ConfigException(sprintf('%s cannot be empty', $key));
70
        }
71
        if ($value && !is_string($value)) {
72
            throw new ConfigException(sprintf('please enter the correct %s', $key));
73
        }
74
    }
75
76
    /**
77
     * 设置配置
78
     *
79
     * @param array $config
80
     * @throws ConfigException
81
     * @author herry.yao <[email protected]>
82
     * @version 1.2.2
83
     * @date 2020-08-04
84
     */
85
    public function setConfig(array $config): void
86
    {
87
        $this->config = $config;
88
        $this->checkConfig('app_id');
89
        $this->checkConfig('app_key');
90
    }
91
92
    /**
93
     * get app id
94
     * @return string
95
     * @author herry.yao <[email protected]>
96
     * @version 1.2.2
97
     * @date 2020-08-04
98
     */
99
    public function getAppId(): string
100
    {
101
        return $this->config['app_id'];
102
    }
103
104
    /**
105
     * get app key
106
     *
107
     * @return string
108
     * @author herry.yao <[email protected]>
109
     * @version 1.2.2
110
     * @date 2020-08-04
111
     */
112
    protected function getAppKey(): string
113
    {
114
        return $this->config['app_key'];
115
    }
116
117
    /**
118
     * 接口请求地址
119
     *
120
     * @return string
121
     * @author herry.yao <[email protected]>
122
     * @version 1.2.2
123
     * @date 2020-08-04
124
     */
125
    protected function getRequestUrl(): string
126
    {
127
        return sprintf('%s/%s', rtrim($this->host), ltrim($this->getRequestPath()));
128
    }
129
130
    /**
131
     * 网络请求
132
     *
133
     * @return StreamInterface
134
     * @throws ConfigException
135
     * @throws ResponseException
136
     * @throws SobotException
137
     * @throws \GuzzleHttp\Exception\GuzzleException
138
     */
139
    protected function httpRequest(): StreamInterface
140
    {
141
        $params = $this->getRequestParam()->toArray();
142
        $method = $this->getRequestMethod();
143
        $client = new Client(["headers" => $this->getHeader(), "timeout" => $this->getTimeout()]);
144
        try {
145
            $response = $client->request($method, $this->getRequestUrl(), [$this->getContentType() => $params]);
146
        } catch (RequestException $exception) {
147
            $response = $exception->getResponse();
148
        } catch (Exception $exception) {
149
            throw  new SobotException($exception->getMessage(), $exception->getCode(), $exception->getPrevious());
150
        }
151
        $status = $response->getStatusCode();
152
        $content = $response->getBody();
153
        if ($status != 200) {
154
            throw new ResponseException('Abnormal response', $status, $content);
155
        }
156
        return $content;
157
    }
158
159
    /**
160
     * 确认是否是Token失效
161
     *
162
     * @param string $retCode
163
     * @return bool
164
     */
165
    protected function tokenIsInvalid(string $retCode)
166
    {
167
        return !$this->updatingToken && $retCode == Code::TOKEN_IS_INVALID && !($this instanceof Token);
168
    }
169
170
    /**
171
     * 接口请求
172
     *
173
     * @return Response
174
     * @throws ResponseException
175
     * @throws SobotException
176
     * @throws \GuzzleHttp\Exception\GuzzleException
177
     * @throws ConfigException
178
     * @throws NotFoundException
179
     * @author herry.yao <[email protected]>
180
     * @version 1.2.2
181
     * @date 2020-08-05
182
     */
183
    public function request(): Response
184
    {
185
        $content = $this->httpRequest();
186
        $res = json_decode($content, true);
187
        $retCode = array_get($res, 'ret_code', Code::SYSTEM_ERR);
188
189
        if ($retCode != Code::SUCCESS_CODE) {
190
            // 如果是TOKEN失效重新获取
191
            if ($this->tokenIsInvalid($retCode)) {
192
                $this->updatingToken = true;
193
                return $this->request();
194
            }
195
            throw new ResponseException(array_get($res, 'ret_msg', 'Sobot Response err'), $retCode, $content);
196
        }
197
        $class = get_class($this) . '\\Response';
198
        if (class_exists($class)) {
199
            return new $class($res);
200
        }
201
        throw new NotFoundException(sprintf('Class[%s] File Not Found.', $class));
202
    }
203
204
    /**
205
     * 获取请求参数传递方式
206
     *
207
     * @return string
208
     * @author herry.yao <[email protected]>
209
     * @version 1.2.2
210
     * @date 2020-08-05
211
     */
212
    protected function getContentType(): string
213
    {
214
        if (strtolower($this->getRequestMethod()) == self::METHOD_GET) {
215
            return 'query';
216
        }
217
        return $this->contentType ?: 'json';
218
    }
219
220
    /**
221
     * 获取头部数据
222
     *
223
     * @return array
224
     * @throws ConfigException
225
     * @throws ResponseException
226
     * @throws SobotException
227
     * @throws \GuzzleHttp\Exception\GuzzleException
228
     * @version 1.2.2
229
     * @date 2020-08-05
230
     * @author herry.yao <[email protected]>
231
     */
232
    protected function getHeader(): array
233
    {
234
        if (!($this instanceof Token)) {
235
            $this->addHeader('token', (new Token($this->config, $this->cache))->getToken($this->updatingToken));
236
        }
237
        return $this->headers;
238
    }
239
240
    /**
241
     * 添加头部信息
242
     *
243
     * @param string|array $key
244
     * @param null|string $value
245
     * @return $this
246
     * @author herry.yao <[email protected]>
247
     * @version 1.2.2
248
     * @date 2020-08-05
249
     */
250
    public function addHeader($key, $value = null)
251
    {
252
        $headers = is_array($key) ? $key : [$key => $value];
253
        $this->headers = array_merge($this->headers, $headers);
254
        return $this;
255
    }
256
257
    /**
258
     * 获取超时时间
259
     *
260
     * @return int
261
     * @author herry.yao <[email protected]>
262
     * @version 1.2.2
263
     * @date 2020-08-05
264
     */
265
    protected function getTimeout(): int
266
    {
267
        return $this->timeout;
268
    }
269
270
    /**
271
     * 设置超时时间
272
     *
273
     * @param int $timeout
274
     * @return $this
275
     * @author herry.yao <[email protected]>
276
     * @version 1.2.2
277
     * @date 2020-08-05
278
     */
279
    public function setTimeout(int $timeout)
280
    {
281
        $this->timeout = $timeout;
282
        return $this;
283
    }
284
285
    /**
286
     * 接口请求方式
287
     *
288
     * @return string
289
     * @author herry.yao <[email protected]>
290
     * @version 1.2.2
291
     * @date 2020-08-05
292
     */
293
    abstract public function getRequestMethod(): string;
294
295
    /**
296
     * 接口请求参数
297
     *
298
     * @return Request
299
     * @author herry.yao <[email protected]>
300
     * @version 1.2.2
301
     * @date 2020-08-05
302
     */
303
    public function getRequestParam(): Request
304
    {
305
        return $this->request;
306
    }
307
308
    /**
309
     * 接口请求地址
310
     *
311
     * @return string
312
     * @author herry.yao <[email protected]>
313
     * @version 1.2.2
314
     * @date 2020-08-05
315
     */
316
    abstract public function getRequestPath(): string;
317
318
    /**
319
     * 魔术方法 获取值
320
     *
321
     * @param $name
322
     * @return Request|null
323
     * @author herry.yao <[email protected]>
324
     * @version 1.2.2
325
     * @date 2020-08-05
326
     */
327
    public function __get($name)
328
    {
329
        $class = get_class($this) . '\\' . underline_to_hump($name);
330
        if (class_exists($class)) {
331
            $this->{$name} = new $class($this->config, $this->cache);
332
            return $this->{$name};
333
        }
334
        return null;
335
    }
336
337
    /**
338
     * 魔术方法赋值
339
     *
340
     * @param $name
341
     * @param $value
342
     */
343
    public function __set($name, $value)
344
    {
345
        if (!is_object($value)) {
346
            $name = underline_to_hump($name);
347
            $this->request->{$name}($name);
348
        } else {
349
            $this->{$name} = $value;
350
        }
351
    }
352
353
    /**
354
     * 方法实例
355
     *
356
     * @param $name
357
     * @param $arguments
358
     * @return Sobot
359
     * @version 1.2.2
360
     * @date 2020-08-05
361
     * @author herry.yao <[email protected]>
362
     */
363
    public function __call($name, $arguments)
364
    {
365
        $this->request->{$name}(...$arguments);
366
        return $this;
367
    }
368
}