Skip to content

Commit ab5f4eb

Browse files
authored
Merge pull request #370 from Art4/implement-http-client-in-clients
Let Clients implements `HttpClient`
2 parents 1e7ff16 + ef1b7ce commit ab5f4eb

File tree

10 files changed

+470
-86
lines changed

10 files changed

+470
-86
lines changed

src/Redmine/Api/AbstractApi.php

Lines changed: 5 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
use Redmine\Exception;
1010
use Redmine\Exception\SerializerException;
1111
use Redmine\Http\HttpClient;
12+
use Redmine\Http\HttpFactory;
1213
use Redmine\Http\Request;
1314
use Redmine\Http\Response;
1415
use Redmine\Serializer\JsonSerializer;
@@ -73,7 +74,7 @@ final protected function getHttpClient(): HttpClient
7374

7475
final protected function getLastResponse(): Response
7576
{
76-
return $this->lastResponse !== null ? $this->lastResponse : $this->createResponse(0, '', '');
77+
return $this->lastResponse !== null ? $this->lastResponse : HttpFactory::makeResponse(0, '', '');
7778
}
7879

7980
/**
@@ -412,16 +413,12 @@ private function getResponseAsArray(Response $response): array
412413

413414
private function handleClient(Client $client): HttpClient
414415
{
415-
$responseFactory = Closure::fromCallable([$this, 'createResponse']);
416-
417-
return new class ($client, $responseFactory) implements HttpClient {
416+
return new class ($client) implements HttpClient {
418417
private $client;
419-
private $responseFactory;
420418

421-
public function __construct(Client $client, Closure $responseFactory)
419+
public function __construct(Client $client)
422420
{
423421
$this->client = $client;
424-
$this->responseFactory = $responseFactory;
425422
}
426423

427424
public function request(Request $request): Response
@@ -436,7 +433,7 @@ public function request(Request $request): Response
436433
$this->client->requestGet($request->getPath());
437434
}
438435

439-
return ($this->responseFactory)(
436+
return HttpFactory::makeResponse(
440437
$this->client->getLastResponseStatusCode(),
441438
$this->client->getLastResponseContentType(),
442439
$this->client->getLastResponseBody()
@@ -445,37 +442,6 @@ public function request(Request $request): Response
445442
};
446443
}
447444

448-
private function createResponse(int $statusCode, string $contentType, string $body): Response
449-
{
450-
return new class ($statusCode, $contentType, $body) implements Response {
451-
private $statusCode;
452-
private $contentType;
453-
private $body;
454-
455-
public function __construct(int $statusCode, string $contentType, string $body)
456-
{
457-
$this->statusCode = $statusCode;
458-
$this->contentType = $contentType;
459-
$this->body = $body;
460-
}
461-
462-
public function getStatusCode(): int
463-
{
464-
return $this->statusCode;
465-
}
466-
467-
public function getContentType(): string
468-
{
469-
return $this->contentType;
470-
}
471-
472-
public function getContent(): string
473-
{
474-
return $this->body;
475-
}
476-
};
477-
}
478-
479445
private function createRequest(string $method, string $path, string $contentType, string $content = ''): Request
480446
{
481447
return new class ($method, $path, $contentType, $content) implements Request {

src/Redmine/Client/NativeCurlClient.php

Lines changed: 50 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,15 @@
55
namespace Redmine\Client;
66

77
use Redmine\Exception\ClientException;
8+
use Redmine\Http\HttpClient;
9+
use Redmine\Http\HttpFactory;
10+
use Redmine\Http\Request;
11+
use Redmine\Http\Response;
812

913
/**
1014
* Native cURL client.
1115
*/
12-
final class NativeCurlClient implements Client
16+
final class NativeCurlClient implements Client, HttpClient
1317
{
1418
use ClientApiTrait;
1519

@@ -55,6 +59,27 @@ public function __construct(
5559
}
5660
}
5761

62+
/**
63+
* Create and send a HTTP request and return the response
64+
*
65+
* @throws ClientException If anything goes wrong on creating or sending the request
66+
*/
67+
public function request(Request $request): Response
68+
{
69+
$this->runRequest(
70+
$request->getMethod(),
71+
$request->getPath(),
72+
$request->getContent(),
73+
$request->getContentType()
74+
);
75+
76+
return HttpFactory::makeResponse(
77+
$this->lastResponseStatusCode,
78+
$this->lastResponseContentType,
79+
$this->lastResponseBody
80+
);
81+
}
82+
5883
/**
5984
* Sets to an existing username so api calls can be
6085
* impersonated to this user.
@@ -77,31 +102,31 @@ public function stopImpersonateUser(): void
77102
*/
78103
public function requestGet(string $path): bool
79104
{
80-
return $this->request('get', $path);
105+
return $this->runRequest('GET', $path);
81106
}
82107

83108
/**
84109
* Create and send a POST request.
85110
*/
86111
public function requestPost(string $path, string $body): bool
87112
{
88-
return $this->request('post', $path, $body);
113+
return $this->runRequest('POST', $path, $body);
89114
}
90115

