APIRequestBuilder::resetState()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 4
nc 1
nop 0
dl 0
loc 6
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;
20
use Amp\Artax\{
21
	Client,
22
	FormBody,
23
	Request
24
};
25
use Aviat\Ion\Di\ContainerAware;
26
use Aviat\Ion\Json;
27
use InvalidArgumentException;
28
use Psr\Log\LoggerAwareTrait;
29
30
/**
31
 * Wrapper around Artex to make it easier to build API requests
32
 */
33
class APIRequestBuilder {
34
	use LoggerAwareTrait;
35
36
	/**
37
	 * Url prefix for making url requests
38
	 * @var string
39
	 */
40
	protected $baseUrl = '';
41
42
	/**
43
	 * Url path of the request
44
	 * @var string
45
	 */
46
	protected $path = '';
47
48
	/**
49
	 * Query string for the request
50
	 * @var string
51
	 */
52
	protected $query = '';
53
54
	/**
55
	 * Default request headers
56
	 * @var array
57
	 */
58
	protected $defaultHeaders = [];
59
60
	/**
61
	 * Valid HTTP request methos
62
	 * @var array
63
	 */
64
	protected $validMethods = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'];
65
66
	/**
67
	 * The current request
68
	 * @var \Amp\Promise
69
	 */
70
	protected $request;
71
72
	/**
73
	 * Set an authorization header
74
	 *
75
	 * @param string $type The type of authorization, eg, basic, bearer, etc.
76
	 * @param string $value The authorization value
77
	 * @return self
78
	 */
79
	public function setAuth(string $type, string $value): self
80
	{
81
		$authString = ucfirst($type) . ' ' . $value;
82
		$this->setHeader('Authorization', $authString);
83
84
		return $this;
85
	}
86
87
	/**
88
	 * Set a basic authentication header
89
	 *
90
	 * @param string $username
91
	 * @param string $password
92
	 * @return self
93
	 */
94
	public function setBasicAuth(string $username, string $password): self
95
	{
96
		$this->setAuth('basic', base64_encode($username . ':' . $password));
97
		return $this;
98
	}
99
100
	/**
101
	 * Set the request body
102
	 *
103
	 * @param FormBody|string $body
104
	 * @return self
105
	 */
106
	public function setBody($body): self
107
	{
108
		$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...
109
		return $this;
110
	}
111
112
	/**
113
	 * Set body as form fields
114
	 *
115
	 * @param array $fields Mapping of field names to values
116
	 * @return self
117
	 */
118
	public function setFormFields(array $fields): self
119
	{
120
		$this->setHeader("Content-Type", "application/x-www-form-urlencoded");
121
		$body = (new FormBody)->addFields($fields);
122
		$this->setBody($body);
0 ignored issues
show
Documentation introduced by
$body is of type object<Amp\Artax\FormBody>, but the function expects a object<FormBody>|string.

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...
123
		return $this;
124
	}
125
126
	/**
127
	 * Set a request header
128
	 *
129
	 * @param string $name
130
	 * @param string $value
131
	 * @return self
132
	 */
133
	public function setHeader(string $name, string $value): self
134
	{
135
		$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...
136
		return $this;
137
	}
138
139
	/**
140
	 * Set multiple request headers
141
	 *
142
	 * name => value
143
	 *
144
	 * @param array $headers
145
	 * @return self
146
	 */
147
	public function setHeaders(array $headers): self
148
	{
149
		foreach ($headers as $name => $value)
150
		{
151
			$this->setHeader($name, $value);
152
		}
153
154
		return $this;
155
	}
156
157
	/**
158
	 * Set the request body
159
	 *
160
	 * @param mixed $body
161
	 * @return self
162
	 */
163
	public function setJsonBody($body): self
164
	{
165
		$requestBody = ( ! is_scalar($body))
166
			? Json::encode($body)
167
			: $body;
168
		
169
		return $this->setBody($requestBody);
170
	}
171
172
	/**
173
	 * Append a query string in array format
174
	 *
175
	 * @param array $params
176
	 * @return self
177
	 */
178
	public function setQuery(array $params): self
179
	{
180
		$this->query = http_build_query($params);
181
		return $this;
182
	}
183
184
	/**
185
	 * Return the promise for the current request
186
	 *
187
	 * @return \Amp\Promise
188
	 */
189
	public function getFullRequest()
190
	{
191
		$this->buildUri();
192
193
		if ($this->logger)
194
		{
195
			$this->logger->debug('API Request', [
196
				'request_url' => $this->request->getUri(),
0 ignored issues
show
Bug introduced by
The method getUri() 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...
197
				'request_headers' => $this->request->getAllHeaders(),
0 ignored issues
show
Bug introduced by
The method getAllHeaders() 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...
198
				'request_body' => $this->request->getBody()
0 ignored issues
show
Bug introduced by
The method getBody() 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...
199
			]);
200
		}
201
202
		return $this->request;
203
	}
204
205
	/**
206
	 * Create a new http request
207
	 *
208
	 * @param string $type
209
	 * @param string $uri
210
	 * @return self
211
	 */
212
	public function newRequest(string $type, string $uri): self
213
	{
214
		if ( ! in_array($type, $this->validMethods))
215
		{
216
			throw new InvalidArgumentException('Invalid HTTP methods');
217
		}
218
219
		$this->resetState();
220
221
		$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...
222
			->setMethod($type)
223
			->setProtocol('1.1');
224
225
		$this->path = $uri;
226
227
		if ( ! empty($this->defaultHeaders))
228
		{
229
			$this->setHeaders($this->defaultHeaders);
230
		}
231
232
		return $this;
233
	}
234
235
	/**
236
	 * Create the full request url
237
	 *
238
	 * @return void
239
	 */
240
	private function buildUri()
241
	{
242
		$url = (strpos($this->path, '//') !== FALSE)
243
			? $this->path
244
			: $this->baseUrl . $this->path;
245
246
		if ( ! empty($this->query))
247
		{
248
			$url .= '?' . $this->query;
249
		}
250
251
		$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...
252
	}
253
254
	/**
255
	 * Reset the class state for a new request
256
	 *
257
	 * @return void
258
	 */
259
	private function resetState()
260
	{
261
		$this->path = '';
262
		$this->query = '';
263
		$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...
264
	}
265
}