Completed
Push — master ( 0512a1...7c8694 )
by Tomáš
03:46
created

Requester::validateStatus()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 4

Importance

Changes 0
Metric Value
dl 0
loc 12
c 0
b 0
f 0
rs 9.8666
ccs 6
cts 6
cp 1
cc 4
nc 3
nop 2
crap 4
1
<?php
2
3
namespace Inspirum\Balikobot\Services;
4
5
use GuzzleHttp\Psr7\Response;
6
use Inspirum\Balikobot\Contracts\RequesterInterface;
7
use Inspirum\Balikobot\Definitions\API;
8
use Inspirum\Balikobot\Exceptions\BadRequestException;
9
use Inspirum\Balikobot\Exceptions\UnauthorizedException;
10
use Psr\Http\Message\ResponseInterface;
11
use RuntimeException;
12
13
class Requester implements RequesterInterface
14
{
15
    /**
16
     * API User
17
     *
18
     * @var string
19
     */
20
    private $apiUser;
21
22
    /**
23
     * API key
24
     *
25
     * @var string
26
     */
27
    private $apiKey;
28
29
    /**
30
     * Balikobot API client
31
     *
32
     * @param string $apiUser
33
     * @param string $apiKey
34
     */
35 258
    public function __construct(string $apiUser, string $apiKey)
36
    {
37 258
        $this->apiUser = $apiUser;
38 258
        $this->apiKey  = $apiKey;
39 258
    }
40
41
    /**
42
     * Call API
43
     *
44
     * @param string             $version
45
     * @param string             $request
46
     * @param string             $shipper
47
     * @param array<mixed,mixed> $data
48
     * @param bool               $shouldHaveStatus
49
     *
50
     * @return array<mixed,mixed>
51
     *
52
     * @throws \Inspirum\Balikobot\Contracts\ExceptionInterface
53
     */
54 247
    public function call(
55
        string $version,
56
        string $shipper,
57
        string $request,
58
        array $data = [],
59
        bool $shouldHaveStatus = true
60
    ): array {
61
        // resolve url
62 247
        $path = trim($shipper . '/' . $request, '/');
63 247
        $path = str_replace('//', '/', $path);
64 247
        $host = $this->resolveHostName($version);
65
66
        // call API server and get response
67 247
        $response = $this->request($host . $path, $data);
68
69
        // get status code and content
70 247
        $statusCode = $response->getStatusCode();
71 247
        $content    = $response->getBody()->getContents();
72
73
        // parse response content to assoc array
74 247
        $content = json_decode($content, true);
75
76
        // return empty array when json_decode fails
77 247
        if ($content === null) {
78 1
            $content = [];
79
        }
80
81
        // validate response status code
82 247
        $this->validateResponse($statusCode, $content, $shouldHaveStatus);
83
84
        // return response
85 166
        return $content;
86
    }
87
88
    /**
89
     * Get API response
90
     *
91
     * @param string             $url
92
     * @param array<mixed,mixed> $data
93
     *
94
     * @return \Psr\Http\Message\ResponseInterface
95
     */
96 6
    public function request(string $url, array $data = []): ResponseInterface
97
    {
98
        // init curl
99 6
        $ch = curl_init();
100
101
        // set headers
102 6
        curl_setopt($ch, CURLOPT_URL, $url);
103 6
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
104 6
        curl_setopt($ch, CURLOPT_HEADER, false);
105 6
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
106 6
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
107
108
        // set data
109 6
        if (count($data) > 0) {
110 1
            curl_setopt($ch, CURLOPT_POST, true);
111 1
            curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
112
        }
113
114
        // set auth
115 6
        curl_setopt($ch, CURLOPT_HTTPHEADER, [
116 6
            'Authorization: Basic ' . base64_encode($this->apiUser . ':' . $this->apiKey),
117 6
            'Content-Type: application/json',
118
        ]);
119
120
        // execute curl
121 6
        $response   = curl_exec($ch);
122 6
        $statusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
123
124
        // check for errors.
125 6
        if ($response === false) {
126 1
            throw new RuntimeException(curl_error($ch), curl_errno($ch));
127
        }
128
129
        // close curl
130 5
        curl_close($ch);
131
132 5
        return new Response((int) $statusCode, [], (string) $response);
133
    }
134
135
    /**
136
     * Get API url for given version
137
     *
138
     * @param string $version
139
     *
140
     * @return string
141
     */
142 247
    private function resolveHostName(string $version): string
143
    {
144 247
        return API::URL[$version] ?? API::URL[API::V1];
145
    }
146
147
    /**
148
     * Validate response
149
     *
150
     * @param int                $statusCode
151
     * @param array<mixed,mixed> $response
152
     * @param bool               $shouldHaveStatus
153
     *
154
     * @throws \Inspirum\Balikobot\Contracts\ExceptionInterface
155
     */
156 247
    private function validateResponse(int $statusCode, array $response, bool $shouldHaveStatus): void
157
    {
158 247
        $this->validateStatus($statusCode, $response);
159
160 215
        $this->validateResponseStatus($response, $shouldHaveStatus);
161 166
    }
162
163
    /**
164
     * Validate status code
165
     *
166
     * @param int                $statusCode
167
     * @param array<mixed,mixed> $response
168
     *
169
     * @throws \Inspirum\Balikobot\Contracts\ExceptionInterface
170
     */
171 247
    private function validateStatus(int $statusCode, array $response = []): void
172
    {
173
        // unauthorized
174 247
        if ($statusCode === 401 || $statusCode === 403) {
175 2
            throw new UnauthorizedException(null, $statusCode);
176
        }
177
178
        // request error
179 245
        if ($statusCode !== 200) {
180 30
            throw new BadRequestException($response, $statusCode);
181
        }
182 215
    }
183
184
    /**
185
     * Validate response status
186
     *
187
     * @param array<mixed,mixed> $response
188
     * @param bool               $shouldHaveStatus
189
     *
190
     * @return void
191
     *
192
     * @throws \Inspirum\Balikobot\Contracts\ExceptionInterface
193
     */
194 215
    private function validateResponseStatus(array $response, bool $shouldHaveStatus): void
195
    {
196
        // no status to validate
197 215
        if (isset($response['status']) === false && $shouldHaveStatus === false) {
198 20
            return;
199
        }
200
201 195
        $statusCode = (int) ($response['status'] ?? 500);
202
203 195
        if ($statusCode !== 200) {
204 51
            throw new BadRequestException($response, $statusCode);
205
        }
206 146
    }
207
}
208