91116
/**
92117
* Create and send a PUT request.
93118
*/
94119
public function requestPut(string $path, string $body): bool
95120
{
96-
return $this->request('put', $path, $body);
121+
return $this->runRequest('PUT', $path, $body);
97122
}
98123

99124
/**
100125
* Create and send a DELETE request.
101126
*/
102127
public function requestDelete(string $path): bool
103128
{
104-
return $this->request('delete', $path);
129+
return $this->runRequest('DELETE', $path);
105130
}
106131

107132
/**
@@ -211,13 +236,13 @@ private function unsetHttpHeader(string $name): void
211236
/**
212237
* @throws ClientException If anything goes wrong on curl request
213238
*/
214-
private function request(string $method, string $path, string $body = ''): bool
239+
private function runRequest(string $method, string $path, string $body = '', string $contentType = ''): bool
215240
{
216241
$this->lastResponseStatusCode = 0;
217242
$this->lastResponseContentType = '';
218243
$this->lastResponseBody = '';
219244

220-
$curl = $this->createCurl($method, $path, $body);
245+
$curl = $this->createCurl($method, $path, $body, $contentType);
221246

222247
$response = curl_exec($curl);
223248

@@ -249,7 +274,7 @@ private function request(string $method, string $path, string $body = ''): bool
249274
*
250275
* @return \CurlHandle a cURL handle on success, <b>FALSE</b> on errors
251276
*/
252-
private function createCurl(string $method, string $path, string $body = '')
277+
private function createCurl(string $method, string $path, string $body = '', string $contentType = '')
253278
{
254279
// General cURL options
255280
$curlOptions = [
@@ -264,13 +289,13 @@ private function createCurl(string $method, string $path, string $body = '')
264289
$curlOptions[CURLOPT_URL] = $this->url . $path;
265290

266291
// Set the HTTP request headers
267-
$curlOptions[CURLOPT_HTTPHEADER] = $this->createHttpHeader($path);
292+
$curlOptions[CURLOPT_HTTPHEADER] = $this->createHttpHeader($path, $contentType);
268293

269294
unset($curlOptions[CURLOPT_CUSTOMREQUEST]);
270295
unset($curlOptions[CURLOPT_POST]);
271296
unset($curlOptions[CURLOPT_POSTFIELDS]);
272297
switch ($method) {
273-
case 'post':
298+
case 'POST':
274299
$curlOptions[CURLOPT_POST] = 1;
275300
if ($this->isUploadCall($path) && $this->isValidFilePath($body)) {
276301
@trigger_error('Uploading an attachment by filepath is deprecated, use file_get_contents() to upload the file content instead.', E_USER_DEPRECATED);
@@ -286,13 +311,13 @@ private function createCurl(string $method, string $path, string $body = '')
286311
$curlOptions[CURLOPT_POSTFIELDS] = $body;
287312
}
288313
break;
289-
case 'put':
314+
case 'PUT':
290315
$curlOptions[CURLOPT_CUSTOMREQUEST] = 'PUT';
291316
if ($body !== '') {
292317
$curlOptions[CURLOPT_POSTFIELDS] = $body;
293318
}
294319
break;
295-
case 'delete':
320+
case 'DELETE':
296321
$curlOptions[CURLOPT_CUSTOMREQUEST] = 'DELETE';
297322
break;
298323
default: // GET
@@ -314,7 +339,7 @@ private function createCurl(string $method, string $path, string $body = '')
314339
return $curl;
315340
}
316341

317-
private function createHttpHeader(string $path): array
342+
private function createHttpHeader(string $path, string $contentType = ''): array
318343
{
319344
// Additional request headers
320345
$httpHeaders = [
@@ -352,14 +377,18 @@ private function createHttpHeader(string $path): array
352377
// Now set or reset mandatory headers
353378

354379
// Content type headers
355-
$tmp = parse_url($this->url . $path);
356-
357-
if ($this->isUploadCall($path)) {
358-
$httpHeaders[] = 'Content-Type: application/octet-stream';
359-
} elseif ('json' === substr($tmp['path'], -4)) {
360-
$httpHeaders[] = 'Content-Type: application/json';
361-
} elseif ('xml' === substr($tmp['path'], -3)) {
362-
$httpHeaders[] = 'Content-Type: text/xml';
380+
if ($contentType !== '') {
381+
$httpHeaders[] = 'Content-Type: ' . $contentType;
382+
} else {
383+
$tmp = parse_url($this->url . $path);
384+
385+
if ($this->isUploadCall($path)) {
386+
$httpHeaders[] = 'Content-Type: application/octet-stream';
387+
} elseif ('json' === substr($tmp['path'], -4)) {
388+
$httpHeaders[] = 'Content-Type: application/json';
389+
} elseif ('xml' === substr($tmp['path'], -3)) {
390+
$httpHeaders[] = 'Content-Type: text/xml';
391+
}
363392
}
364393

365394
return $httpHeaders;

0 commit comments

Comments
 (0)