1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* GuzzleClient.php |
4
|
|
|
* |
5
|
|
|
* @copyright More in license.md |
6
|
|
|
* @license https://www.ipublikuj.eu |
7
|
|
|
* @author Adam Kadlec <[email protected]> |
8
|
|
|
* @package iPublikuj:JsonAPIClient! |
9
|
|
|
* @subpackage Clients |
10
|
|
|
* @since 1.0.0 |
11
|
|
|
* |
12
|
|
|
* @date 05.05.18 |
13
|
|
|
*/ |
14
|
|
|
|
15
|
|
|
declare(strict_types = 1); |
16
|
|
|
|
17
|
|
|
namespace IPub\JsonAPIClient\Clients; |
18
|
|
|
|
19
|
|
|
use Nette; |
20
|
|
|
use Nette\Http as NHttp; |
21
|
|
|
use Nette\Utils; |
22
|
|
|
|
23
|
|
|
use GuzzleHttp; |
24
|
|
|
use GuzzleHttp\Client; |
25
|
|
|
use GuzzleHttp\Exception\BadResponseException; |
26
|
|
|
use GuzzleHttp\Psr7\Request; |
27
|
|
|
|
28
|
|
|
use Neomerx\JsonApi\Contracts\Encoder\Parameters\EncodingParametersInterface; |
29
|
|
|
use Neomerx\JsonApi\Encoder\EncoderOptions; |
30
|
|
|
use Neomerx\JsonApi\Exceptions\JsonApiException; |
31
|
|
|
use Neomerx\JsonApi\Factories\Factory; |
32
|
|
|
|
33
|
|
|
use Psr\Http\Message\RequestInterface as PsrRequest; |
34
|
|
|
use Psr\Http\Message\ResponseInterface as PsrResponse; |
35
|
|
|
|
36
|
|
|
use IPub\JsonAPIClient\Encoders; |
37
|
|
|
use IPub\JsonAPIClient\Exceptions; |
38
|
|
|
use IPub\JsonAPIClient\Http; |
39
|
|
|
use IPub\JsonAPIClient\Objects; |
40
|
|
|
use IPub\JsonAPIClient\Schemas; |
41
|
|
|
|
42
|
|
|
/** |
43
|
|
|
* Guzzle client service |
44
|
|
|
* |
45
|
|
|
* @package iPublikuj:JsonAPIClient! |
46
|
|
|
* @subpackage Clients |
47
|
|
|
* |
48
|
|
|
* @author Adam Kadlec <[email protected]> |
49
|
|
|
*/ |
50
|
1 |
|
class GuzzleClient implements IClient |
51
|
|
|
{ |
52
|
|
|
/** |
53
|
|
|
* Implement nette smart magic |
54
|
|
|
*/ |
55
|
1 |
|
use Nette\SmartObject; |
56
|
|
|
|
57
|
1 |
|
use TSendsRequests; |
58
|
|
|
|
59
|
|
|
/** |
60
|
|
|
* Additional request headers |
61
|
|
|
* |
62
|
|
|
* @var string[] |
63
|
|
|
*/ |
64
|
|
|
private $headers = []; |
65
|
|
|
|
66
|
|
|
/** |
67
|
|
|
* @var Client |
68
|
|
|
*/ |
69
|
|
|
private $http; |
70
|
|
|
|
71
|
|
|
/** |
72
|
|
|
* @param string|NULL $baseUri |
73
|
|
|
* @param Schemas\SchemaProvider $schemaProvider |
74
|
|
|
* @param Client|NULL $client |
75
|
|
|
*/ |
76
|
|
|
public function __construct( |
77
|
|
|
?string $baseUri = NULL, |
78
|
|
|
Schemas\SchemaProvider $schemaProvider, |
79
|
|
|
Client $client = NULL |
80
|
|
|
) { |
81
|
1 |
|
if ($client === NULL && $baseUri === NULL) { |
82
|
|
|
throw new Exceptions\InvalidStateException('You have to define base_uri or client to be able use api client.'); |
83
|
|
|
} |
84
|
|
|
|
85
|
1 |
|
$this->http = $client !== NULL ? $client : $this->createClient($baseUri); |
86
|
|
|
|
87
|
1 |
|
$factory = new Factory; |
88
|
1 |
|
$this->schemas = $factory->createContainer($schemaProvider->getMapping()); |
89
|
1 |
|
$this->serializer = new Encoders\Encoder($factory, $this->schemas, new EncoderOptions( |
90
|
1 |
|
JSON_PRETTY_PRINT |
91
|
|
|
)); |
92
|
1 |
|
} |
93
|
|
|
|
94
|
|
|
/** |
95
|
|
|
* {@inheritdoc} |
96
|
|
|
*/ |
97
|
|
|
public function index(string $endpoint, EncodingParametersInterface $parameters = NULL, array $options = []) : Http\IResponse |
98
|
|
|
{ |
99
|
|
|
$options = $this->mergeOptions([ |
100
|
|
|
GuzzleHttp\RequestOptions::HEADERS => $this->jsonApiHeaders(FALSE), |
101
|
|
|
GuzzleHttp\RequestOptions::QUERY => $parameters ? $this->parseSearchQuery($parameters) : NULL, |
102
|
|
|
], $options); |
103
|
|
|
|
104
|
|
|
return $this->request(NHttp\IRequest::GET, $endpoint, $options); |
105
|
|
|
} |
106
|
|
|
|
107
|
|
|
/** |
108
|
|
|
* {@inheritdoc} |
109
|
|
|
*/ |
110
|
|
|
public function read(string $endpoint, EncodingParametersInterface $parameters = NULL, array $options = []) : Http\IResponse |
111
|
|
|
{ |
112
|
|
|
$options = $this->mergeOptions([ |
113
|
|
|
GuzzleHttp\RequestOptions::HEADERS => $this->jsonApiHeaders(FALSE), |
114
|
|
|
GuzzleHttp\RequestOptions::QUERY => $parameters ? $this->parseQuery($parameters) : NULL, |
115
|
|
|
], $options); |
116
|
|
|
|
117
|
|
|
return $this->request(NHttp\IRequest::GET, $endpoint, $options); |
118
|
|
|
} |
119
|
|
|
|
120
|
|
|
/** |
121
|
|
|
* {@inheritdoc} |
122
|
|
|
*/ |
123
|
|
|
public function create(string $endpoint, $record, EncodingParametersInterface $parameters = NULL, array $options = []) : Http\IResponse |
124
|
|
|
{ |
125
|
|
|
if (!is_object($record)) { |
126
|
|
|
throw new Exceptions\InvalidArgumentException('Provided data entity is not an object.'); |
127
|
|
|
} |
128
|
|
|
|
129
|
|
|
return $this->sendRecord($endpoint, NHttp\IRequest::POST, $this->serializeRecord($record), $parameters, $options); |
130
|
|
|
} |
131
|
|
|
|
132
|
|
|
/** |
133
|
|
|
* {@inheritdoc} |
134
|
|
|
*/ |
135
|
|
|
public function update(string $endpoint, $record, array $fields = NULL, EncodingParametersInterface $parameters = NULL, array $options = []) : Http\IResponse |
136
|
|
|
{ |
137
|
|
|
if (!is_object($record)) { |
138
|
|
|
throw new Exceptions\InvalidArgumentException('Provided data entity is not an object.'); |
139
|
|
|
} |
140
|
|
|
|
141
|
|
|
return $this->sendRecord($endpoint, NHttp\IRequest::PATCH, $this->serializeRecord($record, $fields), $parameters, $options); |
142
|
|
|
} |
143
|
|
|
|
144
|
|
|
/** |
145
|
|
|
* {@inheritdoc} |
146
|
|
|
*/ |
147
|
|
|
public function delete(string $endpoint, array $options = []) : Http\IResponse |
148
|
|
|
{ |
149
|
|
|
$options = $this->mergeOptions([ |
150
|
|
|
GuzzleHttp\RequestOptions::HEADERS => $this->jsonApiHeaders(FALSE) |
151
|
|
|
], $options); |
152
|
|
|
|
153
|
|
|
return $this->request(NHttp\IRequest::DELETE, $endpoint, $options); |
154
|
|
|
} |
155
|
|
|
|
156
|
|
|
/** |
157
|
|
|
* {@inheritdoc} |
158
|
|
|
*/ |
159
|
|
|
public function addApiKey(string $key) : void |
160
|
|
|
{ |
161
|
|
|
$this->addHeader('X-Api-Key', $key); |
162
|
|
|
} |
163
|
|
|
|
164
|
|
|
/** |
165
|
|
|
* {@inheritdoc} |
166
|
|
|
*/ |
167
|
|
|
public function addAuthorization(string $token) : void |
168
|
|
|
{ |
169
|
|
|
$this->addHeader('Authorization', 'Bearer ' . $token); |
170
|
|
|
} |
171
|
|
|
|
172
|
|
|
/** |
173
|
|
|
* {@inheritdoc} |
174
|
|
|
*/ |
175
|
|
|
public function removeAuthorization() : void |
176
|
|
|
{ |
177
|
|
|
if (isset($this->headers['Authorization'])) { |
178
|
|
|
unset($this->headers['Authorization']); |
179
|
|
|
} |
180
|
|
|
} |
181
|
|
|
|
182
|
|
|
/** |
183
|
|
|
* {@inheritdoc} |
184
|
|
|
*/ |
185
|
|
|
public function addHeader(string $header, string $value) : void |
186
|
|
|
{ |
187
|
|
|
$this->headers[$header] = $value; |
188
|
|
|
} |
189
|
|
|
|
190
|
|
|
/** |
191
|
|
|
* @param string $endpoint |
192
|
|
|
* @param string $method |
193
|
|
|
* @param array $serializedRecord the encoded record |
194
|
|
|
* @param EncodingParametersInterface|NULL $parameters |
195
|
|
|
* @param array $options |
196
|
|
|
* |
197
|
|
|
* @return Http\IResponse |
198
|
|
|
* |
199
|
|
|
* @throws JsonApiException |
200
|
|
|
* @throws GuzzleHttp\Exception\GuzzleException |
201
|
|
|
* @throws Utils\JsonException |
202
|
|
|
*/ |
203
|
|
|
protected function sendRecord(string $endpoint, string $method, array $serializedRecord, EncodingParametersInterface $parameters = NULL, array $options = []) : Http\IResponse |
204
|
|
|
{ |
205
|
|
|
$options = $this->mergeOptions([ |
206
|
|
|
GuzzleHttp\RequestOptions::HEADERS => $this->jsonApiHeaders(TRUE), |
207
|
|
|
GuzzleHttp\RequestOptions::QUERY => $parameters ? $this->parseQuery($parameters) : NULL, |
208
|
|
|
], $options); |
209
|
|
|
|
210
|
|
|
$options['json'] = $serializedRecord; |
211
|
|
|
|
212
|
|
|
return $this->request($method, $endpoint, $options); |
213
|
|
|
} |
214
|
|
|
|
215
|
|
|
/** |
216
|
|
|
* @param array $new |
217
|
|
|
* @param array $existing |
218
|
|
|
* |
219
|
|
|
* @return array |
220
|
|
|
*/ |
221
|
|
|
protected function mergeOptions(array $new, array $existing) : array |
222
|
|
|
{ |
223
|
|
|
return array_replace_recursive($new, $existing); |
224
|
|
|
} |
225
|
|
|
|
226
|
|
|
/** |
227
|
|
|
* @param string $method |
228
|
|
|
* @param string $uri |
229
|
|
|
* @param array $options |
230
|
|
|
* |
231
|
|
|
* @return Http\IResponse |
232
|
|
|
* |
233
|
|
|
* @throws JsonApiException |
234
|
|
|
* @throws GuzzleHttp\Exception\GuzzleException |
235
|
|
|
* @throws Utils\JsonException |
236
|
|
|
*/ |
237
|
|
|
protected function request(string $method, string $uri, array $options = []) : Http\IResponse |
238
|
|
|
{ |
239
|
|
|
$request = new Request($method, $uri); |
240
|
|
|
|
241
|
|
|
try { |
242
|
|
|
$response = $this->http->send($request, $options); |
243
|
|
|
|
244
|
|
|
} catch (BadResponseException $ex) { |
|
|
|
|
245
|
|
|
throw $this->parseErrorResponse($request, $ex); |
246
|
|
|
} |
247
|
|
|
|
248
|
|
|
return new Http\Response($response, $this->createDocumentObject($request, $response)); |
249
|
|
|
} |
250
|
|
|
|
251
|
|
|
/** |
252
|
|
|
* Safely parse an error response. |
253
|
|
|
* |
254
|
|
|
* This method wraps decoding the body content of the provided exception, so that |
255
|
|
|
* another exception is not thrown while trying to parse an existing exception. |
256
|
|
|
* |
257
|
|
|
* @param PsrRequest $request |
258
|
|
|
* @param BadResponseException $ex |
259
|
|
|
* |
260
|
|
|
* @return JsonApiException |
261
|
|
|
*/ |
262
|
|
|
private function parseErrorResponse(PsrRequest $request, BadResponseException $ex) : JsonApiException |
263
|
|
|
{ |
264
|
|
|
try { |
265
|
|
|
$response = $ex->getResponse(); |
266
|
|
|
|
267
|
|
|
$document = $response ? $this->createDocumentObject($request, $response) : NULL; |
268
|
|
|
|
269
|
|
|
$errors = $document && $document->getErrors() !== NULL ? $document->getErrors() : [$this->createErrorObject($request, $response)]; |
270
|
|
|
|
271
|
|
|
$statusCode = $response ? $response->getStatusCode() : 0; |
272
|
|
|
|
273
|
|
|
} catch (\Exception $e) { |
274
|
|
|
$errors = []; |
275
|
|
|
$statusCode = 0; |
276
|
|
|
} |
277
|
|
|
|
278
|
|
|
return new JsonApiException($errors, $statusCode, $ex); |
279
|
|
|
} |
280
|
|
|
|
281
|
|
|
/** |
282
|
|
|
* @param PsrRequest $request |
283
|
|
|
* @param PsrResponse|NULL $response |
284
|
|
|
* |
285
|
|
|
* @return Objects\IDocument|NULL |
286
|
|
|
* |
287
|
|
|
* @throws Utils\JsonException |
288
|
|
|
*/ |
289
|
|
|
private function createDocumentObject(PsrRequest $request, PsrResponse $response = NULL) : ?Objects\IDocument |
290
|
|
|
{ |
291
|
|
|
return new Objects\Document(Utils\Json::decode(($response ? (string) $response->getBody() : (string) $request->getBody()))); |
292
|
|
|
} |
293
|
|
|
|
294
|
|
|
/** |
295
|
|
|
* @param PsrRequest $request |
296
|
|
|
* @param PsrResponse|NULL $response |
297
|
|
|
* |
298
|
|
|
* @return Objects\IMutableError|NULL |
299
|
|
|
* |
300
|
|
|
* @throws Utils\JsonException |
301
|
|
|
*/ |
302
|
|
|
private function createErrorObject(PsrRequest $request, PsrResponse $response = NULL) : ?Objects\IMutableError |
303
|
|
|
{ |
304
|
|
|
return Objects\Error::create(Utils\Json::decode(($response ? (string) $response->getBody() : (string) $request->getBody()), Utils\Json::FORCE_ARRAY)); |
305
|
|
|
} |
306
|
|
|
|
307
|
|
|
/** |
308
|
|
|
* @param string $baseUri |
309
|
|
|
* |
310
|
|
|
* @return Client |
311
|
|
|
*/ |
312
|
|
|
private function createClient(string $baseUri) : Client |
313
|
|
|
{ |
314
|
1 |
|
$client = new Client([ |
315
|
1 |
|
'base_uri' => $baseUri, |
316
|
|
|
]); |
317
|
|
|
|
318
|
1 |
|
return $client; |
319
|
|
|
} |
320
|
|
|
} |
321
|
|
|
|
Scrutinizer analyzes your
composer.json
/composer.lock
file if available to determine the classes, and functions that are defined by your dependencies.It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.