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;
}
/**
* 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
{
// HTTP response status code
protected $statusCode;
private $statusCode;
// response assoc array
protected $response;
private $response;
// raw response
protected $rawResponse;
private $rawResponse;
/**
* ApiResponse constructor.

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

@ -37,75 +37,45 @@
*/
class RetailcrmProxy
{
private $api;
private $log;
public function __construct($url, $key, $log)
{
$this->api = new RetailcrmApiClientV5($url, $key);
$this->log = $log;
}
/**
* @var RetailcrmApiClientV5
*/
private $client;
/**
* Reduces error array into string
*
* @param $errors
*
* @return false|string
* @var RetailcrmPipeline
*/
private static function reduceErrors($errors)
private $pipeline;
public function __construct($url, $key)
{
$reduced = '';
$this->client = new RetailcrmApiClientV5($url, $key);
if (is_array($errors)) {
foreach ($errors as $key => $error) {
$reduced .= sprintf('%s => %s\n', $key, $error);
}
}
return $reduced;
$this->pipeline = new RetailcrmPipeline();
$this->pipeline
->setMiddlewares(
RetailcrmTools::filter(
'RetailcrmFilterMiddlewares',
[
RetailcrmLoggerMiddleware::class,
])
)
->setAction(function ($request) {
return call_user_func_array([$this->client, $request->getMethod()], $request->getData());
})
->build()
;
}
public function __call($method, $arguments)
{
$date = date('Y-m-d H:i:s');
try {
RetailcrmLogger::writeDebug($method, print_r($arguments, true));
$response = call_user_func_array(array($this->api, $method), $arguments);
{
$request = new RetailcrmApiRequest();
$request->setApi($this->client);
$request->setMethod($method);
$request->setData($arguments);
if (!($response instanceof RetailcrmApiResponse)) {
RetailcrmLogger::writeDebug($method, $response);
return $response;
}
$response = $this->pipeline->run($request);
if (!$response->isSuccessful()) {
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;
}
return $response;
}
}

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;