GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Push — master ( 262abc...17da4d )
by Feyman
03:12
created

ApiClient   C

Complexity

Total Complexity 55

Size/Duplication

Total Lines 547
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 13

Test Coverage

Coverage 76.55%

Importance

Changes 0
Metric Value
wmc 55
lcom 1
cbo 13
dl 0
loc 547
ccs 111
cts 145
cp 0.7655
rs 6.8
c 0
b 0
f 0

33 Methods

Rating   Name   Duplication   Size   Complexity  
B __construct() 0 8 6
A setBaseUri() 0 6 1
A getBaseUri() 0 4 1
A setCustomer() 0 7 1
A getApiKey() 0 4 1
A setApiKey() 0 4 1
A getApiSecret() 0 4 1
A setApiSecret() 0 4 1
A getApiVersion() 0 4 1
A setApiVersion() 0 6 1
A setOutTime() 0 6 1
A getOutTime() 0 4 1
A getResponseCode() 0 4 1
A getRequestData() 0 4 1
A getResponseData() 0 12 2
A getResponse() 0 4 1
A getRequest() 0 4 1
A get() 0 4 1
A post() 0 4 1
A put() 0 4 1
A delete() 0 4 1
A patch() 0 4 1
A getLastUrl() 0 4 1
A getTransferTime() 0 4 1
A createGuzzleLoggingMiddleware() 0 4 1
A standardizeParam() 0 10 2
A validateApiOptions() 0 9 3
A compileRoute() 0 6 2
A extractOptionalParameters() 0 6 1
A getHttpClient() 0 14 3
C request() 0 50 8
A setLogger() 0 12 3
A getAuthParams() 0 12 2

How to fix   Complexity   

Complex Class

Complex classes like ApiClient often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use ApiClient, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace Lingxi\ApiClient;
4
5
use GuzzleHttp\Client;
6
use GuzzleHttp\ClientInterface;
7
use GuzzleHttp\Exception\BadResponseException;
8
use GuzzleHttp\Exception\RequestException;
9
use GuzzleHttp\HandlerStack;
10
use GuzzleHttp\MessageFormatter;
11
use GuzzleHttp\Middleware;
12
use GuzzleHttp\RequestOptions;
13
use GuzzleHttp\TransferStats;
14
use Lingxi\ApiClient\Exceptions\ApiClientInitException;
15
use Lingxi\ApiClient\Exceptions\ResponseDataParseException;
16
use Lingxi\Signature\Authenticator;
17
use Psr\Http\Message\ResponseInterface;
18
use Psr\Log\LoggerInterface;
19
20
/**
21
 * Class ApiClient
22
 * @package Lingxi\Packages\ApiClient
23
 */
