Запись всех запросов и ответов на мыло в PHP

Кто-нибудь знает, как регистрировать все запросы и ответы со встроенным SoapClient в PHP? Я мог бы вручную зарегистрировать все с помощью SoapClient::__getLastRequest() и SoapClient::__getLastResponse() Но у нас есть столько мыльных запросов в нашей системе, что я ищу другие возможности.

Примечание: я использую wsdl-режим, используя метод, который туннелирует все до SoapClient::__soapCall() не является опцией

Related of "Запись всех запросов и ответов на мыло в PHP"

Я предлагаю второе предложение Александра и Штефана, но не подклассы SoapClient. Вместо этого я обернул бы обычный SoapClient в декораторе, потому что регистрация не является прямой проблемой SoapClient. Кроме того, свободная муфта позволяет легко заменить SoapClient макетами в UnitTests, поэтому вы можете сосредоточиться на тестировании функций ведения журнала. Если вы хотите только регистрировать определенные вызовы, вы можете добавить некоторую логику, которая фильтрует запросы и ответы с помощью действия $ или что-либо, что вам подходит.

Редактировать, так как Стефан предложил добавить код, декоратор, вероятно, будет выглядеть примерно так, хотя я не уверен в методе __call () (см. Комментарии Stefans)

 class SoapClientLogger { protected $soapClient; // wrapping the SoapClient instance with the decorator public function __construct(SoapClient $client) { $this->soapClient = $client; } // Overloading __doRequest with your logging code function __doRequest($request, $location, $action, $version, $one_way = 0) { $this->log($request, $location, $action, $version); $response = $this->soapClient->__doRequest($request, $location, $action, $version, $one_way); $this->log($response, $location, $action, $version); return $response; } public function log($request, $location, $action, $version) { // here you could add filterings to log only items, eg if($action === 'foo') { // code to log item } } // route all other method calls directly to soapClient public function __call($method, $args) { // you could also add method_exists check here return call_user_func_array(array($this->soapClient, $method), $args); } } 

Я думаю, что лучший способ – переопределить SoapClient::__doRequest() (а не SoapClient::__soapCall() ), поскольку у вас будет прямой доступ к запросу, а также к XML-ответу. Но общий подход к подклассу SoapClient должен быть способом.

 class My_LoggingSoapClient extends SoapClient { // logging methods function __doRequest($request, $location, $action, $version, $one_way = 0) { $this->_logRequest($location, $action, $version, $request); $response = parent::__doRequest($request, $location, $action, $version, $one_way); $this->_logResponse($location, $action, $version, $response); return $response; } } 

РЕДАКТИРОВАТЬ

С точки зрения дизайна OOP-дизайна / дизайна декоратор , очевидно, лучший способ справиться с такой проблемой – см . Ответ Гордона . Но это немного сложнее реализовать.

Извините, что просмотрел такой старый пост, но я столкнулся с некоторыми проблемами с реализацией принятого ответа декоратора, который отвечает за ведение журнала запросов Soap и хотел бы поделиться, если кто-то еще столкнется с этим.

Представьте, что вы настроили свой экземпляр следующим образом, используя класс SoapClientLogger, описанный в принятом ответе.

 $mySoapClient = new SoapClientLogger(new SoapClient()); 

Предположительно, любой метод, вызываемый экземпляром SoapClientLogger, будет передан через метод __call () и выполнен на SoapClient. Однако обычно вы используете SoapClient, вызывая методы, созданные из WSDL, например:

 $mySoapClient->AddMember($parameters); // AddMember is defined in the WSDL 

Это использование никогда не ударит по методу _doRequest () SoapClientLogger и, следовательно, запрос не будет зарегистрирован. Вместо этого AddMember () маршрутизируется через $ mySoapClient :: _ call (), а затем прямо вниз до метода _doRequest экземпляра SoapClient.

Я все еще ищу элегантное решение.

Переходя к проблеме, поднятой в https://stackoverflow.com/a/3939077/861788, я пришел со следующим решением ( полный источник ):

 <?php namespace Lc5\Toolbox\LoggingSoapClient; use Psr\Log\LoggerInterface; /** * Class LoggingSoapClient * * @author Łukasz Krzyszczak <lukasz.krzyszczak@gmail.com> */ class LoggingSoapClient { const REQUEST = 'Request'; const RESPONSE = 'Response'; /** * @var TraceableSoapClient */ private $soapClient; /** * @var LoggerInterface */ private $logger; /** * @param TraceableSoapClient $soapClient * @param LoggerInterface $logger */ public function __construct(TraceableSoapClient $soapClient, LoggerInterface $logger) { $this->soapClient = $soapClient; $this->logger = $logger; } /** * @param string $method * @param array $arguments * @return string */ public function __call($method, array $arguments) { $result = call_user_func_array([$this->soapClient, $method], $arguments); if (!method_exists($this->soapClient, $method) || $method === '__soapCall') { $this->logger->info($this->soapClient->__getLastRequest(), ['type' => self::REQUEST]); $this->logger->info($this->soapClient->__getLastResponse(), ['type' => self::RESPONSE]); } return $result; } /** * @param string $request * @param string $location * @param string $action * @param int $version * @param int $oneWay * @return string */ public function __doRequest($request, $location, $action, $version, $oneWay = 0) { $response = $this->soapClient->__doRequest($request, $location, $action, $version, $oneWay); $this->logger->info($request, ['type' => self::REQUEST]); $this->logger->info($response, ['type' => self::RESPONSE]); return $response; } } 

Применение:

 use Lc5\Toolbox\LoggingSoapClient\LoggingSoapClient; use Lc5\Toolbox\LoggingSoapClient\TraceableSoapClient; use Lc5\Toolbox\LoggingSoapClient\MessageXmlFormatter; use Monolog\Handler\StreamHandler; use Monolog\Logger; $handler = new StreamHandler('path/to/your.log'); $handler->setFormatter(new MessageXmlFormatter()); $logger = new Logger('soap'); $logger->pushHandler($handler); $soapClient = new LoggingSoapClient(new TraceableSoapClient('http://example.com'), $logger); 

Затем клиент SOAP регистрирует каждый запрос и ответ с помощью любого регистратора PSR-3.

Будет что-то вроде этой работы?

 class MySoapClient extends SoapClient { function __soapCall($function_name, $arguments, $options = null, $input_headers = null, &$output_headers = null) { $out = parent::__soapCall($function_name, $arguments, $options, $input_headers, $output_headers); // log request here... // log response here... return $out; } } 

Поскольку SoapClient уже отправляет все запросы через __soapCall, вы можете перехватить их путем подкласса SoapClient и переопределить его. Конечно, чтобы заставить его работать, вам нужно также заменить каждый new SoapClient(...) в вашем коде new MySoapClient(...) , но это похоже на довольно легкую задачу поиска и замены.