BaseClient   A
last analyzed

Complexity

Total Complexity 25

Size/Duplication

Total Lines 182
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 58
dl 0
loc 182
rs 10
c 0
b 0
f 0
wmc 25

14 Methods

Rating   Name   Duplication   Size   Complexity  
A httpUpload() 0 21 3
A httpGet() 0 3 1
A httpPost() 0 3 1
A setAccessToken() 0 5 1
A httpPostJson() 0 3 1
A logMiddleware() 0 5 1
A getAccessToken() 0 3 1
A registerHttpMiddlewares() 0 8 1
A requestRaw() 0 3 1
A retryMiddleware() 0 23 6
A accessTokenMiddleware() 0 9 2
A __construct() 0 4 1
A request() 0 9 3
A getHttpClient() 0 7 2
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\Http\Response;
14
use GuzzleHttp\Client;
15
use GuzzleHttp\MessageFormatter;
16
use GuzzleHttp\Middleware;
17
use Psr\Http\Message\RequestInterface;
18
use Psr\Http\Message\ResponseInterface;
19
20
class BaseClient
21
{
22
    use HasHttpRequests {
23
        request as performRequest;
24
    }
25
26
    /**
27
     * @var ServiceContainer
28
     */
29
    protected $app;
30
31
    /**
32
     * @var AccessTokenInterface|mixed
33
     */
34
    protected $accessToken;
35
36
    /**
37
     * @var
38
     */
39
    protected $baseUri;
40
41
    public function __construct(ServiceContainer $app, AccessTokenInterface $accessToken = null)
42
    {
43
        $this->app = $app;
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 9 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...
44
        $this->accessToken = $accessToken ?? $this->app['access_token'];
45
    }
46
47
    /**
48
     * @param string $url
49
     * @param array $query
50
     * @return Response|Support\Collection|array|mixed|ResponseInterface
51
     * @throws \GuzzleHttp\Exception\GuzzleException
52
     */
53
    public function httpGet(string $url, array $query = [])
54
    {
55
        return $this->request($url, 'GET', ['query' => $query]);
56
    }
57
58
    /**
59
     * @param string $url
60
     * @param array $data
61
     * @return Response|Support\Collection|array|mixed|ResponseInterface
62
     * @throws \GuzzleHttp\Exception\GuzzleException
63
     */
64
    public function httpPost(string $url, array $data = [])
65
    {
66
        return $this->request($url, 'POST', ['form_params' => $data]);
67
    }
68
69
    /**
70
     * @param string $url
71
     * @param array $data
72
     * @param array $query
73
     * @return Response|Support\Collection|array|mixed|ResponseInterface
74
     * @throws \GuzzleHttp\Exception\GuzzleException
75
     */
76
    public function httpPostJson(string $url, array $data = [], array $query = [])
77
    {
78
        return $this->request($url, 'POST', ['query' => $query, 'json' => $data]);
79
    }
80
81
    /**
82
     * @param string $url
83
     * @param array $files
84
     * @param array $form
85
     * @param array $query
86
     * @return Response|Support\Collection|array|mixed|ResponseInterface
87
     * @throws \GuzzleHttp\Exception\GuzzleException
88
     */
89
    public function httpUpload(string $url, array $files = [], array $form = [], array $query = [])
90
    {
91
        $multipart = [];
92
93
        foreach ($files as $name => $path) {
94
            $multipart[] = [
95
                'name' => $name,
96
                'contents' => fopen($path, 'r'),
97
            ];
98
        }
99
100
        foreach ($form as $name => $contents) {
101
            $multipart[] = compact('name', 'contents');
102
        }
103
104
        return $this->request($url, 'POST', [
105
            'query' => $query,
106
            'multipart' => $multipart,
107
            'connect_timeout' => 30,
108
            'timeout' => 30,
109
            'read_timeout' => 30
110
        ]);
111
    }
112
113
    public function getAccessToken(): AccessTokenInterface
114
    {
115
        return $this->accessToken;
116
    }
117
118
    public function setAccessToken(AccessTokenInterface $accessToken)
119
    {
120
        $this->accessToken = $accessToken;
121
122
        return $this;
123
    }
124
125
    public function request(string $url, string $method = 'GET', array $options = [], $returnRaw = false)
126
    {
127
        if (empty($this->middlewares)) {
128
            $this->registerHttpMiddlewares();
129
        }
130
131
        $response = $this->performRequest($url, $method, $options);
132
133
        return $returnRaw ? $response : $this->castResponseToType($response, $this->app->config->get('response_type'));
134
    }
135
    public function requestRaw(string $url, string $method = 'GET', array $options = [])
136
    {
137
        return Response::buildFromPsrResponse($this->request($url, $method, $options, true));
138
    }
139
140
    public function getHttpClient(): Client
141
    {
142
        if (!($this->httpClient instanceof Client)) {
143
            $this->httpClient = $this->app['http_client'] ?? new Client();
144
        }
145
146
        return $this->httpClient;
147
    }
148
149
    protected function registerHttpMiddlewares()
150
    {
151
        // retry
152
        $this->pushMiddleware($this->retryMiddleware(), 'retry');
153
        // access token
154
        $this->pushMiddleware($this->accessTokenMiddleware(), 'access_token');
155
        // log
156
        $this->pushMiddleware($this->logMiddleware(), 'log');
157
    }
158
159
    protected function accessTokenMiddleware()
160
    {
161
        return function(callable $handler) {
162
            return function(RequestInterface $request, array $options) use ($handler) {
163
                if ($this->accessToken) {
164
                    $request = $this->accessToken->applyToRequest($request, $options);
165
                }
166
167
                return $handler($request, $options);
168
            };
169
        };
170
    }
171
172
    protected function logMiddleware()
173
    {
174
        $formatter = new MessageFormatter($this->app['config']['http.log_template'] ?? MessageFormatter::DEBUG);
175
176
        return Middleware::log($this->app['logger'], $formatter);
177
    }
178
179
    protected function retryMiddleware()
180
    {
181
        return Middleware::retry(function(
182
            $retries,
183
            RequestInterface $request,
184
            ResponseInterface $response = null
185
        ) {
186
            // Limit the number of retries to 2
187
            if ($retries < $this->app->config->get('http.retries', 1) && $response && $body = $response->getBody()) {
188
                // Retry on server errors
189
                $response = json_decode($body, true);
190
191
                if (!empty($response['errcode']) && in_array(abs($response['errcode']), [40001, 40014, 42001], true)) {
192
                    $this->accessToken->refresh();
193
                    $this->app['logger']->debug('Retrying with refreshed access token.');
194
195
                    return true;
196
                }
197
            }
198
199
            return false;
200
        }, function() {
201
            return abs($this->app->config->get('http.retry_delay', 500));
202
        });
203
    }
204
}
205