From 5bbddab7ee867d79304ea6aa3ef0a94d61f0084d Mon Sep 17 00:00:00 2001 From: Apcenuu <62610873+Apcenuu@users.noreply.github.com> Date: Tue, 12 Oct 2021 20:55:46 +0700 Subject: [PATCH] Refactor RetailcrmProxy --- doc/2. Workflow/Pipeline/Middlewares.md | 11 +++ retailcrm/lib/RetailcrmLogger.php | 20 +++++ retailcrm/lib/api/RetailcrmApiRequest.php | 64 +++++++++++++ retailcrm/lib/api/RetailcrmApiResponse.php | 8 +- retailcrm/lib/api/RetailcrmProxy.php | 90 +++++++------------ .../middleware/RetailcrmLoggerMiddleware.php | 38 ++++++++ retailcrm/lib/api/middleware/index.php | 8 ++ .../pipeline/RetailcrmMiddlewareInterface.php | 11 +++ .../lib/api/pipeline/RetailcrmPipeline.php | 72 +++++++++++++++ retailcrm/lib/api/pipeline/index.php | 8 ++ 10 files changed, 265 insertions(+), 65 deletions(-) create mode 100644 doc/2. Workflow/Pipeline/Middlewares.md mode change 100644 => 100755 retailcrm/lib/RetailcrmLogger.php create mode 100644 retailcrm/lib/api/RetailcrmApiRequest.php mode change 100644 => 100755 retailcrm/lib/api/RetailcrmProxy.php create mode 100644 retailcrm/lib/api/middleware/RetailcrmLoggerMiddleware.php create mode 100644 retailcrm/lib/api/middleware/index.php create mode 100644 retailcrm/lib/api/pipeline/RetailcrmMiddlewareInterface.php create mode 100644 retailcrm/lib/api/pipeline/RetailcrmPipeline.php create mode 100644 retailcrm/lib/api/pipeline/index.php diff --git a/doc/2. Workflow/Pipeline/Middlewares.md b/doc/2. Workflow/Pipeline/Middlewares.md new file mode 100644 index 0000000..3ca2fb6 --- /dev/null +++ b/doc/2. Workflow/Pipeline/Middlewares.md @@ -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 в стеке. \ No newline at end of file diff --git a/retailcrm/lib/RetailcrmLogger.php b/retailcrm/lib/RetailcrmLogger.php old mode 100644 new mode 100755 index 76b5f54..c389bb6 --- a/retailcrm/lib/RetailcrmLogger.php +++ b/retailcrm/lib/RetailcrmLogger.php @@ -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; + } } \ No newline at end of file diff --git a/retailcrm/lib/api/RetailcrmApiRequest.php b/retailcrm/lib/api/RetailcrmApiRequest.php new file mode 100644 index 0000000..d77a4f1 --- /dev/null +++ b/retailcrm/lib/api/RetailcrmApiRequest.php @@ -0,0 +1,64 @@ +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; + } + + +} \ No newline at end of file diff --git a/retailcrm/lib/api/RetailcrmApiResponse.php b/retailcrm/lib/api/RetailcrmApiResponse.php index a84452c..904108d 100644 --- a/retailcrm/lib/api/RetailcrmApiResponse.php +++ b/retailcrm/lib/api/RetailcrmApiResponse.php @@ -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. diff --git a/retailcrm/lib/api/RetailcrmProxy.php b/retailcrm/lib/api/RetailcrmProxy.php old mode 100644 new mode 100755 index 63deaa1..45db804 --- a/retailcrm/lib/api/RetailcrmProxy.php +++ b/retailcrm/lib/api/RetailcrmProxy.php @@ -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; } } diff --git a/retailcrm/lib/api/middleware/RetailcrmLoggerMiddleware.php b/retailcrm/lib/api/middleware/RetailcrmLoggerMiddleware.php new file mode 100644 index 0000000..a03e630 --- /dev/null +++ b/retailcrm/lib/api/middleware/RetailcrmLoggerMiddleware.php @@ -0,0 +1,38 @@ +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; + } +} \ No newline at end of file diff --git a/retailcrm/lib/api/middleware/index.php b/retailcrm/lib/api/middleware/index.php new file mode 100644 index 0000000..6a1c957 --- /dev/null +++ b/retailcrm/lib/api/middleware/index.php @@ -0,0 +1,8 @@ +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); + }; + }; + } +} \ No newline at end of file diff --git a/retailcrm/lib/api/pipeline/index.php b/retailcrm/lib/api/pipeline/index.php new file mode 100644 index 0000000..6a1c957 --- /dev/null +++ b/retailcrm/lib/api/pipeline/index.php @@ -0,0 +1,8 @@ +