Refactor RetailcrmProxy

This commit is contained in:
Apcenuu 2021-10-12 20:55:46 +07:00 committed by GitHub
parent 35bccc98b4
commit 5bbddab7ee
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 265 additions and 65 deletions

View File

@ -0,0 +1,11 @@
# Middlewares
Pipeline содержит стек middleware. В глубине стека выполняется callback-функция, переданная в метод setAction класса *RetailcrmPipeline*.
Для добавления дополнительной логики при обработке запроса вы можете добавить новую middleware в pipeline.
Для этого требуется создать класс, реализующий интерфейс *RetailcrmMiddlewareInterface* и добавить имя класса в массив, который передаётся в метод setMiddlewares класса RetailcrmPipeline.
Порядок в массиве, передаваемом в *setMiddlewares()* определяет позицию middleware в стеке. Напрмер, массив `[MW1, MW2, MW3]` приведет к вызову `MW1 -> MW2 -> MW3 -> ACTION -> MW3 -> MW2 -> MW1`.
К middleware применяются фильтры из папки `custom/hooks`
В методе *__invoke()* middleware-класса должна быть описана логика, которую вы хотите выполнить при обработке запроса, а так же вызов следующей middleware в стеке.

20
retailcrm/lib/RetailcrmLogger.php Normal file → Executable file
View File

@ -302,4 +302,24 @@ class RetailcrmLogger
return false; return false;
} }
/**
* Reduces error array into string
*
* @param $errors
*
* @return string
*/
public static function reduceErrors($errors)
{
$reduced = '';
if (is_array($errors)) {
foreach ($errors as $key => $error) {
$reduced .= sprintf('%s => %s\n', $key, $error);
}
}
return $reduced;
}
} }

View File

@ -0,0 +1,64 @@
<?php
class RetailcrmApiRequest
{
private $api;
private $data;
private $method;
/**
* @return mixed
*/
public function getApi()
{
return $this->api;
}
/**
* @param mixed $api
* @return RetailcrmApiRequest
*/
public function setApi($api)
{
$this->api = $api;
return $this;
}
/**
* @return mixed
*/
public function getData()
{
return $this->data;
}
/**
* @param mixed $data
*/
public function setData($data)
{
$this->data = $data;
return $this;
}
/**
* @return mixed
*/
public function getMethod()
{
return $this->method;
}
/**
* @param mixed $method
*/
public function setMethod($method)
{
$this->method = $method;
return $this;
}
}

View File

