Refactorings

- important curl and wget improvements
- initial test coverage
- setters and getters in Request classes
- namespace fixes
- some additions in README
- docblocks and code-style
This commit is contained in:
2023-09-10 09:03:54 +08:00
parent af9c360684
commit 1345b7eddb
26 changed files with 2901 additions and 300 deletions

View File

@@ -2,13 +2,14 @@
declare(strict_types=1);
namespace PmConverter\Exporters\Abstract;
namespace PmConverter\Converters\Abstract;
use Exception;
use PmConverter\Environment;
use PmConverter\Exporters\{
use PmConverter\Converters\{
ConverterContract,
RequestContract};
use PmConverter\Environment;
use PmConverter\Exceptions\InvalidHttpVersionException;
use PmConverter\FileSystem;
/**
@@ -129,14 +130,16 @@ abstract class AbstractConverter implements ConverterContract
*
* @param object $item
* @return RequestContract
* @throws InvalidHttpVersionException
*/
protected function initRequest(object $item): RequestContract
{
$request_class = static::REQUEST_CLASS;
/** @var RequestContract $result */
$result = new $request_class($this->vars);
$result = new $request_class();
$result->setName($item->name);
$result->setHttpVersion(1.1); //TODO http version?
$result->setDescription($item->request?->description ?? null);
$result->setVerb($item->request->method);
$result->setUrl($item->request->url->raw);

View File

@@ -0,0 +1,295 @@
<?php
declare(strict_types=1);
namespace PmConverter\Converters\Abstract;
use PmConverter\Converters\RequestContract;
use PmConverter\Exceptions\{
EmptyHttpVerbException,
InvalidHttpVersionException};
use PmConverter\HttpVersions;
use Stringable;
/**
* Class to determine file content with any request format
*/
abstract class AbstractRequest implements Stringable, RequestContract
{
/**
* @var string HTTP verb (GET, POST, etc.)
*/
protected string $verb;
/**
* @var string URL where to send a request
*/
protected string $url;
/**
* @var float HTTP protocol version
*/
protected float $httpVersion = 1.1;
/**
* @var string Request name
*/
protected string $name;
/**
* @var string|null Request description
*/
protected ?string $description = null;
/**
* @var array Request headers
*/
protected array $headers = [];
/**
* @var mixed Request body
*/
protected mixed $body = null;
/**
* @var string Request body type
*/
protected string $bodymode = 'raw';
/**
* @inheritDoc
*/
public function setHttpVersion(float $version): static
{
if (!in_array($version, HttpVersions::values())) {
throw new InvalidHttpVersionException(
'Only these HTTP versions are supported: ' . implode(', ', HttpVersions::values())
);
}
$this->httpVersion = $version;
return $this;
}
/**
* @inheritDoc
*/
public function getHttpVersion(): float
{
return $this->httpVersion;
}
/**
* @inheritDoc
*/
public function setName(string $name): static
{
$this->name = $name;
return $this;
}
/**
* @inheritDoc
*/
public function getName(): string
{
return str_replace(DIRECTORY_SEPARATOR, '_', $this->name);
}
/**
* @inheritDoc
*/
public function setDescription(?string $description): static
{
$this->description = $description;
return $this;
}
/**
* @inheritDoc
*/
public function getDescription(): ?string
{
return $this->description;
}
/**
* @inheritDoc
*/
public function setVerb(string $verb): static
{
$this->verb = $verb;
return $this;
}
/**
* @inheritDoc
*/
public function getVerb(): string
{
empty($this->verb) && throw new EmptyHttpVerbException('Request HTTP verb must be defined before conversion');
return $this->verb;
}
/**
* @inheritDoc
*/
public function setUrl(string $url): static
{
$this->url = $url;
return $this;
}
/**
* @inheritDoc
*/
public function getUrl(): string
{
return $this->url ?: '<empty url>';
}
/**
* @inheritDoc
*/
public function setHeaders(?array $headers): static
{
foreach ($headers as $header) {
$this->setHeader($header->key, $header->value, $header?->disabled ?? false);
}
return $this;
}
/**
* @inheritDoc
*/
public function setHeader(string $name, mixed $value, bool $disabled = false): static
{
$this->headers[$name] = [
'value' => $value,
'disabled' => $disabled,
];
return $this;
}
/**
* @inheritDoc
*/
public function getHeaders(): array
{
return $this->headers;
}
/**
* @inheritDoc
*/
public function setAuth(?object $auth): static
{
if (!empty($auth)) {
switch ($auth->type) {
case 'bearer':
$this->setHeader('Authorization', 'Bearer ' . $auth->{$auth->type}[0]->value);
break;
default:
break;
}
}
return $this;
}
/**
* @inheritDoc
*/
public function setBodymode(string $bodymode): static
{
$this->bodymode = $bodymode;
return $this;
}
/**
* @inheritDoc
*/
public function getBodymode(): string
{
return $this->bodymode;
}
/**
* @inheritDoc
*/
public function setBody(object $body): static
{
$this->setBodymode($body->mode);
if ($body->mode === 'formdata') {
$this->setHeader('Content-Type', 'multipart/form-data')
->setFormdataBody($body);
} elseif (!empty($body->options) && $body->options->{$this->bodymode}->language === 'json') {
$this->setHeader('Content-Type', 'application/json')
->setJsonBody($body);
}
return $this;
}
/**
* Sets body content from multipart/formdata
*
* @param object $body
* @return $this
*/
protected function setFormdataBody(object $body): static
{
foreach ($body->formdata as $field) {
$this->body[$field->key] = [
'value' => $field->type === 'file' ? $field->src : $field->value,
'type' => $field->type,
];
}
return $this;
}
/**
* Sets body content from application/json
*
* @param object $body
* @return $this
*/
protected function setJsonBody(object $body): static
{
$this->body = $body->{$this->getBodymode()};
return $this;
}
/**
* @inheritDoc
*/
public function getBody(): mixed
{
return $this->body;
}
/**
* Returns array of description lines
*
* @return array
*/
abstract protected function prepareDescription(): array;
/**
* Returns array of headers
*
* @return array
*/
abstract protected function prepareHeaders(): array;
/**
* Returns array of request body lines
*
* @return array
*/
abstract protected function prepareBody(): array;
/**
* Converts request object to string to be written in result file
*
* @return string
*/
abstract public function __toString(): string;
}

View File

@@ -2,12 +2,13 @@
declare(strict_types=1);
namespace PmConverter\Exporters;
namespace PmConverter\Converters;
use PmConverter\Exporters\Curl\CurlConverter;
use PmConverter\Exporters\Http\HttpConverter;
use PmConverter\Exporters\Wget\WgetConverter;
use PmConverter\Converters\{
Curl\CurlConverter,
Http\HttpConverter,
Wget\WgetConverter};
enum ConvertFormat: string
{

View File

@@ -2,7 +2,7 @@
declare(strict_types=1);
namespace PmConverter\Exporters;
namespace PmConverter\Converters;
interface ConverterContract
{

View File

@@ -2,9 +2,9 @@
declare(strict_types=1);
namespace PmConverter\Exporters\Curl;
namespace PmConverter\Converters\Curl;
use PmConverter\Exporters\{
use PmConverter\Converters\{
Abstract\AbstractConverter,
ConverterContract};

View File

@@ -2,9 +2,9 @@
declare(strict_types=1);
namespace PmConverter\Exporters\Curl;
namespace PmConverter\Converters\Curl;
use PmConverter\Exporters\Abstract\AbstractRequest;
use PmConverter\Converters\Abstract\AbstractRequest;
/**
* Class to determine file content with curl request format
@@ -31,7 +31,7 @@ class CurlRequest extends AbstractRequest
if ($header['disabled']) {
continue;
}
$output[] = sprintf("\t--header '%s=%s' \ ", $header_key, $header['value']);
$output[] = sprintf("\t--header '%s: %s' \ ", $header_key, $header['value']);
}
return $output;
}
@@ -44,12 +44,12 @@ class CurlRequest extends AbstractRequest
$output = [];
switch ($this->bodymode) {
case 'formdata':
foreach ($this->body as $data) {
foreach ($this->body as $key => $data) {
$output[] = sprintf(
"%s\t--form '%s=%s' \ ",
isset($data->disabled) ? '# ' : '',
$data->key,
$data->type === 'file' ? "@$data->src" : $data->value
isset($data['disabled']) ? '# ' : '',
$key,
$data['type'] === 'file' ? "@" . $data['value'] : $data['value']
);
}
break;

View File

@@ -2,9 +2,9 @@
declare(strict_types=1);
namespace PmConverter\Exporters\Http;
namespace PmConverter\Converters\Http;
use PmConverter\Exporters\{
use PmConverter\Converters\{
Abstract\AbstractConverter,
ConverterContract};

View File

@@ -2,9 +2,11 @@
declare(strict_types=1);
namespace PmConverter\Exporters\Http;
namespace PmConverter\Converters\Http;
use PmConverter\Exporters\Abstract\AbstractRequest;
use PmConverter\Converters\Abstract\AbstractRequest;
use PmConverter\Exceptions\{
EmptyHttpVerbException};
/**
* Class to determine file content with http request format
@@ -23,12 +25,13 @@ class HttpRequest extends AbstractRequest
/**
* @inheritDoc
* @throws EmptyHttpVerbException
*/
protected function prepareHeaders(): array
{
$output[] = "$this->verb $this->url $this->http";
foreach ($this->headers as $header_key => $header) {
$output[] = sprintf('%s%s: %s', $header['disabled'] ? '# ' : '', $header_key, $header['value']);
$output[] = sprintf('%s %s HTTP/%s', $this->getVerb(), $this->getUrl(), $this->getHttpVersion());
foreach ($this->headers as $name => $data) {
$output[] = sprintf('%s%s: %s', $data['disabled'] ? '# ' : '', $name, $data['value']);
}
return $output;
}
@@ -38,15 +41,15 @@ class HttpRequest extends AbstractRequest
*/
protected function prepareBody(): array
{
switch ($this->bodymode) {
switch ($this->getBodymode()) {
case 'formdata':
$output = [''];
foreach ($this->body as $data) {
foreach ($this->body as $key => $data) {
$output[] = sprintf(
'%s%s=%s',
empty($data->disabled) ? '' : '# ',
$data->key,
$data->type === 'file' ? $data->src : $data->value
empty($data['disabled']) ? '' : '# ',
$key,
$data['type'] === 'file' ? '@' . $data['value'] : $data['value']
);
}
return $output;
@@ -57,6 +60,7 @@ class HttpRequest extends AbstractRequest
/**
* @inheritDoc
* @throws EmptyHttpVerbException
*/
public function __toString(): string
{

View File

@@ -0,0 +1,153 @@
<?php
declare(strict_types=1);
namespace PmConverter\Converters;
use PmConverter\Converters\Http\HttpRequest;
use PmConverter\Exceptions\{
EmptyHttpVerbException,
InvalidHttpVersionException};
interface RequestContract
{
/**
* Sets HTTP protocol version
*
* @param float $version
* @return $this
* @throws InvalidHttpVersionException
*/
public function setHttpVersion(float $version): static;
/**
* Returns HTTP protocol version
*
* @return float
*/
public function getHttpVersion(): float;
/**
* Sets name from collection item to request object
*
* @param string $name
* @return HttpRequest
*/
public function setName(string $name): static;
/**
* Returns name of request
*
* @return string
*/
public function getName(): string;
/**
* Sets description from collection item to request object
*
* @param string|null $description
* @return HttpRequest
*/
public function setDescription(?string $description): static;
/**
* Returns description request
*
* @return string|null
*/
public function getDescription(): ?string;
/**
* Sets HTTP verb from collection item to request object
*
* @param string $verb
* @return HttpRequest
*/
public function setVerb(string $verb): static;
/**
* Returns HTTP verb of request
*
* @return string
* @throws EmptyHttpVerbException
*/
public function getVerb(): string;
/**
* Sets URL from collection item to request object
*
* @param string $url
* @return HttpRequest
*/
public function setUrl(string $url): static;
/**
* Returns URL of request
*
* @return string
*/
public function getUrl(): string;
/**
* Sets headers from collection item to request object
*
* @param object[]|null $headers
* @return $this
*/
public function setHeaders(?array $headers): static;
/**
* Sets one header to request object
*
* @param string $name Header's name
* @param mixed $value Header's value
* @param bool $disabled Pass true to skip (or comment out) this header
* @return $this
*/
public function setHeader(string $name, mixed $value, bool $disabled = false): static;
/**
* Returns array of prepared headers
*
* @return array
*/
public function getHeaders(): array;
/**
* Sets authorization headers
*
* @param object|null $auth
* @return $this
*/
public function setAuth(object $auth): static;
/**
* Sets body mode from collection item to request object
*
* @param string $bodymode
* @return HttpRequest
*/
public function setBodymode(string $bodymode): static;
/**
* Returns body mode of request
*
* @return HttpRequest
*/
public function getBodymode(): string;
/**
* Sets body from collection item to request object
*
* @param object $body
* @return $this
*/
public function setBody(object $body): static;
/**
* Returns body content
*
* @return mixed
*/
public function getBody(): mixed;
}

View File

@@ -2,9 +2,9 @@
declare(strict_types=1);
namespace PmConverter\Exporters\Wget;
namespace PmConverter\Converters\Wget;
use PmConverter\Exporters\{
use PmConverter\Converters\{
Abstract\AbstractConverter,
ConverterContract};

View File

@@ -2,9 +2,10 @@
declare(strict_types=1);
namespace PmConverter\Exporters\Wget;
namespace PmConverter\Converters\Wget;
use PmConverter\Exporters\Abstract\AbstractRequest;
use PmConverter\Converters\Abstract\AbstractRequest;
use PmConverter\Exceptions\EmptyHttpVerbException;
/**
* Class to determine file content with wget request format
@@ -31,7 +32,7 @@ class WgetRequest extends AbstractRequest
if ($header['disabled']) {
continue;
}
$output[] = sprintf("\t--header '%s=%s' \ ", $header_key, $header['value']);
$output[] = sprintf("\t--header '%s: %s' \ ", $header_key, $header['value']);
}
return $output;
}
@@ -43,22 +44,22 @@ class WgetRequest extends AbstractRequest
{
switch ($this->bodymode) {
case 'formdata':
$params = [];
foreach ($this->body as $data) {
if ($data->type === 'file') {
$output = [];
foreach ($this->body as $key => $data) {
if ($data['type'] === 'file') {
continue;
}
$params[$data->key] = $data->value;
$output[$key] = $data['value'];
}
$output[] = http_build_query($params);
return $output;
default:
return ["\t'$this->body' \ "];
return [$this->body];
}
}
/**
* @inheritDoc
* @throws EmptyHttpVerbException
*/
public function __toString(): string
{
@@ -68,14 +69,26 @@ class WgetRequest extends AbstractRequest
[
'wget \ ',
"\t--no-check-certificate \ ",
"\t--quiet \ ",
"\t--timeout=0 \ ",
"\t--timeout 0 \ ",
"\t--method $this->verb \ ",
],
$this->prepareHeaders(),
$this->prepareBody()
);
$output[] = "\t'$this->url'";
if ($this->getBodymode() === 'formdata') {
if ($this->getBody()) {
if ($this->getVerb() === 'GET') {
$output[] = sprintf("\t%s?%s", $this->getUrl(), http_build_query($this->prepareBody()));
} else {
$output[] = sprintf("\t--body-data '%s' \ ", http_build_query($this->prepareBody()));
$output[] = sprintf("\t%s", $this->getUrl());
}
}
} else {
if ($this->getVerb() !== 'GET') {
$output[] = sprintf("\t--body-data '%s' \ ", implode("\n", $this->prepareBody()));
$output[] = sprintf("\t%s", $this->getUrl());
}
}
return implode(PHP_EOL, array_merge($output, ['']));
}
}

View File

@@ -0,0 +1,11 @@
<?php
declare(strict_types=1);
namespace PmConverter\Exceptions;
use Exception;
class EmptyHttpVerbException extends Exception
{
}

View File

@@ -0,0 +1,11 @@
<?php
declare(strict_types=1);
namespace PmConverter\Exceptions;
use Exception;
class EmptyURLException extends Exception
{
}

View File

@@ -0,0 +1,11 @@
<?php
declare(strict_types=1);
namespace PmConverter\Exceptions;
use Exception;
class InvalidHttpVersionException extends Exception
{
}

View File

@@ -1,222 +0,0 @@
<?php
declare(strict_types=1);
namespace PmConverter\Exporters\Abstract;
use PmConverter\Exporters\Http\HttpRequest;
use PmConverter\Exporters\RequestContract;
/**
* Class to determine file content with any request format
*/
abstract class AbstractRequest implements RequestContract
{
/**
* @var string
*/
protected string $http = 'HTTP/1.1'; //TODO proto
/**
* @var string
*/
protected string $name;
/**
* @var string|null
*/
protected ?string $description = null;
/**
* @var array
*/
protected array $headers = [];
/**
* @var mixed
*/
protected mixed $body = null;
/**
* @var string
*/
protected string $bodymode = 'raw';
/**
* @var string
*/
protected string $verb;
/**
* @var string
*/
protected string $url;
/**
* Sets name from collection item to request object
*
* @param string $name
* @return HttpRequest
*/
public function setName(string $name): static
{
$this->name = $name;
return $this;
}
/**
* Returns name of request
*
* @return string
*/
public function getName(): string
{
return str_replace(DIRECTORY_SEPARATOR, '_', $this->name);
}
/**
* Sets description from collection item to request object
*
* @param string|null $description
* @return HttpRequest
*/
public function setDescription(?string $description): static
{
$this->description = $description;
return $this;
}
/**
* Sets HTTP verb from collection item to request object
*
* @param string $verb
* @return HttpRequest
*/
public function setVerb(string $verb): static
{
$this->verb = $verb;
return $this;
}
/**
* Sets URL from collection item to request object
*
* @param string $url
* @return HttpRequest
*/
public function setUrl(string $url): static
{
$this->url = $url;
return $this;
}
/**
* Sets headers from collection item to request object
*
* @param object[]|null $headers
* @return $this
*/
public function setHeaders(?array $headers): static
{
foreach ($headers as $header) {
$this->headers[$header->key] = [
'value' => $header->value,
'disabled' => $header?->disabled ?? false,
];
}
return $this;
}
/**
* Sets authorization headers
*
* @param object|null $auth
* @return $this
*/
public function setAuth(?object $auth): static
{
if (!empty($auth)) {
switch ($auth->type) {
case 'bearer':
$this->headers['Authorization'] = [
'value' => 'Bearer ' . $auth->{$auth->type}[0]->value,
'disabled' => false,
];
break;
default:
break;
}
}
return $this;
}
/**
* Sets body mode from collection item to request object
*
* @param string $bodymode
* @return HttpRequest
*/
public function setBodymode(string $bodymode): static
{
$this->bodymode = $bodymode;
return $this;
}
/**
* Sets body from collection item to request object
*
* @param object $body
* @return $this
*/
public function setBody(object $body): static
{
$this->setBodymode($body->mode);
if (!empty($body->options) && $body->options->{$this->bodymode}->language === 'json') {
empty($this->headers['Content-Type']) && $this->setHeaders([
(object)[
'key' => 'Content-Type',
'value' => 'application/json',
'disabled' => false,
],
]);
}
$body->mode === 'formdata' && $this->setHeaders([
(object)[
'key' => 'Content-Type',
'value' => 'multipart/form-data',
'disabled' => false,
],
]);
$this->body = $body->{$body->mode};
return $this;
}
/**
* Returns array of description lines
*
* @return array
*/
abstract protected function prepareDescription(): array;
/**
* Returns array of headers
*
* @return array
*/
abstract protected function prepareHeaders(): array;
/**
* Returns array of request body lines
*
* @return array
*/
abstract protected function prepareBody(): array;
/**
* Converts request object to string to be written in result file
*
* @return string
*/
abstract public function __toString(): string;
}

View File

@@ -1,19 +0,0 @@
<?php
declare(strict_types=1);
namespace PmConverter\Exporters;
interface RequestContract
{
public function setName(string $name): static;
public function getName(): string;
public function setDescription(?string $description): static;
public function setVerb(string $verb): static;
public function setUrl(string $url): static;
public function setAuth(object $auth): static;
public function setHeaders(?array $headers): static;
public function setBodymode(string $bodymode): static;
public function setBody(object $body): static;
public function __toString(): string;
}

21
src/HttpVersions.php Normal file
View File

@@ -0,0 +1,21 @@
<?php
declare(strict_types=1);
namespace PmConverter;
enum HttpVersions: string
{
case Version10 = '1.0';
case Version11 = '1.1';
case Version2 = '2';
case Version3 = '3';
public static function values(): array
{
return array_combine(
array_column(self::cases(), 'name'),
array_column(self::cases(), 'value'),
);
}
}

View File

@@ -7,14 +7,14 @@ namespace PmConverter;
use Exception;
use InvalidArgumentException;
use JsonException;
use PmConverter\Converters\{
ConverterContract,
ConvertFormat};
use PmConverter\Exceptions\{
CannotCreateDirectoryException,
DirectoryIsNotReadableException,
DirectoryIsNotWriteableException,
DirectoryNotExistsException};
use PmConverter\Exporters\{
ConverterContract,
ConvertFormat};
class Processor
{