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.
Passed
Pull Request — master (#8)
by Krzysztof
05:28
created

Client::__construct()   A

Complexity

Conditions 4
Paths 8

Size

Total Lines 23
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 4.0092

Importance

Changes 0
Metric Value
cc 4
eloc 11
nc 8
nop 3
dl 0
loc 23
ccs 11
cts 12
cp 0.9167
crap 4.0092
rs 9.9
c 0
b 0
f 0
1
<?php
2
3
namespace Coinpaprika;
4
5
use Coinpaprika\Exception\InvalidResponseException;
6
use Coinpaprika\Exception\RateLimitExceededException;
7
use Coinpaprika\Exception\ResponseErrorException;
8
use Coinpaprika\Http\Request;
9
use Coinpaprika\Model\Coin;
10
use Coinpaprika\Model\GlobalStats;
11
use Coinpaprika\Model\Ico;
12
use Coinpaprika\Model\Search;
13
use Coinpaprika\Model\Ticker;
14
use GuzzleHttp\Exception\ClientException;
15
use JMS\Serializer\SerializerBuilder;
16
use JMS\Serializer\Serializer;
17
use GuzzleHttp\Exception\GuzzleException;
18
use Psr\Http\Message\ResponseInterface;
19
20
/**
21
 * Class Client
22
 *
23
 * @package Coinpaprika
24
 *
25
 * @author Krzysztof Przybyszewski <[email protected]>
26
 */
27
class Client
28
{
29
    /**
30
     * @var string
31
     */
32
    private $apiVersion;
33
34
    /**
35
     * @var \GuzzleHttp\Client
36
     */
37
    private $httpClient;
38
39
    /**
40
     * @var Serializer
41
     */
42
    private $serializer;
43
44
    /**
45
     * @var string
46
     */
47
    private $apiBaseUrl = 'https://api.coinpaprika.com';
48
49
    /**
50
     * Client constructor.
51
     *
52
     * @param   string|null        $cacheDir
53
     * @param   \GuzzleHttp\Client $httpClient
54
     * @param    string            $apiBaseUrl
55
     */
56 13
    public function __construct(
57
        string $cacheDir = null,
58
        \GuzzleHttp\Client $httpClient = null,
59
        string $apiBaseUrl = null
60
    ) {
61 13
        $serializerBuilder = SerializerBuilder::create()
62 13
            ->addMetadataDir(__DIR__.'/Resource/config/serializer');
63
64 13
        if ($cacheDir !== null) {
65 1
            $serializerBuilder->setCacheDir($cacheDir);
66
        }
67
68 13
        $this->apiVersion = 'v1';
69 13
        $this->serializer = $serializerBuilder->build();
70
71 13
        if ($httpClient === null) {
72 1
            $httpClient = new \GuzzleHttp\Client();
73
        }
74
75 13
        $this->httpClient = $httpClient;
76
77 13
        if ($apiBaseUrl) {
78
            $this->apiBaseUrl = $apiBaseUrl;
79
        }
80 13
    }
81
82
    /**
83
     * Get global stats
84
     *
85
     * @throws  GuzzleException
86
     * @throws  ResponseErrorException
87
     * @throws  RateLimitExceededException
88
     * @throws  InvalidResponseException
89
     *
90
     * @return  GlobalStats
91
     */
92 1
    public function getGlobalStats(): GlobalStats
93
    {
94 1
        $response = $this->sendRequest(
95 1
            Request::METHOD_GET,
96 1
            $this->getEndpointUrl('global')
97
        );
98
99 1
        return $this->response($response, GlobalStats::class);
100
    }
101
102
    /**
103
     * Get tickers
104
     *
105
     * @throws  GuzzleException
106
     * @throws  ResponseErrorException
107
     * @throws  RateLimitExceededException
108
     * @throws  InvalidResponseException
109
     *
110
     * @return  array|Ticker[]
111
     */
112 1
    public function getTickers(): array
113
    {
114 1
        $response = $this->sendRequest(
115 1
            Request::METHOD_GET,
116 1
            $this->getEndpointUrl('ticker')
117
        );
118
119 1
        return $this->response($response, sprintf('array<%s>', Ticker::class));
120
    }
121
122
    /**
123
     * Get coin`s ticker data
124
     *
125
     * @param   string $id
126
     *
127
     * @throws  GuzzleException
128
     * @throws  ResponseErrorException
129
     * @throws  RateLimitExceededException
130
     * @throws  InvalidResponseException
131
     *
132
     * @return  Ticker
133
     */
134 4
    public function getTickerByCoinId(string $id): Ticker
135
    {
136 4
        $response = $this->sendRequest(
137 4
            Request::METHOD_GET,
138 4
            $this->getEndpointUrl(sprintf('ticker/%s', $id))
139
        );
140
141 4
        return $this->response($response, Ticker::class);
142
    }
143
144
    /**
145
     * Get coins list
146
     *
147
     * @throws  GuzzleException
148
     * @throws  ResponseErrorException
149
     * @throws  RateLimitExceededException
150
     * @throws  InvalidResponseException
151
     *
152
     * @return  array|Coin[]
153
     */
154 1
    public function getCoins(): array
155
    {
156 1
        $response = $this->sendRequest(
157 1
            Request::METHOD_GET,
158 1
            $this->getEndpointUrl('coins')
159
        );
160
161 1
        return $this->response($response, sprintf('array<%s>', Coin::class));
162
163
    }
164
165
    /**
166
     *
167
     * @param array $parameters API url query params array
168
     *
169
     * @throws \Coinpaprika\Exception\InvalidResponseException
170
     * @throws \Coinpaprika\Exception\RateLimitExceededException
171
     * @throws \Coinpaprika\Exception\ResponseErrorException
172
     * @throws \GuzzleHttp\Exception\GuzzleException
173
     *
174
     * @return array|Ico[]
175
     */
176 1
    public function getIcos(array $parameters = []): array
177
    {
178 1
        $response = $this->sendRequest(
179 1
            Request::METHOD_GET,
180 1
            $this->getEndpointUrl('icos'),
181 1
            $parameters
182
        );
183
184 1
        return $this->response($response, sprintf('array<%s>', Ico::class));
185
    }
186
187
    /**
188
     * @param   string     $query       Search query string
189
     * @param   array|null $categories  When null it defaults to all possible categories
190
     * @param   int        $limit       Per category limit
191
     *
192
     * @throws  InvalidResponseException
193
     * @throws  RateLimitExceededException
194
     * @throws  ResponseErrorException
195
     * @throws  GuzzleException
196
     *
197
     * @return Search
198
     */
199 4
    public function search(string $query, array $categories = null, int $limit = null): Search
200
    {
201 4
        $params = array_filter([
202 4
            'q' => $query,
203 4
            'c' => $categories ? implode(',', $categories) : null,
204 4
            'limit' => $limit
205
        ]);
206
207 4
        $response = $this->sendRequest(
208 4
            Request::METHOD_GET,
209 4
            $this->getEndpointUrl('search'),
210 4
            $params
211
        );
212
213 4
        return $this->response($response, Search::class);
214
    }
215
216
    /**
217
     * Get the API version
218
     *
219
     * @return  string
220
     */
221 13
    public function getApiVersion(): string
222
    {
223 13
        return $this->apiVersion;
224
    }
225
226
    /**
227
     * Get the endpoint URL.
228
     *
229
     * @param   string  $endpoint
230
     *
231
     * @return  string
232
     */
233 12
    protected function getEndpointUrl(string $endpoint): string
234
    {
235 12
        return str_replace('%ver%', $this->getApiVersion(), $this->apiBaseUrl.'/%ver%/').$endpoint;
236
    }
237
238
    /**
239
     * @param   string $method
240
     * @param   string $url
241
     * @param   array  $params
242
     * @param   array  $headers
243
     *
244
     * @return  ResponseInterface
245
     * @throws \GuzzleHttp\Exception\GuzzleException
246
     */
247 12
    protected function sendRequest(
248
        string $method,
249
        string $url,
250
        array $params = [],
251
        array $headers = []
252
    ): ResponseInterface {
253
254
        $defaultHeaders = [
255 12
            'User-Agent' => 'Coinpaprika API Client - PHP'
256
        ];
257
258 12
        if (Request::METHOD_GET === $method) {
259 12
            $params = http_build_query($params);
260
261 12
            $url = sprintf('%s?%s', $url, $params);
262
        }
263
264
        try {
265
266 12
            return $this->httpClient->request($method, $url, [
267 12
                'headers' => array_merge($defaultHeaders, $headers)
268
            ]);
269
270 4
        } catch (ClientException $e) {
271 4
            return $e->getResponse();
272
        }
273
    }
274
275
    /**
276
     * @param   ResponseInterface   $response
277
     *
278
     * @throws  InvalidResponseException
279
     * @throws  RateLimitExceededException
280
     * @throws  ResponseErrorException
281
     */
282 12
    protected function validateResponse(ResponseInterface $response): void
283
    {
284 12
        $statusCode = $response->getStatusCode();
285
286
        // rate limit exceeded
287 12
        if ($statusCode === 429) {
288 1
            throw new RateLimitExceededException('Response code from API 429. Rate limit exceeded.');
289
        }
290
291
        // check for errors
292 11
        if ($statusCode >= 400 && $statusCode <= 500) {
293
294 3
            if (array_key_exists('error', $e = json_decode($response->getBody(), true))) {
295
296 2
                throw new ResponseErrorException(sprintf(
297 2
                    'Response code: %s, error: %s',
298 2
                    $statusCode,
299 2
                    $e['error']
300
                ));
301
            }
302
303 1
            throw new InvalidResponseException(sprintf(
304 1
                'Bad response from a server - status code: %s, but error field does not exists.',
305 1
                $statusCode
306
            ));
307
        }
308 8
    }
309
310
    /**
311
     * Unmarshal JSON
312
     *
313
     * @param   ResponseInterface $response
314
     * @param   string            $type
315
     *
316
     * @throws  ResponseErrorException
317
     * @throws  RateLimitExceededException
318
     * @throws  InvalidResponseException
319
     *
320
     * @see     https://api.coinpaprika.com/#section/Errors
321
     *
322
     * @return  mixed
323
     */
324 12
    protected function response(ResponseInterface $response, string $type)
325
    {
326 12
        $this->validateResponse($response);
327
328 8
        return $this->serializer->deserialize($response->getBody(), $type, 'json');
329
    }
330
}
331