Completed
Push — master ( 2baebf...b22d69 )
by smiley
01:43
created

HTTPClientAbstract::request()   B

Complexity

Conditions 9
Paths 16

Size

Total Lines 34

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 9
nc 16
nop 5
dl 0
loc 34
rs 8.0555
c 0
b 0
f 0
1
<?php
2
/**
3
 * Class HTTPClientAbstract
4
 *
5
 * @filesource   HTTPClientAbstract.php
6
 * @created      22.02.2019
7
 * @package      chillerlan\HTTP\Psr18
8
 * @author       smiley <[email protected]>
9
 * @copyright    2019 smiley
10
 * @license      MIT
11
 */
12
13
namespace chillerlan\HTTP\Psr18;
14
15
use chillerlan\HTTP\{HTTPOptions, Psr7, Psr17};
16
use chillerlan\HTTP\Psr7\Request;
17
use chillerlan\HTTP\Psr17\ResponseFactory;
18
use chillerlan\Settings\SettingsContainerInterface;
19
use Psr\Http\Message\{ResponseFactoryInterface, ResponseInterface};
20
use Psr\Log\{LoggerAwareInterface, LoggerAwareTrait, LoggerInterface, NullLogger};
21
22
abstract class HTTPClientAbstract implements HTTPClientInterface, LoggerAwareInterface{
23
	use LoggerAwareTrait;
24
25
	/**
26
	 * @var \chillerlan\HTTP\HTTPOptions
27
	 */
28
	protected $options;
29
30
	/**
31
	 * @var \Psr\Http\Message\RequestFactoryInterface
32
	 */
33
	protected $requestFactory;
34
35
	/**
36
	 * @var \Psr\Http\Message\ResponseFactoryInterface
37
	 */
38
	protected $responseFactory;
39
40
	/**
41
	 * CurlClient constructor.
42
	 *
43
	 * @param \chillerlan\Settings\SettingsContainerInterface|null $options
44
	 * @param \Psr\Http\Message\ResponseFactoryInterface|null      $responseFactory
45
	 * @param \Psr\Log\LoggerInterface|null                        $logger
46
	 */
47
	public function __construct(
48
		SettingsContainerInterface $options = null,
49
		ResponseFactoryInterface $responseFactory = null,
50
		LoggerInterface $logger = null
51
	){
52
		$this->options         = $options ?? new HTTPOptions;
0 ignored issues
show
Documentation Bug introduced by
$options ?? new \chillerlan\HTTP\HTTPOptions() is of type object<chillerlan\Settin...ingsContainerInterface>, but the property $options was declared to be of type object<chillerlan\HTTP\HTTPOptions>. Are you sure that you always receive this specific sub-class here, or does it make sense to add an instanceof check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a given class or a super-class is assigned to a property that is type hinted more strictly.

Either this assignment is in error or an instanceof check should be added for that assignment.

class Alien {}

class Dalek extends Alien {}

class Plot
{
    /** @var  Dalek */
    public $villain;
}

$alien = new Alien();
$plot = new Plot();
if ($alien instanceof Dalek) {
    $plot->villain = $alien;
}
Loading history...
53
		$this->responseFactory = $responseFactory ?? new ResponseFactory;
54
		$this->logger          = $logger ?? new NullLogger;
55
	}
56
57
	/**
58
	 * @todo: files, content-type
59
	 *
60
	 * @param string      $uri
61
	 * @param string|null $method
62
	 * @param array|null  $query
63
	 * @param mixed|null  $body
64
	 * @param array|null  $headers
65
	 *
66
	 * @return \Psr\Http\Message\ResponseInterface
67
	 */
68
	public function request(string $uri, string $method = null, array $query = null, $body = null, array $headers = null):ResponseInterface{
69
		$method    = strtoupper($method ?? 'GET');
70
		$headers   = Psr7\normalize_request_headers($headers);
0 ignored issues
show
Bug introduced by
It seems like $headers can also be of type null; however, chillerlan\HTTP\Psr7\normalize_request_headers() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
71
		$request   = new Request($method, Psr7\merge_query($uri, $query ?? []));
72
73
		if(in_array($method, ['DELETE', 'PATCH', 'POST', 'PUT'], true) && $body !== null){
74
75
			if(is_array($body) || is_object($body)){
76
77
				if(!isset($headers['Content-type'])){
78
					$headers['Content-type'] = 'application/x-www-form-urlencoded';
79
				}
80
81
				if($headers['Content-type'] === 'application/x-www-form-urlencoded'){
82
					$body = http_build_query($body, '', '&', PHP_QUERY_RFC1738);
83
				}
84
				elseif($headers['Content-type'] === 'application/json'){
85
					$body = json_encode($body);
86
				}
87
				else{
88
					$body = null; // @todo
89
				}
90
91
			}
92
93
			$request = $request->withBody(Psr17\create_stream((string)$body));
94
		}
95
96
		foreach($headers as $header => $value){
97
			$request = $request->withAddedHeader($header, $value);
98
		}
99
100
		return $this->sendRequest($request);
0 ignored issues
show
Documentation introduced by
$request is of type object<chillerlan\HTTP\Psr7\Message>, but the function expects a object<Psr\Http\Message\RequestInterface>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
101
	}
102
103
}
104