Completed
Push — master ( 5e707a...73f162 )
by Stefan
02:28
created

Options::asString()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 6
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
1
<?php
2
3
namespace Gemz\HttpClient\Contracts;
4
5
use Gemz\HttpClient\Exceptions\InvalidArgument;
6
use Symfony\Component\Mime\Part\Multipart\FormDataPart;
7
8
trait Options
9
{
10
    /** @var string */
11
    private static $CONTENT_TYPE_JSON = 'application/json';
12
13
    /** @var string */
14
    private static $CONTENT_TYPE_PLAIN = 'text/plain';
15
16
    /** @var string */
17
    private static $CONTENT_TYPE_MULTIPART = 'multipart/form-data';
18
19
    /** @var string */
20
    private static $CONTENT_TYPE_FORM_PARAMS = 'application/x-www-form-urlencoded';
21
22
    /** @var string */
23
    protected static $CUSTOM_DATA_HEADER = 'X-Custom-Data';
24
25
    /** @var array<mixed> */
26
    protected $options = [];
27
28
    /** @var bool */
29
    protected $throwErrors = false;
30
31
    /** @var array<String> */
32
    protected $bodyFormats = [
33
        'json' => 'json',
34
        'multipart' => 'body',
35
        'form_params' => 'body',
36
        'string' => 'body',
37
    ];
38
39
    /** @var string */
40
    protected $bodyFormat = 'json';
41
42
    /**
43
     * Set authentication auth bearer token
44
     *
45
     * @param string $token
46
     *
47
     * @return $this
48
     */
49
    public function authBearer(string $token): self
50
    {
51
        return $this->option('auth_bearer', $token);
52
    }
53
54
    /**
55
     * Set authentication auth basic. If password is null
56
     * only username will be used
57
     *
58
     * @param string $username
59
     * @param string $password
60
     *
61
     * @return $this
62
     */
63
    public function authBasic(string $username, string $password = ''): self
64
    {
65
        $this->options['auth_basic'] = $username;
66
67
        if ('' !== $password) {
68
            $this->options['auth_basic'] .= ':' . $password;
69
        }
70
71
        return $this;
72
    }
73
74
    /**
75
     * @return $this
76
     */
77
    public function throwErrors(): self
78
    {
79
        $this->throwErrors = true;
80
81
        return $this;
82
    }
83
84
    /**
85
     * @return bool
86
     */
87
    public function shouldThrowErrors(): bool
88
    {
89
        return $this->throwErrors;
90
    }
91
92
    /**
93
     * Values for existing header keys will be replaced
94
     *
95
     * @param string $key
96
     * @param string $value
97
     *
98
     * @return $this
99
     */
100
    public function header(string $key, string $value): self
101
    {
102
        $this->options['headers'][$key] = $value;
103
104
        return $this;
105
    }
106
107
    /**
108
     * Values for existing header keys will be replaced
109
     *
110
     * @param array<String> $headers
111
     *
112
     * @return $this
113
     */
114
    public function headers(array $headers): self
115
    {
116
        foreach ($headers as $key => $value) {
117
            $this->header($key, $value);
118
        }
119
120
        return $this;
121
    }
122
123
    /**
124
     * Set the base uri.
125
     *
126
     * @param string $uri
127
     *
128
     * @return $this
129
     */
130
    public function baseUri(string $uri): self
131
    {
132
        return $this->option('base_uri', $uri);
133
    }
134
135
    /**
136
     * Disallows redirects.
137
     *
138
     * @return $this
139
     */
140
    public function disallowRedirects(): self
141
    {
142
        return $this->option('max_redirects', -1);
143
    }
144
145
    /**
146
     * @param int $max
147
     *
148
     * @return $this
149
     */
150
    public function allowRedirects(int $max = 0): self
151
    {
152
        return $this->option('max_redirects', $max);
153
    }
154
155
    /**
156
     * Float describing the timeout of the request in seconds.
157
     * use 0 to wait indefinitely
158
     *
159
     * @param float $seconds
160
     *
161
     * @return $this
162
     */
163
    public function timeout(float $seconds): self
164
    {
165
        return $this->option('timeout', $seconds);
166
    }
167
168
    /**
169
     * Pass a string to specify an HTTP proxy, or an array to specify different proxies for different protocols.
170
     *
171
     * @param string|array<String> $proxy
172
     *
173
     * @return $this
174
     */
175
    public function useProxy($proxy): self
176
    {
177
        return $this->option('proxy', $proxy);
178
    }
179
180
    /**
181
     * @param float $seconds
182
     *
183
     * @return $this
184
     */
185
    public function maxDuration(float $seconds): self
186
    {
187
        return $this->option('max_duration', $seconds);
188
    }
189
190
    /**
191
     * Does not verify SSL certificates
192
     *
193
     * @return $this
194
     */
195
    public function doNotVerifySsl(): self
196
    {
197
        $this->option('verify_peer', false);
198
        $this->option('verify_host', false);
199
200
        return $this;
201
    }
202
203
    /**
204
     * Does verify SSL certificates
205
     *
206
     * @return $this
207
     */
208
    public function verifySsl(): self
209
    {
210
        $this->option('verify_peer', true);
211
        $this->option('verify_host', true);
212
213
        return $this;
214
    }
215
216
    /**
217
     * Set the content type
218
     *
219
     * @param string $type
220
     *
221
     * @return $this
222
     */
223
    public function contentType(string $type): self
224
    {
225
        return $this->header('Content-Type', $type);
226
    }
227
228
    /**
229
     * Set the clients user agent
230
     *
231
     * @param string $agent
232
     *
233
     * @return $this
234
     */
235
    public function userAgent(string $agent): self
236
    {
237
        return $this->header('User-Agent', $agent);
238
    }
239
240
    /**
241
     * Set accept header
242
     *
243
     * @param string $value
244
     *
245
     * @return $this
246
     */
247
    public function accept(string $value): self
248
    {
249
        return $this->header('Accept', $value);
250
    }
251
252
    /**
253
     * Set option according guzzle request options
254
     *
255
     * @param string $key
256
     * @param mixed $value
257
     *
258
     * @return $this
259
     */
260
    public function option(string $key, $value): self
261
    {
262
        $this->options[$key] = $value;
263
264
        return $this;
265
    }
266
267
    /**
268
     * Set param for the query url
269
     *
270
     * @param string $key
271
     * @param string $value
272
     *
273
     * @return $this
274
     */
275
    public function queryParam(string $key, string $value): self
276
    {
277
        $this->options['query'][$key] = $value;
278
279
        return $this;
280
    }
281
282
    /**
283
     * Set multiple params for query url
284
     * in form of [<key> => <value>, <key2> => <value2>]
285
     *
286
     * @param array<String> $params
287
     *
288
     * @return $this
289
     */
290
    public function queryParams(array $params): self
291
    {
292
        foreach ($params as $key => $value) {
293
            $this->queryParam($key, $value);
294
        }
295
296
        return $this;
297
    }
298
299
    /**
300
     * Any extra data to attach to the response header
301
     * Available in response->customData(). Useful when using asynchronous requests
302
     * to identify the request
303
     *
304
     * @param mixed $data
305
     *
306
     * @return $this
307
     */
308
    public function customData($data): self
309
    {
310
        return $this->option('user_data', $data);
311
    }
312
313
    /**
314
     * @param string $format
315
     *
316
     * @return $this
317
     */
318
    protected function bodyFormat(string $format): self
319
    {
320
        $this->bodyFormat = $format;
321
322
        return $this;
323
    }
324
325
    /**
326
     * Set the content type and body format for strings
327
     * @return $this
328
     */
329
    public function asString()
330
    {
331
        return $this
332
            ->bodyFormat('string')
333
            ->contentType(self::$CONTENT_TYPE_PLAIN);
334
    }
335
336
    /**
337
     * Set the content type and body format json
338
     *
339
     * @return $this
340
     */
341
    public function asJson(): self
342
    {
343
        return $this
344
            ->bodyFormat('json')
345
            ->contentType(self::$CONTENT_TYPE_JSON);
346
    }
347
348
    /**
349
     * Set the content type and body format form params
350
     *
351
     * @return $this
352
     */
353
    public function asFormParams(): self
354
    {
355
        return $this
356
            ->bodyFormat('form_params')
357
            ->contentType(self::$CONTENT_TYPE_FORM_PARAMS);
358
    }
359
360
    /**
361
     * Set the content type and body format multipart form-data
362
     *
363
     * @return $this
364
     */
365
    public function asMultipart(): self
366
    {
367
        return $this->bodyFormat('multipart');
368
    }
369
370
    /**
371
     * @return array<mixed>
372
     */
373
    public function getHeaders(): array
374
    {
375
        return $this->options['headers'] ?? [];
376
    }
377
378
    /**
379
     * @return null|string
380
     */
381
    public function getContentType()
382
    {
383
        return array_key_exists('Content-Type', $this->getHeaders())
384
            ? $this->getHeaders()['Content-Type']
385
            : null;
386
    }
387
388
    /**
389
     * @return string
390
     */
391
    public function getBodyFormat(): string
392
    {
393
        return $this->bodyFormat;
394
    }
395
396
    /**
397
     * Set any payload text, array, resource, callable ...
398
     *
399
     * @param mixed $payload
400
     *
401
     * @return $this
402
     */
403
    public function payload($payload): self
404
    {
405
        return $this->option('body', $payload);
406
    }
407
408
    /**
409
     * @param string $option
410
     *
411
     * @return mixed
412
     */
413
    protected function getOption(string $option)
414
    {
415
        return $this->options[$option] ?? '';
416
    }
417
418
    /**
419
     * @return $this
420
     */
421
    protected function resolveJsonPayload(): self
422
    {
423
        $body = $this->getOption('body');
424
425
        if (! empty($body) && is_array($body)) {
426
            $this->option('body', json_encode($body));
427
        }
428
429
        return $this;
430
    }
431
432
    /**
433
     * @return $this
434
     */
435
    public function resolveMultipartPayload(): self
436
    {
437
        $body = $this->getOption('body');
438
439
        if (! is_array($body) || ! is_iterable($body)) {
440
            throw InvalidArgument::payloadMustBeArray();
441
        }
442
443
        $formData = new FormDataPart($body);
444
        $headers = $formData->getPreparedHeaders()->toArray();
445
        [$name, $value] = explode(':', $headers[0], 2);
0 ignored issues
show
Bug introduced by
The variable $name does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
Bug introduced by
The variable $value does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
446
447
        $this->header($name, $value);
448
        $this->body($formData->bodyToIterable());
449
450
        return $this;
451
    }
452
453
    /**
454
     * @return $this
455
     */
456
    public function resolveFormParamsPayload(): self
457
    {
458
        $body = $this->getOption('body');
459
460
        if (!is_array($body) || !is_iterable($body)) {
461
            throw InvalidArgument::payloadMustBeArray();
462
        }
463
464
        return $this;
465
    }
466
467
    /**
468
     * resolve the payload
469
     * if body format is json then payload value must be json encoded
470
     *
471
     * @return $this
472
     */
473
    protected function resolvePayload(): self
474
    {
475
        $bodyFormat = $this->getBodyFormat();
476
477
478
        if ($bodyFormat == 'json') {
479
            $this->resolveJsonPayload();
480
        }
481
482
        if ($bodyFormat == 'multipart') {
483
            $this->resolveMultipartPayload();
484
        }
485
486
        if ($bodyFormat == 'form_params') {
487
            $this->resolveFormParamsPayload();
488
        }
489
490
        return $this;
491
    }
492
493
    /**
494
     * remove an option
495
     *
496
     * @param string $option
497
     *
498
     * @return $this
499
     */
500
    protected function removeOption(string $option): self
501
    {
502
        unset($this->options[$option]);
503
504
        return $this;
505
    }
506
507
    /**
508
     * @param array<String> $options
509
     *
510
     * @return $this
511
     */
512
    protected function removeOptions(array $options): self
513
    {
514
        foreach ($options as $option) {
515
            if (! is_string($option)) {
516
                continue;
517
            }
518
519
            $this->removeOption($option);
520
        }
521
522
        return $this;
523
    }
524
525
    /**
526
     * @param mixed $body
527
     *
528
     * @return $this
529
     */
530
    protected function body($body): self
531
    {
532
        return $this->option('body', $body);
533
    }
534
}
535