@ -38,13 +38,11 @@
class RetailcrmApiResponse implements \ArrayAccess class RetailcrmApiResponse implements \ArrayAccess
{ {
// HTTP response status code // HTTP response status code
protected $statusCode; private $statusCode;
// response assoc array private $response;
protected $response;
// raw response private $rawResponse;
protected $rawResponse;
/** /**
* ApiResponse constructor. * ApiResponse constructor.

90
retailcrm/lib/api/RetailcrmProxy.php Normal file → Executable file
View File

@ -37,75 +37,45 @@
*/ */
class RetailcrmProxy class RetailcrmProxy
{ {
private $api; /**
private $log; * @var RetailcrmApiClientV5
*/
public function __construct($url, $key, $log) private $client;
{
$this->api = new RetailcrmApiClientV5($url, $key);
$this->log = $log;
}
/** /**
* Reduces error array into string * @var RetailcrmPipeline
*
* @param $errors
*
* @return false|string
*/ */
private static function reduceErrors($errors) private $pipeline;
public function __construct($url, $key)
{ {
$reduced = ''; $this->client = new RetailcrmApiClientV5($url, $key);
if (is_array($errors)) { $this->pipeline = new RetailcrmPipeline();
foreach ($errors as $key => $error) { $this->pipeline
$reduced .= sprintf('%s => %s\n', $key, $error); ->setMiddlewares(
} RetailcrmTools::filter(
} 'RetailcrmFilterMiddlewares',
[
return $reduced; RetailcrmLoggerMiddleware::class,
])
)
->setAction(function ($request) {
return call_user_func_array([$this->client, $request->getMethod()], $request->getData());
})
->build()
;
} }
public function __call($method, $arguments) public function __call($method, $arguments)
{ {
$date = date('Y-m-d H:i:s'); $request = new RetailcrmApiRequest();
try { $request->setApi($this->client);
RetailcrmLogger::writeDebug($method, print_r($arguments, true)); $request->setMethod($method);
$response = call_user_func_array(array($this->api, $method), $arguments); $request->setData($arguments);
if (!($response instanceof RetailcrmApiResponse)) { $response = $this->pipeline->run($request);
RetailcrmLogger::writeDebug($method, $response);
return $response;
}
if (!$response->isSuccessful()) { return $response;
RetailcrmLogger::writeCaller($method, $response->getErrorMsg());
if (isset($response['errors'])) {
RetailcrmApiErrors::set($response['errors'], $response->getStatusCode());
$error = static::reduceErrors($response['errors']);
RetailcrmLogger::writeNoCaller($error);
}
$response = false;
} else {
// Don't print long lists in debug logs (errors while calling this will be easy to detect anyway)
if (in_array($method, array('statusesList', 'paymentTypesList', 'deliveryTypesList'))) {
RetailcrmLogger::writeDebug($method, '[request was successful, but response is omitted]');
} else {
RetailcrmLogger::writeDebug($method, $response->getRawResponse());
}
}
return $response;
} catch (CurlException $e) {
RetailcrmLogger::writeCaller(get_class($this->api).'::'.$method, $e->getMessage());
RetailcrmLogger::writeNoCaller($e->getTraceAsString());
return false;
} catch (InvalidJsonException $e) {
RetailcrmLogger::writeCaller(get_class($this->api).'::'.$method, $e->getMessage());
RetailcrmLogger::writeNoCaller($e->getTraceAsString());
return false;
}
} }
} }

View File

@ -0,0 +1,38 @@
<?php
class RetailcrmLoggerMiddleware implements RetailcrmMiddlewareInterface
{
/**
* @param RetailcrmApiRequest $request
* @param callable|null $next
* @return RetailcrmApiResponse
*/
public function __invoke(RetailcrmApiRequest $request, callable $next = null)
{
$method = $request->getMethod();
if (!is_null($request->getMethod())) {
RetailcrmLogger::writeDebug($method, print_r($request->getData(), true));
}
$response = $next($request);
if ($response->isSuccessful()) {
// Don't print long lists in debug logs (errors while calling this will be easy to detect anyway)
if (in_array($method, ['statusesList', 'paymentTypesList', 'deliveryTypesList'])) {
RetailcrmLogger::writeDebug($method, '[request was successful, but response is omitted]');
} else {
RetailcrmLogger::writeDebug($method, $response->getRawResponse());
}
} else {
RetailcrmLogger::writeCaller($method, $response->getErrorMsg());
if (isset($response['errors'])) {
RetailcrmApiErrors::set($response['errors'], $response->getStatusCode());
$error = RetailcrmLogger::reduceErrors($response['errors']);
RetailcrmLogger::writeNoCaller($error);
}
}
return $response;
}
}

View File

@ -0,0 +1,8 @@
<?php
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT");
header("Cache-Control: no-store, no-cache, must-revalidate");
header("Cache-Control: post-check=0, pre-check=0", false);
header("Pragma: no-cache");
header("Location: ../");
exit;

View File

@ -0,0 +1,11 @@
<?php
interface RetailcrmMiddlewareInterface
{
/**
* @param RetailcrmApiRequest $request
* @param callable|null $next
* @return RetailcrmApiResponse
*/
public function __invoke(RetailcrmApiRequest $request, callable $next = null);
}

View File

@ -0,0 +1,72 @@
<?php
class RetailcrmPipeline
{
/**
* @var array
*/
private $middlewares;
/**
* @var callable
*/
private $action;
/**
* @var callable
*/
private $pipeline;
/**
* @param RetailcrmApiRequest $request
* @return callable
*/
public function run(RetailcrmApiRequest $request)
{
$pipeline = $this->pipeline;
return $pipeline($request);
}
/**
* @param callable $action
* @return $this
*/
public function setAction(callable $action)
{
$this->action = $action;
return $this;
}
/**
* @param array $middlewares
* @return $this
*/
public function setMiddlewares(array $middlewares)
{
$this->middlewares = $middlewares;
return $this;
}
public function build()
{
$this->pipeline =
array_reduce(
array_reverse($this->middlewares),
$this->buildStack(),
$this->action
);
}
/**
* @return callable
*/
private function buildStack()
{
return function ($stack, $middlewareClass) {
return function ($request) use ($stack, $middlewareClass) {
$middleware = new $middlewareClass;
return $middleware($request, $stack);
};
};
}
}

View File

@ -0,0 +1,8 @@
<?php
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT");
header("Cache-Control: no-store, no-cache, must-revalidate");
header("Cache-Control: post-check=0, pre-check=0", false);
header("Pragma: no-cache");
header("Location: ../");
exit;