Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Let Clients implements HttpClient #370

Merged
merged 11 commits into from
Feb 1, 2024
44 changes: 5 additions & 39 deletions src/Redmine/Api/AbstractApi.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use Redmine\Exception;
use Redmine\Exception\SerializerException;
use Redmine\Http\HttpClient;
use Redmine\Http\HttpFactory;
use Redmine\Http\Request;
use Redmine\Http\Response;
use Redmine\Serializer\JsonSerializer;
Expand Down Expand Up @@ -73,7 +74,7 @@ final protected function getHttpClient(): HttpClient

final protected function getLastResponse(): Response
{
return $this->lastResponse !== null ? $this->lastResponse : $this->createResponse(0, '', '');
return $this->lastResponse !== null ? $this->lastResponse : HttpFactory::makeResponse(0, '', '');
}

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

private function handleClient(Client $client): HttpClient
{
$responseFactory = Closure::fromCallable([$this, 'createResponse']);

return new class ($client, $responseFactory) implements HttpClient {
return new class ($client) implements HttpClient {
private $client;
private $responseFactory;

public function __construct(Client $client, Closure $responseFactory)
public function __construct(Client $client)
{
$this->client = $client;
$this->responseFactory = $responseFactory;
}

public function request(Request $request): Response
Expand All @@ -436,7 +433,7 @@ public function request(Request $request): Response
$this->client->requestGet($request->getPath());
}

return ($this->responseFactory)(
return HttpFactory::makeResponse(
$this->client->getLastResponseStatusCode(),
$this->client->getLastResponseContentType(),
$this->client->getLastResponseBody()
Expand All @@ -445,37 +442,6 @@ public function request(Request $request): Response
};
}

private function createResponse(int $statusCode, string $contentType, string $body): Response
{
return new class ($statusCode, $contentType, $body) implements Response {
private $statusCode;
private $contentType;
private $body;

public function __construct(int $statusCode, string $contentType, string $body)
{
$this->statusCode = $statusCode;
$this->contentType = $contentType;
$this->body = $body;
}

public function getStatusCode(): int
{
return $this->statusCode;
}

public function getContentType(): string
{
return $this->contentType;
}

public function getContent(): string
{
return $this->body;
}
};
}

private function createRequest(string $method, string $path, string $contentType, string $content = ''): Request
{
return new class ($method, $path, $contentType, $content) implements Request {
Expand Down
71 changes: 50 additions & 21 deletions src/Redmine/Client/NativeCurlClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,15 @@
namespace Redmine\Client;

use Redmine\Exception\ClientException;
use Redmine\Http\HttpClient;
use Redmine\Http\HttpFactory;
use Redmine\Http\Request;
use Redmine\Http\Response;

/**
* Native cURL client.
*/
final class NativeCurlClient implements Client
final class NativeCurlClient implements Client, HttpClient
{
use ClientApiTrait;

Expand Down Expand Up @@ -55,6 +59,27 @@
}
}

/**
* Create and send a HTTP request and return the response
*
* @throws ClientException If anything goes wrong on creating or sending the request
*/
public function request(Request $request): Response
{
$this->runRequest(
$request->getMethod(),
$request->getPath(),
$request->getContent(),
$request->getContentType()
);

return HttpFactory::makeResponse(
$this->lastResponseStatusCode,
$this->lastResponseContentType,
$this->lastResponseBody
);
}

/**
* Sets to an existing username so api calls can be
* impersonated to this user.
Expand All @@ -77,31 +102,31 @@
*/
public function requestGet(string $path): bool
{
return $this->request('get', $path);
return $this->runRequest('GET', $path);
}

/**
* Create and send a POST request.
*/
public function requestPost(string $path, string $body): bool
{
return $this->request('post', $path, $body);
return $this->runRequest('POST', $path, $body);
}

/**
* Create and send a PUT request.
*/
public function requestPut(string $path, string $body): bool
{
return $this->request('put', $path, $body);
return $this->runRequest('PUT', $path, $body);
}

/**
* Create and send a DELETE request.
*/
public function requestDelete(string $path): bool
{
return $this->request('delete', $path);
return $this->runRequest('DELETE', $path);
}

/**
Expand Down Expand Up @@ -211,13 +236,13 @@
/**
* @throws ClientException If anything goes wrong on curl request
*/
private function request(string $method, string $path, string $body = ''): bool
private function runRequest(string $method, string $path, string $body = '', string $contentType = ''): bool
{
$this->lastResponseStatusCode = 0;
$this->lastResponseContentType = '';
$this->lastResponseBody = '';

$curl = $this->createCurl($method, $path, $body);
$curl = $this->createCurl($method, $path, $body, $contentType);

$response = curl_exec($curl);

Expand Down Expand Up @@ -249,7 +274,7 @@
*
* @return \CurlHandle a cURL handle on success, <b>FALSE</b> on errors
*/
private function createCurl(string $method, string $path, string $body = '')
private function createCurl(string $method, string $path, string $body = '', string $contentType = '')
{
// General cURL options
$curlOptions = [
Expand All @@ -264,13 +289,13 @@
$curlOptions[CURLOPT_URL] = $this->url . $path;

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

unset($curlOptions[CURLOPT_CUSTOMREQUEST]);
unset($curlOptions[CURLOPT_POST]);
unset($curlOptions[CURLOPT_POSTFIELDS]);
switch ($method) {
case 'post':
case 'POST':
$curlOptions[CURLOPT_POST] = 1;
if ($this->isUploadCall($path) && $this->isValidFilePath($body)) {
@trigger_error('Uploading an attachment by filepath is deprecated, use file_get_contents() to upload the file content instead.', E_USER_DEPRECATED);
Expand All @@ -286,13 +311,13 @@
$curlOptions[CURLOPT_POSTFIELDS] = $body;
}
break;
case 'put':
case 'PUT':
$curlOptions[CURLOPT_CUSTOMREQUEST] = 'PUT';
if ($body !== '') {
$curlOptions[CURLOPT_POSTFIELDS] = $body;
}
break;
case 'delete':
case 'DELETE':
$curlOptions[CURLOPT_CUSTOMREQUEST] = 'DELETE';
break;
default: // GET
Expand All @@ -314,7 +339,7 @@
return $curl;
}

private function createHttpHeader(string $path): array
private function createHttpHeader(string $path, string $contentType = ''): array
{
// Additional request headers
$httpHeaders = [
Expand Down Expand Up @@ -352,14 +377,18 @@
// Now set or reset mandatory headers

// Content type headers
$tmp = parse_url($this->url . $path);

if ($this->isUploadCall($path)) {
$httpHeaders[] = 'Content-Type: application/octet-stream';
} elseif ('json' === substr($tmp['path'], -4)) {
$httpHeaders[] = 'Content-Type: application/json';
} elseif ('xml' === substr($tmp['path'], -3)) {
$httpHeaders[] = 'Content-Type: text/xml';
if ($contentType !== '') {
$httpHeaders[] = 'Content-Type: ' . $contentType;
} else {
$tmp = parse_url($this->url . $path);

if ($this->isUploadCall($path)) {
$httpHeaders[] = 'Content-Type: application/octet-stream';

Check warning on line 386 in src/Redmine/Client/NativeCurlClient.php

View check run for this annotation

Codecov / codecov/patch

src/Redmine/Client/NativeCurlClient.php#L386

Added line #L386 was not covered by tests
} elseif ('json' === substr($tmp['path'], -4)) {
$httpHeaders[] = 'Content-Type: application/json';

Check warning on line 388 in src/Redmine/Client/NativeCurlClient.php

View check run for this annotation

Codecov / codecov/patch

src/Redmine/Client/NativeCurlClient.php#L388

Added line #L388 was not covered by tests
} elseif ('xml' === substr($tmp['path'], -3)) {
$httpHeaders[] = 'Content-Type: text/xml';

Check warning on line 390 in src/Redmine/Client/NativeCurlClient.php

View check run for this annotation

Codecov / codecov/patch

src/Redmine/Client/NativeCurlClient.php#L390

Added line #L390 was not covered by tests
}
}

return $httpHeaders;
Expand Down
Loading
Loading