Completed
Push — master ( 450f6c...ad56b7 )
by Stefan
05:07
created

Options::resolvePayload()   C

Complexity

Conditions 13
Paths 6

Size

Total Lines 50

Duplication

Lines 14
Ratio 28 %

Importance

Changes 0
Metric Value
dl 14
loc 50
rs 6.6166
c 0
b 0
f 0
cc 13
nc 6
nop 0

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace Gemz\HttpClient\Contracts;
4
5
use Gemz\HttpClient\Exceptions\InvalidArgument;
6
use Psr\Http\Message\StreamInterface;
7
use Symfony\Component\Mime\Part\Multipart\FormDataPart;
8
9
trait Options
10
{
11
    /** @var string */
12
    private static $CONTENT_TYPE_JSON = 'application/json';
13
14
    /** @var string */
15
    private static $CONTENT_TYPE_PLAIN = 'text/plain';
16
17
    /** @var string */
18
    private static $CONTENT_TYPE_MULTIPART = 'multipart/form-data';
19
20
    /** @var string */
21
    private static $CONTENT_TYPE_FORM_PARAMS = 'application/x-www-form-urlencoded';
22
23
    /** @var array<String> */
24
    private $bodyFormats = ['json', 'multipart', 'form_params'];
25
26
    /** @var string */
27
    protected static $CUSTOM_DATA_HEADER = 'X-Custom-Data';
28
29
    /**
30
     * Set authentication auth bearer token
31
     *
32
     * @param string $token
33
     *
34
     * @return $this
35
     */
36
    public function authBearer(string $token): self
37
    {
38
        return $this->option('auth_bearer', $token);
39
    }
40
41
    /**
42
     * Set authentication auth basic. If password is null
43
     * only username will be used
44
     *
45
     * @param string $username
46
     * @param string $password
47
     *
48
     * @return $this
49
     */
50
    public function authBasic(string $username, string $password = ''): self
51
    {
52
        $this->options['auth_basic'] = $username;
0 ignored issues
show
Bug introduced by
The property options does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
53
54
        if ('' !== $password) {
55
            $this->options['auth_basic'] .= ':' . $password;
56
        }
57
58
        return $this;
59
    }
60
61
    /**
62
     * @return $this
63
     */
64
    public function throwErrors(): self
65
    {
66
        $this->throwErrors = true;
0 ignored issues
show
Bug introduced by
The property throwErrors does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
67
68
        return $this;
69
    }
70
71
    /**
72
     * @return bool
73
     */
74
    public function shouldThrowErrors(): bool
75
    {
76
        return $this->throwErrors;
77
    }
78
79
    /**
80
     * Values for existing header keys will be replaced
81
     *
82
     * @param string $key
83
     * @param string $value
84
     *
85
     * @return $this
86
     */
87
    public function header(string $key, string $value): self
88
    {
89
        $this->options['headers'][$key] = $value;
90
91
        return $this;
92
    }
93
94
    /**
95
     * Values for existing header keys will be replaced
96
     *
97
     * @param array<String> $headers
98
     *
99
     * @return $this
100
     */
101
    public function headers(array $headers): self
102
    {
103
        foreach ($headers as $key => $value) {
104
            $this->header($key, $value);
105
        }
106
107
        return $this;
108
    }
109
110
    /**
111
     * Set the base uri.
112
     *
113
     * @param string $uri
114
     *
115
     * @return $this
116
     */
117
    public function baseUri(string $uri): self
118
    {
119
        return $this->option('base_uri', $uri);
120
    }
121
122
    /**
123
     * Disallows redirects.
124
     *
125
     * @return $this
126
     */
127
    public function disallowRedirects(): self
128
    {
129
        return $this->option('max_redirects', -1);
130
    }
131
132
    /**
133
     * @param int $max
134
     *
135
     * @return $this
136
     */
137
    public function allowRedirects(int $max = 0): self
138
    {
139
        return $this->option('max_redirects', $max);
140
    }
141
142
    /**
143
     * Float describing the timeout of the request in seconds.
144
     * use 0 to wait indefinitely
145
     *
146
     * @param float $seconds
147
     *
148
     * @return $this
149
     */
150
    public function timeout(float $seconds): self
151
    {
152
        return $this->option('timeout', $seconds);
153
    }
154
155
    /**
156
     * Pass a string to specify an HTTP proxy, or an array to specify different proxies for different protocols.
157
     *
158
     * @param string|array<String> $proxy
159
     *
160
     * @return $this
161
     */
162
    public function useProxy($proxy): self
163
    {
164
        return $this->option('proxy', $proxy);
165
    }
166
167
    /**
168
     * @param float $seconds
169
     *
170
     * @return $this
171
     */
172
    public function maxDuration(float $seconds): self
173
    {
174
        return $this->option('max_duration', $seconds);
175
    }
176
177
    /**
178
     * Does not verify SSL certificates
179
     *
180
     * @return $this
181
     */
182
    public function doNotVerifySsl(): self
183
    {
184
        $this->option('verify_peer', false);
185
        $this->option('verify_host', false);
186
187
        return $this;
188
    }
189
190
    /**
191
     * Does verify SSL certificates
192
     *
193
     * @return $this
194
     */
195
    public function verifySsl(): self
196
    {
197
        $this->option('verify_peer', true);
198
        $this->option('verify_host', true);
199
200
        return $this;
201
    }
202
203
    /**
204
     * Set the content type
205
     *
206
     * @param string $type
207
     *
208
     * @return $this
209
     */
210
    public function contentType(string $type): self
211
    {
212
        return $this->header('Content-Type', $type);
213
    }
214
215
    /**
216
     * Set the clients user agent
217
     *
218
     * @param string $agent
219
     *
220
     * @return $this
221
     */
222
    public function userAgent(string $agent): self
223
    {
224
        return $this->header('User-Agent', $agent);
225
    }
226
227
    /**
228
     * Set accept header
229
     *
230
     * @param string $value
231
     *
232
     * @return $this
233
     */
234
    public function accept(string $value): self
235
    {
236
        return $this->header('Accept', $value);
237
    }
238
239
    /**
240
     * Set option according guzzle request options
241
     *
242
     * @param string $key
243
     * @param mixed $value
244
     *
245
     * @return $this
246
     */
247
    public function option(string $key, $value): self
248
    {
249
        $this->options[$key] = $value;
250
251
        return $this;
252
    }
253
254
    /**
255
     * Set param for the query url
256
     *
257
     * @param string $key
258
     * @param string $value
259
     *
260
     * @return $this
261
     */
262
    public function queryParam(string $key, string $value): self
263
    {
264
        $this->options['query'][$key] = $value;
265
266
        return $this;
267
    }
268
269
    /**
270
     * Set multiple params for query url
271
     * in form of [<key> => <value>, <key2> => <value2>]
272
     *
273
     * @param array<String> $params
274
     *
275
     * @return $this
276
     */
277
    public function queryParams(array $params): self
278
    {
279
        foreach ($params as $key => $value) {
280
            $this->queryParam($key, $value);
281
        }
282
283
        return $this;
284
    }
285
286
    /**
287
     * Any extra data to attach to the response header
288
     * Available in response->customData(). Useful when using asynchronous requests
289
     * to identify the request
290
     *
291
     * @param mixed $data
292
     *
293
     * @return $this
294
     */
295
    public function customData($data): self
296
    {
297
        return $this->option('user_data', $data);
298
    }
299
300
    /**
301
     * @param string $format
302
     *
303
     * @return $this
304
     */
305
    protected function bodyFormat(string $format): self
306
    {
307
        $this->bodyFormat = $format;
0 ignored issues
show
Bug introduced by
The property bodyFormat does not seem to exist. Did you mean bodyFormats?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
308
309
        return $this;
310
    }
311
312
    /**
313
     * @return $this
314
     */
315
    public function asPlainText()
316
    {
317
        $this->bodyFormat('body');
318
319
        return $this->contentType(self::$CONTENT_TYPE_PLAIN);
320
    }
321
322
    /**
323
     * @return $this
324
     */
325
    public function asJson(): self
326
    {
327
        $this->bodyFormat('json');
328
329
        return $this->contentType(self::$CONTENT_TYPE_JSON);
330
    }
331
332
    /**
333
     * @return $this
334
     */
335
    public function asFormParams(): self
336
    {
337
        $this->bodyFormat('form_params');
338
339
        return $this->contentType(self::$CONTENT_TYPE_FORM_PARAMS);
340
    }
341
342
    /**
343
     * Set the content type multipart form-data
344
     *
345
     * @return $this
346
     */
347
    public function asMultipart(): self
348
    {
349
        $this->bodyFormat('multipart');
350
351
        return $this->contentType(self::$CONTENT_TYPE_MULTIPART);
352
    }
353
354
    /**
355
     * @return array<mixed>
356
     */
357
    public function getHeaders(): array
358
    {
359
        return $this->options['headers'] ?? [];
360
    }
361
362
    /**
363
     * @return null|string
364
     */
365
    public function getContentType()
366
    {
367
        return array_key_exists('Content-Type', $this->getHeaders())
368
            ? $this->getHeaders()['Content-Type']
369
            : null;
370
    }
371
372
    /**
373
     * @return string
374
     */
375
    public function getBodyFormat(): string
376
    {
377
        return $this->bodyFormat;
0 ignored issues
show
Bug introduced by
The property bodyFormat does not seem to exist. Did you mean bodyFormats?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
378
    }
379
380
    /**
381
     * Indicates if the payload must be an array
382
     * depending on body format
383
     *
384
     * @return bool
385
     */
386
    protected function payloadMustBeArray(): bool
387
    {
388
        return in_array(
389
            $this->bodyFormat,
0 ignored issues
show
Bug introduced by
The property bodyFormat does not seem to exist. Did you mean bodyFormats?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
390
            $this->bodyFormats
391
        );
392
    }
393
394
    /**
395
     * @param mixed $payload
396
     *
397
     * @return $this
398
     */
399
    protected function throwExceptionWhenPayloadIsNotArray($payload): self
400
    {
401
        if (! is_array($payload)) {
402
            throw InvalidArgument::payloadMustBeArray();
403
        }
404
405
        return $this;
406
    }
407
408
    /**
409
     * Set any payload text, array
410
     *
411
     * @param mixed $payload
412
     *
413
     * @return $this
414
     */
415
    public function payload($payload): self
416
    {
417
        return $this->option('payload', $payload);
418
    }
419
420
    /**
421
     * @param string $option
422
     *
423
     * @return mixed
424
     */
425
    protected function getOption(string $option)
426
    {
427
        return $this->options[$option] ?? '';
428
    }
429
430
    /**
431
     * @return $this
432
     */
433
    protected function resolvePayload(): self
434
    {
435
        $payload = $this->getOption('payload');
436
437
        if (! empty($payload) || $payload == null) {
438
            $this->removeOptions(['body', 'payload']);
439
            return $this;
440
        }
441
442 View Code Duplication
        if ($this->bodyFormat == 'json' && ! empty($payload)) {
0 ignored issues
show
Bug introduced by
The property bodyFormat does not seem to exist. Did you mean bodyFormats?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
443
            $this->option('json', $payload);
444
            $this->throwExceptionWhenPayloadIsNotArray($payload);
445
            $this->removeOptions(['body', 'payload']);
446
447
            return $this;
448
        }
449
450
        if ($this->bodyFormat == 'multipart' && !empty($payload)) {
0 ignored issues
show
Bug introduced by
The property bodyFormat does not seem to exist. Did you mean bodyFormats?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
451
452
            $this->throwExceptionWhenPayloadIsNotArray($payload);
453
454
            $formData = new FormDataPart($payload);
455
456
            $this->headers($formData->getPreparedHeaders()->toArray());
457
            $this->option('body', $formData->bodyToIterable());
458
            $this->removeOptions(['json', 'payload']);
459
460
            return $this;
461
        }
462
463 View Code Duplication
        if ($this->bodyFormat == 'form_params' && !empty($payload)) {
0 ignored issues
show
Bug introduced by
The property bodyFormat does not seem to exist. Did you mean bodyFormats?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
464
            $this->option('body', $payload);
465
            $this->throwExceptionWhenPayloadIsNotArray($payload);
466
            $this->removeOptions(['json', 'payload']);
467
468
            return $this;
469
        }
470
471
        if ((is_string($payload) && $payload !== '')
472
            || is_resource($payload)
473
            || is_callable($payload)) {
474
475
            $this->option('body', $payload);
476
            $this->removeOptions(['json', 'payload']);
477
478
            return $this;
479
        } else {
480
            throw InvalidArgument::payloadAndBodyFormatNotCompatible($this->bodyFormat);
0 ignored issues
show
Bug introduced by
The property bodyFormat does not seem to exist. Did you mean bodyFormats?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
481
        }
482
    }
483
484
    /**
485
     * remove an option
486
     *
487
     * @param string $option
488
     *
489
     * @return $this
490
     */
491
    protected function removeOption(string $option): self
492
    {
493
        unset($this->options[$option]);
494
495
        return $this;
496
    }
497
498
    /**
499
     * @param array<String> $options
500
     *
501
     * @return $this
502
     */
503
    protected function removeOptions(array $options): self
504
    {
505
        foreach ($options as $option) {
506
            if (! is_string($option)) {
507
                continue;
508
            }
509
510
            $this->removeOption($option);
511
        }
512
513
        return $this;
514
    }
515
516
    /**
517
     * @param mixed $body
518
     *
519
     * @return $this
520
     */
521
    protected function body($body): self
522
    {
523
        return $this->option('body', $body);
524
    }
525
526
}
527