24
class ApiClient
25
{
26
    /**
27
     * @var
28
     */
29
    protected $httpClient;
30
    /**
31
     * @var mixed|string
32
     */
33
    protected $baseUri;
34
    /**
35
     * @var float|mixed
36
     */
37
    protected $outTime;
38
    /**
39
     * @var mixed|string
40
     */
41
    protected $apiKey;
42
43
    /**
44
     * @var mixed|string
45
     */
46
    protected $apiSecret;
47
48
    /**
49
     * @var mixed|string
50
     */
51
    protected $apiVersion;
52
    /**
53
     * @var \Psr\Http\Message\RequestInterface
54
     */
55
    protected $request;
56
    /**
57
     * @var \Psr\Http\Message\ResponseInterface
58
     */
59
    protected $response;
60
    /**
61
     * @var array
62
     */
63
    protected $requestData;
64
    /**
65
     * @var int
66
     */
67
    protected $responseCode;
68
    /**
69
     * @var array
70
     */
71
    protected $responseBody;
72
    /**
73
     * @var
74
     */
75
    protected $authenticator;
76
    /**
77
     * @var string
78
     */
79
    protected $lastUrl = '';
80
    /**
81
     * @var double
82
     */
83
    protected $transferTime = 0;
84
    /**
85
     * @var callable
86
     */
87
    protected $completeCallBack;
88
    /**
89
     * @var bool
90
     */
91
    protected $log = false;
92
    /**
93
     * @var $handlerStack
94
     */
95
    protected $handlerStack;
96
97
    /**
98
     * ApiClient constructor.
99
     *
100
     * @param array $options
101
     */
102 18
    public function __construct(array $options = [])
103
    {
104 18
        $this->baseUri    = key_exists('base_uri', $options) ? $options['base_uri'] : '';
105 18
        $this->outTime    = key_exists('time_out', $options) ? $options['time_out'] : 5.0;
106 18
        $this->apiKey     = key_exists('api_key', $options) ? $options['api_key'] : '';
107 18
        $this->apiSecret  = key_exists('api_secret', $options) ? $options['api_secret'] : '';
108 18
        $this->apiVersion = key_exists('api_version', $options) ? $options['api_version'] : 'v1';
109 18
    }
110
111
    /**
112
     * 设置 base uri
113
     *
114
     * @param $baseUri
115
     *
116
     * @return $this
117
     */
118 1
    public function setBaseUri($baseUri)
119
    {
120 1
        $this->baseUri = $baseUri;
121
122 1
        return $this;
123
    }
124
125
    /**
126
     * 获取 base uri
127
     *
128
     * @return string
129
     */
130 1
    public function getBaseUri()
131
    {
132 1
        return $this->baseUri;
133
    }
134
135
    /**
136
     * 设置 api key 和 api secret
137
     *
138
     * @param $apiKey
139
     * @param $apiSecret
140
     *
141
     * @return $this
142
     */
143 1
    public function setCustomer($apiKey, $apiSecret)
144
    {
145 1
        $this->apiKey    = $apiKey;
146 1
        $this->apiSecret = $apiSecret;
147
148 1
        return $this;
149
    }
150
151
    /**
152
     * 获取 api key
153
     *
154
     * @return string
155
     */
156 1
    public function getApiKey()
157
    {
158 1
        return $this->apiKey;
159
    }
160
161
    /**
162
     * 设置 api key
163
     *
164
     * @param mixed|string $apiKey
165
     */
166 1
    public function setApiKey($apiKey)
167
    {
168 1
        $this->apiKey = $apiKey;
169 1
    }
170
171
    /**
172
     * 获取 api secret
173
     *
174
     * @return string
175
     */
176 1
    public function getApiSecret()
177
    {
178 1
        return $this->apiSecret;
179
    }
180
181
    /**
182
     * 设置 api secret
183
     *
184
     * @param mixed|string $apiSecret
185
     */
186 1
    public function setApiSecret($apiSecret)
187
    {
188 1
        $this->apiSecret = $apiSecret;
189 1
    }
190
191
    /**
192
     * 获取 api version
193
     *
194
     * @return mixed|string
195
     */
196 1
    public function getApiVersion()
197
    {
198 1
        return $this->apiVersion;
199
    }
200
201
    /**
202
     * 设置 api version
203
     *
204
     * @param $apiVersion
205
     *
206
     * @return $this
207
     */
208 1
    public function setApiVersion($apiVersion)
209
    {
210 1
        $this->apiVersion = $apiVersion;
211
212 1
        return $this;
213
    }
214
215
    /**
216
     * 设置超时时间
217
     *
218
     * @param $time
219
     *
220
     * @return $this
221
     */
222 1
    public function setOutTime($time)
223
    {
224 1
        $this->outTime = $time;
225
226 1
        return $this;
227
    }
228
229
    /**
230
     * 获取当前设置的超时时间
231
     *
232
     * @return float|mixed
233
     */
234 1
    public function getOutTime()
235
    {
236 1
        return $this->outTime;
237
    }
238
239
    /**
240
     * get a response code
241
     *
242
     * @return int
243
     */
244 1
    public function getResponseCode()
245
    {
246 1
        return $this->getResponse()->getStatusCode();
247
    }
248
249
    /**
250
     * 获取请求的数据
251
     * @return array
252
     */
253 1
    public function getRequestData()
254
    {
255 1
        return $this->requestData;
256
    }
257
258
    /**
259
     * @return array
260
     * @throws ResponseDataParseException
261
     */
262 2
    public function getResponseData()
263
    {
264 2
        $responseBody = (string)$this->getResponse()->getBody();
265
266 2
        $this->responseBody = json_decode($responseBody, true);
0 ignored issues
show
Documentation Bug introduced by
It seems like json_decode($responseBody, true) of type * is incompatible with the declared type array of property $responseBody.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
267
268 2
        if (JSON_ERROR_NONE !== json_last_error()) {
269
            throw new ResponseDataParseException('Failed to parse JSON: ' . json_last_error_msg());
270
        }
271
272 2
        return $this->responseBody;
273
    }
274
275
    /**
276
     * @return \Psr\Http\Message\ResponseInterface \GuzzleHttp\Psr7\RequestInterface
277
     */
278 4
    public function getResponse()
279
    {
280 4
        return $this->response;
281
    }
282
283
    /**
284
     * @return \Psr\Http\Message\RequestInterface \GuzzleHttp\Psr7\Request
285
     */
286 1
    public function getRequest()
287
    {
288 1
        return $this->request;
289
    }
290
291
    /**
292
     * @return Client|ClientInterface
293
     * @throws ApiClientInitException
294
     */
295 10
    public function getHttpClient()
296
    {
297 10
        if (!$this->baseUri) {
298 1
            throw new ApiClientInitException('没有配置有效的 BaseUri');
299
        }
300 9
        if (!($this->httpClient instanceof ClientInterface)) {
301 9
            $this->httpClient = new Client([
302 9
                'base_uri' => rtrim($this->baseUri, '/') . '/',
303 9
                'time_out' => $this->outTime,
304
            ]);
305
        }
306
307 9
        return $this->httpClient;
308
    }
309
310
    /**
311
     * Call a Get Request
312
     *
313
     * @param string $uri
314
     * @param array  $query
315
     *
316
     * @return mixed|null
317
     */
318 9
    public function get($uri, $query = [])
319
    {
320 9
        return $this->request('GET', $uri, $query);
321
    }
322
323
    /**
324
     * Call a Post Request
325
     *
326
     * @param string $uri
327
     * @param array  $data
328
     *
329
     * @return mixed|null
330
     */
331
    public function post($uri, $data = [])
332
    {
333
        return $this->request('POST', $uri, $data);
334
    }
335
336
    /**
337
     * Call a Put Request
338
     *
339
     * @param string $uri
340
     * @param array  $data
341
     *
342
     * @return mixed|null
343
     */
344
    public function put($uri, $data = [])
345
    {
346
        return $this->request('PUT', $uri, $data);
347
    }
348
349
    /**
350
     * Call a delete Request
351
     *
352
     * @param string $uri
353
     * @param array  $query
354
     *
355
     * @return ApiClient
356
     */
357
    public function delete($uri, $query = [])
358
    {
359
        return $this->request('DELETE', $uri, $query);
360
    }
361
362
    /**
363
     * Call a patch Request
364
     *
365
     * @param string $uri
366
     * @param array  $data
367
     *
368
     * @return ApiClient
369
     */
370
    public function patch($uri, $data = [])
371
    {
372
        return $this->request('PATCH', $uri, $data);
373
    }
374
375
    /**
376
     * Call a Request
377
     *
378
     * @param string $method
379
     * @param string $uri
380
     * @param array  $optionals
381
     *
382
     * @return $this
383
     * @throws \Exception
384
     */
385 9
    public function request($method, $uri, $optionals = [])
386
    {
387 9
        $options = $this->extractOptionalParameters($uri, $optionals);
388 9
        $uri     = $this->compileRoute($uri, $optionals);
389 9
        $data    = [];
390 9
        $method  = strtoupper($method);
391
392 9
        $paramType = $method === 'POST' ? RequestOptions::FORM_PARAMS : RequestOptions::QUERY;
393 9
        if (key_exists(RequestOptions::JSON, $options)) {
394
            $json = $options[RequestOptions::JSON];
395
            unset($options[RequestOptions::JSON]);
396
            $data[RequestOptions::JSON] = $json;
397
            $paramType                  = RequestOptions::QUERY;
398
        }
399 9
        $data[$paramType]               = $this->getAuthParams($options);
400 9
        $this->requestData              = $data;
401 9
        $data[RequestOptions::ON_STATS] = function (TransferStats $stats) {
402 9
            $this->lastUrl      = (string) $stats->getEffectiveUri();
403 9
            $this->request      = $stats->getRequest();
404 9
            $this->transferTime = $stats->getTransferTime();
405 9
        };
406 9
        if ($this->log) {
407
            $data['handler'] = $this->handlerStack;
408
        }
409 9
        if ($this->apiVersion) {
410 9
            $uri = $this->apiVersion . $uri;
411
        }
412 9
        $promise = $this->getHttpClient()->requestAsync($method, $uri, $data);
413 9
        $promise->then(
414 9
            function (ResponseInterface $response) {
415 9
                $this->response = $response;
416 9
                call_user_func($this->completeCallBack);
417 9
            },
418 9
            function ($e) {
419
                if ($e instanceof BadResponseException) {
420
                    $this->request  = $e->getRequest();
421
                    $this->response = $e->getResponse();
422
                } elseif ($e instanceof RequestException) {
423
                    $this->request = $e->getRequest();
424
                    if ($e->hasResponse()) {
425
                        $this->response = $e->getResponse();
426
                    }
427
                }
428
                throw $e;
429 9
            }
430
        );
431 9
        $promise->wait();
432
433 9
        return $this;
434
    }
435
436
    /**
437
     * 获取最后一次请求的 URL
438
     *
439
     * @return string
440
     */
441 1
    public function getLastUrl()
442
    {
443 1
        return (string)$this->lastUrl;
444
    }
445
446
    /**
447
     * 获取请求时间
448
     *
449
     * @return double
450
     */
451 1
    public function getTransferTime()
452
    {
453 1
        return $this->transferTime;
454
    }
455
456
    /**
457
     * 设置日志
458
     *
459
     * @param LoggerInterface $logger
460
     * @param mixed           $format
461
     */
462
    public function setLogger(LoggerInterface $logger, $format = null)
463
    {
464
        $this->log          = true;
465
        $this->handlerStack = HandlerStack::create();
466
        if (is_array($format)) {
467
            foreach ($format as $item) {
468
                $this->handlerStack->unshift($this->createGuzzleLoggingMiddleware($logger, $item));
469
            }
470
        } else {
471
            $this->handlerStack->push($this->createGuzzleLoggingMiddleware($logger, $format));
472
        }
473
    }
474
475
    /**
476
     * 创建一个日志中间件
477
     *
478
     * @param $logger
479
     * @param $Format
480
     *
481
     * @return callable
482
     */
483
    private function createGuzzleLoggingMiddleware($logger, $Format)
484
    {
485
        return Middleware::log($logger, new MessageFormatter($Format));
486
    }
487
488
    /**
489
     * 将所有请求参数转为字符串
490
     *
491
     * @param array $param
492
     *
493
     * @return array
494
     */
495
    public function standardizeParam($param)
496
    {
497 10
        return array_map(function ($item) {
498 1
            if (is_array($item)) {
499 1
                return $this->standardizeParam($item);
500
            } else {
501 1
                return (string)$item;
502
            }
503 10
        }, $param);
504
    }
505
506
    /**
507
     * 获取 auth param
508
     *
509
     * @param array $options
510
     *
511
     * @return mixed
512
     */
513 9
    private function getAuthParams($options)
514
    {
515 9
        $this->validateApiOptions();
516
517 9
        if (!$this->authenticator instanceof Authenticator) {
518 9
            $this->authenticator = new Authenticator($this->apiKey, $this->apiSecret);
519
        }
520
521 9
        $options = $this->standardizeParam($options);
522
523 9
        return $this->authenticator->getAuthParams($options);
524
    }
525
526
    /**
527
     * 验证 api 必须的是否已经被初始化
528
     *
529
     * @throws ApiClientInitException
530
     */
531 9
    private function validateApiOptions()
532
    {
533 9
        if (!$this->apiKey) {
534
            throw new ApiClientInitException('没有配置有效的 apiKey');
535
        }
536 9
        if (!$this->apiSecret) {
537
            throw new ApiClientInitException('没有配置有效的 apiSecret');
538
        }
539 9
    }
540
541
    /**
542
     * 替换 url 中的变量
543
     *
544
     * @param string $uri
545
     * @param array  $optionals
546
     *
547
     * @return string
548
     */
549
    protected function compileRoute($uri, $optionals)
550
    {
551 9
        return preg_replace_callback('/\{(\w+?)\??\}/', function ($matches) use ($optionals) {
552 1
            return isset($optionals[$matches[1]]) ? $optionals[$matches[1]] : '';
553 9
        }, $uri);
554
    }
555
556
    /**
557
     * 去掉 uri 中已存在的变量
558
     *
559
     * @param string $uri
560
     * @param array  $optionals
561
     *
562
     * @return array
563
     */
564 9
    protected function extractOptionalParameters($uri, $optionals)
565
    {
566 9
        preg_match_all('/\{(\w+?)\??\}/', $uri, $matches);
567
568 9
        return array_except($optionals, $matches[1]);
569
    }
570
}