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 (#9)
by
unknown
04:15
created

Client   A

Complexity

Total Complexity 21

Size/Duplication

Total Lines 292
Duplicated Lines 0 %

Test Coverage

Coverage 93.42%

Importance

Changes 0
Metric Value
eloc 69
dl 0
loc 292
ccs 71
cts 76
cp 0.9342
rs 10
c 0
b 0
f 0
wmc 21

12 Methods

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