RestClient::processResponse()   B
last analyzed

Complexity

Conditions 9
Paths 6

Size

Total Lines 25

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 25
rs 8.0555
c 0
b 0
f 0
cc 9
nc 6
nop 1
1
<?php
2
3
declare(strict_types=1);
4
5
/**
6
 * MyPoseo API Bundle
7
 *
8
 * @author Tristan Bessoussa <[email protected]>
9
 */
10
11
namespace Tristanbes\MyPoseoBundle\Connection;
12
13
use Http\Client\Common\Plugin\AuthenticationPlugin;
14
use Http\Client\Common\PluginClient;
15
use Http\Client\HttpClient;
16
use Http\Discovery\HttpClientDiscovery;
17
use Http\Discovery\MessageFactoryDiscovery;
18
use Http\Message\Authentication\QueryParam;
19
use Psr\Cache\CacheItemPoolInterface;
20
use Psr\Http\Message\ResponseInterface;
21
use Tristanbes\MyPoseoBundle\Exception\NotEnoughCreditsException;
22
use Tristanbes\MyPoseoBundle\Exception\ThrottleLimitException;
23
24
/**
25
 * This class is a wrapper for the HTTP client.
26
 */
27
class RestClient
28
{
29
    /**
30
     * Your API key.
31
     *
32
     * @var string
33
     */
34
    private $apiKey;
35
    private $httpClient;
36
    private $apiHost;
37
    private $cache;
38
39
    public function __construct(string $apiKey, string $apiHost, ?HttpClient $httpClient = null, ?CacheItemPoolInterface $cache = null)
40
    {
41
        $this->apiKey     = $apiKey;
42
        $this->apiHost    = $apiHost;
43
        $this->httpClient = $httpClient;
44
        $this->cache      = $cache;
45
    }
46
47
    protected function getHttpClient(): HttpClient
48
    {
49
        if (null === $this->httpClient) {
50
            $this->httpClient = HttpClientDiscovery::find();
51
        }
52
53
        $authentication = new QueryParam(['key' => $this->apiKey]);
54
55
        $authenticationPlugin = new AuthenticationPlugin($authentication);
56
57
        $client = new PluginClient($this->httpClient, [$authenticationPlugin]);
58
59
        return $client;
60
    }
61
62
    /**
63
     * Sends the API request if cache not hit
64
     *
65
     * @param array<string,string> $headers
66
     * @param mixed                $body
67
     *
68
     * @return array<mixed>
69
     */
70
    public function send(string $method, string $uri, $body = null, array $headers = [], ?string $cacheKey = null, ?int $ttl = null): array
71
    {
72
        $saveToCache = false;
73
74
        if (null !== $cacheKey && null !== $ttl && null !== $this->cache) {
75
            if ($this->cache->hasItem($cacheKey)) {
76
                return $this->cache->getItem($cacheKey)->get();
77
            } else {
78
                $saveToCache = true;
79
            }
80
        }
81
82
        if (is_array($body)) {
83
            $body                    = http_build_query($body);
84
            $headers['Content-Type'] = 'application/x-www-form-urlencoded';
85
        }
86
87
        $request     = MessageFactoryDiscovery::find()->createRequest($method, $this->getApiUrl($uri), $headers, $body);
88
        $rawResponse = $this->getHttpClient()->sendRequest($request);
89
90
        $data = $this->processResponse($rawResponse);
91
92
        if (null !== $this->cache && null !== $cacheKey && true === $saveToCache) {
93
            $item = $this->cache
94
                ->getItem($cacheKey)
95
                ->set($data)
96
                ->expiresAfter($ttl)
97
            ;
98
99
            $this->cache->save($item);
100
        }
101
102
        return $data;
103
    }
104
105
    /**
106
     * Process the API response, provides error handling
107
     *
108
     * @throws \Exception
109
     *
110
     * @return array<string,mixed>
111
     */
112
    public function processResponse(ResponseInterface $response): array
113
    {
114
        $data         = (string) $response->getBody();
115
        $responseData = json_decode($data, true, 512, JSON_THROW_ON_ERROR);
116
117
        if (!is_array($responseData)) {
118
            throw new \UnexpectedValueException(sprintf('Expected "array" as Response content, got "%s", instead.', gettype($responseData)));
119
        }
120
121
        if (isset($responseData['status']) && 'success' != $responseData['status'] && array_key_exists('message', $responseData)) {
122
            throw new \Exception(sprintf('MyPoseo API: %s', $responseData['message']));
123
        }
124
125
        if (isset($responseData['myposeo']['code'])) {
126
            if ('-1' == $responseData['myposeo']['code'] && 'No enough credits' == $responseData['myposeo']['message']) {
127
                throw new NotEnoughCreditsException();
128
            }
129
130
            if ('-1' == $responseData['myposeo']['code']) {
131
                throw new ThrottleLimitException();
132
            }
133
        }
134
135
        return $responseData;
136
    }
137
138
    /**
139
     * @param array<string,mixed> $queryString
140
     *
141
     * @return array<mixed>
142
     */
143
    public function get(string $endpointUrl, array $queryString = [], ?string $cacheKey = null, ?int $ttl = null): array
144
    {
145
        return $this->send('GET', $endpointUrl.'?'.http_build_query($queryString), null, [], $cacheKey, $ttl);
146
    }
147
148
    /**
149
     * @param array<string,mixed> $postData
150
     *
151
     * @return array<mixed>
152
     */
153
    public function post(string $endpointUrl, array $postData = []): array
154
    {
155
        $postDataMultipart = [];
156
        foreach ($postData as $key => $value) {
157
            if (is_array($value)) {
158
                $index = 0;
159
                foreach ($value as $subValue) {
160
                    $postDataMultipart[] = [
161
                        'name'     => sprintf('%s[%d]', $key, $index++),
162
                        'contents' => $subValue,
163
                    ];
164
                }
165
            } else {
166
                $postDataMultipart[] = [
167
                    'name'     => $key,
168
                    'contents' => $value,
169
                ];
170
            }
171
        }
172
173
        return $this->send('POST', $endpointUrl, $postDataMultipart);
174
    }
175
176
    private function getApiUrl(string $uri): string
177
    {
178
        return $this->generateEndpoint($this->apiHost).$uri;
179
    }
180
181
    private function generateEndpoint(string $apiEndpoint): string
182
    {
183
        return sprintf('%s/', $apiEndpoint);
184
    }
185
}
186