Completed
Branch develop (205409)
by Timothy
07:06
created

APIRequestBuilder::setHeader()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 3
nc 1
nop 2
dl 0
loc 5
rs 9.4285
c 0
b 0
f 0
1
<?php declare(strict_types=1);
2
/**
3
 * Anime List Client
4
 *
5
 * An API client for Kitsu and MyAnimeList to manage anime and manga watch lists
6
 *
7
 * PHP version 7
8
 *
9
 * @package     AnimeListClient
10
 * @author      Timothy J. Warren <[email protected]>
11
 * @copyright   2015 - 2017  Timothy J. Warren
12
 * @license     http://www.opensource.org/licenses/mit-license.html  MIT License
13
 * @version     4.0
14
 * @link        https://github.com/timw4mail/HummingBirdAnimeClient
15
 */
16
17
namespace Aviat\AnimeClient\API;
18
19
use Amp\Artax\{
20
	Client, 
21
	FormBody, 
22
	Request
23
};
24
use Aviat\Ion\Di\ContainerAware;
25
use InvalidArgumentException;
26
use Psr\Log\LoggerAwareTrait;
27
28
/**
29
 * Wrapper around Artex to make it easier to build API requests
30
 */
31
class APIRequestBuilder {
32
	use LoggerAwareTrait;
33
	
34
	/**
35
	 * Url prefix for making url requests
36
	 * @var string
37
	 */
38
	protected $baseUrl = '';
39
	
40
	/**
41
	 * Url path of the request
42
	 * @var string
43
	 */
44
	protected $path = '';
45
	
46
	/**
47
	 * Query string for the request
48
	 * @var string
49
	 */
50
	protected $query = '';
51
	
52
	/**
53
	 * Default request headers
54
	 * @var array
55
	 */
56
	protected $defaultHeaders = [];
57
	
58
	/**
59
	 * Valid HTTP request methos
60
	 * @var array
61
	 */
62
	protected $validMethods = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'];
63
	
64
	/**
65
	 * The current request
66
	 * @var \Amp\Promise
67
	 */
68
	protected $request;
69
	
70
	/**
71
	 * Set body as form fields
72
	 * 
73
	 * @param array $fields Mapping of field names to values
74
	 * @return self
75
	 */
76
	public function setFormFields(array $fields): self
0 ignored issues
show
Unused Code introduced by
The parameter $fields is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
77
	{
78
		$body = $this->fixBody((new FormBody)->addFields($createData));
0 ignored issues
show
Bug introduced by
The variable $createData 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...
79
		$this->setBody($body);
80
		return $this;
81
	}
82
	
83
	/**
84
	 * Set the request body
85
	 *
86
	 * @param FormBody|string $body
87
	 * @return self
88
	 */
89
	public function setBody($body): self
90
	{
91
		$this->request->setBody($body);
0 ignored issues
show
Bug introduced by
The method setBody() does not seem to exist on object<Amp\Promise>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
92
		return $this;
93
	}
94
	
95
	/**
96
	 * Set a request header
97
	 *
98
	 * @param string $name
99
	 * @param string $value
100
	 * @return self
101
	 */
102
	public function setHeader(string $name, string $value): self
103
	{
104
		$this->request->setHeader($name, $value);
0 ignored issues
show
Bug introduced by
The method setHeader() does not seem to exist on object<Amp\Promise>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
105
		return $this;
106
	}
107
	
108
	/**
109
	 * Set multiple request headers
110
	 * 
111
	 * name => value
112
	 *
113
	 * @param array $headers
114
	 * @return self
115
	 */
116
	public function setHeaders(array $headers): self
117
	{
118
		foreach ($headers as $name => $value)
119
		{
120
			$this->setHeader($name, $value);
121
		}
122
		
123
		return $this;
124
	}
125
	
126
	/**
127
	 * Append a query string in array format
128
	 *
129
	 * @param array $params
130
	 * @return self
131
	 */
132
	public function setQuery(array $params): self
133
	{
134
		$this->query = http_build_query($params);	
135
		return $this;
136
	}
137
	
138
	/**
139
	 * Return the promise for the current request
140
	 *
141
	 * @return \Amp\Promise
142
	 */
143
	public function getFullRequest()
144
	{
145
		$this->buildUri();
146
		return $this->request;
147
	}
148
	
149
	/**
150
	 * Create a new http request
151
	 *
152
	 * @param string $type
153
	 * @param string $uri
154
	 * @return self
155
	 */
156
	public function newRequest(string $type, string $uri): self
0 ignored issues
show
Unused Code introduced by
The parameter $uri is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
157
	{
158
		if ( ! in_array($type, $this->validMethods))
159
		{
160
			throw new InvalidArgumentException('Invalid HTTP methods');
161
		}
162
		
163
		$this->resetState();
164
		
165
		$this->request
0 ignored issues
show
Bug introduced by
The method setMethod() does not seem to exist on object<Amp\Promise>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
166
			->setMethod($type)
167
			->setProtocol('1.1');
168
		
169
		return $this;
170
	}
171
	
172
	/**
173
	 * Create the full request url
174
	 *
175
	 * @return void
176
	 */
177
	private function buildUri()
178
	{
179
		$url = (strpos($this->path, '//') !== FALSE)
180
			? $this->path
181
			: $this->baseUrl . $url;
0 ignored issues
show
Bug introduced by
The variable $url seems only to be defined at a later point. Did you maybe move this code here without moving the variable definition?

This error can happen if you refactor code and forget to move the variable initialization.

Let’s take a look at a simple example:

function someFunction() {
    $x = 5;
    echo $x;
}

The above code is perfectly fine. Now imagine that we re-order the statements:

function someFunction() {
    echo $x;
    $x = 5;
}

In that case, $x would be read before it is initialized. This was a very basic example, however the principle is the same for the found issue.

Loading history...
182
183
		if ( ! empty($this->query))
184
		{
185
			$url .= '?' . $this->query;
186
		}
187
		
188
		$this->request->setUri($url);
0 ignored issues
show
Bug introduced by
The method setUri() does not seem to exist on object<Amp\Promise>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
189
	}
190
	
191
	/**
192
	 * Unencode the dual-encoded ampersands in the body
193
	 *
194
	 * This is a dirty hack until I can fully track down where
195
	 * the dual-encoding happens
196
	 *
197
	 * @param FormBody $formBody The form builder object to fix
0 ignored issues
show
Documentation introduced by
Should the type for parameter $formBody not be \Amp\Artax\FormBody?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
198
	 * @return string
199
	 */
200
	private function fixBody(FormBody $formBody): string
201
	{
202
		$rawBody = \Amp\wait($formBody->getBody());
203
		return html_entity_decode($rawBody, \ENT_HTML5, 'UTF-8');
204
	}
205
	
206
	/**
207
	 * Reset the class state for a new request
208
	 *
209
	 * @return void
210
	 */
211
	private function resetState()
212
	{
213
		$this->path = '';
214
		$this->query = '';
215
		$this->request = new Request();
0 ignored issues
show
Documentation Bug introduced by
It seems like new \Amp\Artax\Request() of type object<Amp\Artax\Request> is incompatible with the declared type object<Amp\Promise> of property $request.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
216
	}
217
}