- First working version of ulmus-api package; at working state only
This commit is contained in:
1 parent
0f9495e07a
commit
7e69a09e7f
27 files changed
+1406
-101
No files matched your search
+126
-39
@@ -2,78 +2,165 @@
|
||||
|
||||
namespace Ulmus\Api\Transport;
|
||||
|
||||
use Ulmus\Api\Common\MethodEnum;
|
||||
use Ulmus\Api\Common\{ ContentTypeEnum, MethodEnum, HttpHeaderEnum };
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Ulmus\Api\Response\JsonResponse;
|
||||
use Ulmus\Api\Response\Response;
|
||||
use Ulmus\Api\Request\Stream;
|
||||
use Ulmus\Attribute\Obj\Method;
|
||||
|
||||
abstract class CurlTransport {
|
||||
|
||||
public $timeout = 1;
|
||||
|
||||
public function post(string $url, array $data) : mixed
|
||||
{
|
||||
return $this->request(MethodEnum::Post, $url, $data);
|
||||
public int $timeout = 5;
|
||||
|
||||
public int $maximumRedirections = 10;
|
||||
|
||||
public function __construct(
|
||||
public array $headers = [],
|
||||
public array $curlOptions = [],
|
||||
public null|CurlAuthorization $authorization = null,
|
||||
public ContentTypeEnum $contentType = ContentTypeEnum::Json,
|
||||
# Matching Guzzle's great user-agent syntax
|
||||
public string $userAgent = "ulmus-api/1.0 curl/{curl} php/{php}",
|
||||
) {
|
||||
$this->userAgent = str_replace([ '{curl}', '{php}', ], [ curl_version()['version'] ?? "???", phpversion() ], $this->userAgent);
|
||||
}
|
||||
|
||||
public function get(string $url, array $data) : mixed
|
||||
public function post(string $url, mixed $data, array $headers = [], array $curlOptions = []) : mixed
|
||||
{
|
||||
return $this->request(MethodEnum::Get, $url, $data);
|
||||
return $this->request(MethodEnum::Post, $url, $data, $headers, $curlOptions);
|
||||
}
|
||||
|
||||
public function delete(string $url, array $data) : mixed
|
||||
public function get(string $url, mixed $data, array $headers = [], array $curlOptions = []) : mixed
|
||||
{
|
||||
return $this->request(MethodEnum::Delete, $url, $data);
|
||||
return $this->request(MethodEnum::Get, $url, $data, $headers, $curlOptions);
|
||||
}
|
||||
|
||||
public function patch(string $url, array $data) : mixed
|
||||
public function delete(string $url, mixed $data, array $headers = [], array $curlOptions = []) : mixed
|
||||
{
|
||||
return $this->request(MethodEnum::Patch, $url, $data);
|
||||
return $this->request(MethodEnum::Delete, $url, $data, $headers, $curlOptions);
|
||||
}
|
||||
|
||||
public function put(string $url, array $data) : mixed
|
||||
public function patch(string $url, mixed $data, array $headers = [], array $curlOptions = []) : mixed
|
||||
{
|
||||
return $this->request(MethodEnum::Put, $url, $data);
|
||||
return $this->request(MethodEnum::Patch, $url, $data, $headers, $curlOptions);
|
||||
}
|
||||
|
||||
public function request(MethodEnum $method, string $url, array $data) : mixed
|
||||
public function put(string $url, mixed $data, array $headers = [], array $curlOptions = []) : mixed
|
||||
{
|
||||
$ch = curl_init();
|
||||
return $this->request(MethodEnum::Put, $url, $data, $headers, $curlOptions);
|
||||
}
|
||||
|
||||
$options = [
|
||||
public function fromRequest(ServerRequestInterface $request) : ResponseInterface
|
||||
{
|
||||
return $this->request($request->getMethod(), $request->getUri(), $request->getBody()->getContents(), $request->getHeaders());
|
||||
}
|
||||
|
||||
public function request(MethodEnum $method, string $url, mixed $data = null, array $headers = [], array $options = []) : ResponseInterface
|
||||
{
|
||||
$response = new Response();
|
||||
|
||||
$headers = HttpHeaderEnum::normalizeHeaderArray($headers + $this->headers);
|
||||
|
||||
$options += $this->curlOptions;
|
||||
|
||||
$this->applyMethod($method, $data, $headers, $options);
|
||||
|
||||
$headers += $this->authorization->headers;
|
||||
|
||||
$options += $this->authorization->options;
|
||||
|
||||
$options += [
|
||||
CURLOPT_URL => $url,
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
CURLOPT_HTTPHEADER => $this->headers,
|
||||
CURLOPT_MAXREDIRS => 10,
|
||||
CURLOPT_TIMEOUT_MS => $this->timeout * 200,
|
||||
CURLOPT_HTTPHEADER => HttpHeaderEnum::compileHeaders($headers),
|
||||
CURLOPT_MAXREDIRS => $this->maximumRedirections,
|
||||
CURLOPT_TIMEOUT_MS => $this->timeout * 1000,
|
||||
CURLOPT_SSL_VERIFYPEER => false,
|
||||
CURLOPT_SSL_VERIFYHOST => false,
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
CURLOPT_FOLLOWLOCATION => true,
|
||||
CURLOPT_HEADERFUNCTION => function($curl, $headerLine) use (& $response) {
|
||||
if ( strpos($headerLine, ':') ) {
|
||||
list($key, $value) = array_map('trim', explode(':', $headerLine));
|
||||
$response = $response->withHeader($key, $value);
|
||||
}
|
||||
elseif ( strtoupper(substr($headerLine, 0, 4)) === 'HTTP' ) {
|
||||
list(,$code, $status) = explode(' ', trim($headerLine), 3);
|
||||
|
||||
$response = $response->withStatus($code, $status);
|
||||
}
|
||||
|
||||
return strlen($headerLine);
|
||||
}
|
||||
];
|
||||
|
||||
switch ($method) {
|
||||
case MethodEnum::Put:
|
||||
case MethodEnum::Delete:
|
||||
$options[CURLOPT_CUSTOMREQUEST] = $method->value;
|
||||
break;
|
||||
|
||||
case MethodEnum::Post:
|
||||
$options[CURLOPT_POST] = true;
|
||||
$options[CURLOPT_POSTFIELDS] = http_build_query($data, '', '&');
|
||||
break;
|
||||
|
||||
default:
|
||||
case MethodEnum::Get:
|
||||
}
|
||||
|
||||
$ch = curl_init();
|
||||
|
||||
foreach($options as $opt => $value) {
|
||||
curl_setopt($ch, $opt, $value);
|
||||
}
|
||||
|
||||
if ( ( false === curl_exec($ch) ) && $this->throwErrors ) {
|
||||
if ( false === ( $result = curl_exec($ch) ) ) {
|
||||
$errno = curl_errno($ch);
|
||||
$errors = array_filter([ curl_error($ch) , CurlErrors::CURL_CODES[$errno] ?? null ]);
|
||||
|
||||
throw new CurlException(implode(PHP_EOL, $errors), $errno);
|
||||
throw new \Exception(implode(PHP_EOL, $errors), $errno);
|
||||
}
|
||||
|
||||
curl_close($ch);
|
||||
$response = $response->withBody( Stream::fromMemory($result) );
|
||||
|
||||
if ( $response->hasHeader('Content-Type') && false !== strpos($response->getHeader('Content-Type')[0], 'json') ) {
|
||||
$response = JsonResponse::fromResponse($response);
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
protected function applyMethod(MethodEnum $method, mixed &$data, array &$headers, array &$options) : void
|
||||
{
|
||||
switch ($method) {
|
||||
case MethodEnum::Patch:
|
||||
case MethodEnum::Put:
|
||||
case MethodEnum::Delete:
|
||||
case MethodEnum::Post:
|
||||
if ($method === MethodEnum::Post) {
|
||||
$options[CURLOPT_POST] = true;
|
||||
}
|
||||
else {
|
||||
$options[CURLOPT_CUSTOMREQUEST] = $method->value;
|
||||
}
|
||||
|
||||
$this->arrayToPostFields($data, $headers, $options);
|
||||
break;
|
||||
|
||||
case MethodEnum::Get:
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
protected function arrayToPostFields(mixed &$data, array &$headers, array &$options) : void
|
||||
{
|
||||
$headers["Content-Type"] = $this->contentType->value;
|
||||
|
||||
switch($this->contentType) {
|
||||
case ContentTypeEnum::Json:
|
||||
$options[CURLOPT_POSTFIELDS] = json_encode($data, JsonResponse::DEFAULT_JSON_ENCODING_FLAGS);
|
||||
$headers['Accept'] ??= $this->contentType->value;
|
||||
break;
|
||||
|
||||
case ContentTypeEnum::UrlEncoded:
|
||||
$options[CURLOPT_POSTFIELDS] = http_build_query($data, '', '&');
|
||||
break;
|
||||
|
||||
case ContentTypeEnum::Multipart:
|
||||
$options[CURLOPT_POSTFIELDS] = $data;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected function unindexQueryStringArrays(string $query) : string
|
||||
{
|
||||
return preg_replace("/\[[0-9]+\]/simU", "[]", $query);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user