Completed
Push — master ( 3564a7...54c862 )
by Dmitry
03:27
created

Transport::prepareXmlBody()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
cc 2
nc 2
nop 1
dl 0
loc 13
ccs 0
cts 9
cp 0
crap 6
rs 9.8333
c 0
b 0
f 0
1
<?php
2
/**
3
 * @author Dmitry Gladyshev <[email protected]>
4
 * @date 16/08/2016 18:06
5
 */
6
7
namespace Yandex\Direct\Transport\Json;
8
9
use GuzzleHttp\Client;
10
use GuzzleHttp\ClientInterface;
11
use GuzzleHttp\Exception\RequestException;
12
use GuzzleHttp\HandlerStack;
13
use GuzzleHttp\MessageFormatter;
14
use GuzzleHttp\Middleware;
15
use LSS\Array2XML;
16
use Psr\Log\LoggerAwareInterface;
17
use Psr\Log\LoggerInterface;
18
use Psr\Log\NullLogger;
19
use Yandex\Direct\ConfigurableInterface;
20
use Yandex\Direct\ConfigurableTrait;
21
use Yandex\Direct\Exception\InvalidArgumentException;
22
use Yandex\Direct\Exception\RuntimeException;
23
use Yandex\Direct\Exception\TransportRequestException;
24
use Yandex\Direct\Transport\RequestInterface;
25
use Yandex\Direct\Transport\Response;
26
use Yandex\Direct\Transport\TransportInterface;
27
28
/**
29
 * Class JsonTransport
30
 * @package Yandex\Direct\Transport
31
 */
32
class Transport implements TransportInterface, LoggerAwareInterface, ConfigurableInterface
33
{
34
    use ConfigurableTrait;
35
36
    /**
37
     * @var string
38
     */
39
    private $baseUrl = 'https://api.direct.yandex.com';
40
41
    /**
42
     * @var string
43
     */
44
    private $reportsXmlSchema = 'https://api.direct.yandex.com/v5/reports.xsd';
45
46
    /**
47
     * @var bool
48
     */
49
    private $enableReportValidation = false;
50
51
    /**
52
     * @var ClientInterface
53
     */
54
    private $httpClient;
55
56
    /**
57
     * Custom Service urls
58
     * @var array
59
     */
60
    private $serviceUrls = [
61
//        'Reports' => '/v5/reports'
62
    ];
63
64
    /**
65
     * @var array
66
     */
67
    private $headers = [
68
        'Content-Type' => 'application/json; charset=utf-8'
69
    ];
70
71
    /**
72
     * @var LoggerInterface
73
     */
74
    private $logger;
75
76
    /**
77
     * @var MessageFormatter
78
     */
79
    private $logMessageFormatter;
80
81
    /**
82
     * JsonTransport constructor.
83
     *
84
     * @param array $options
85
     * @throws InvalidArgumentException
86
     */
87 56
    public function __construct(array $options = [])
88
    {
89 56
        $this->setOptions($options);
90 56
    }
91
92
    /**
93
     * @inheritdoc
94
     */
95 2
    public function getServiceUrl($serviceName)
96
    {
97 2
        if (array_key_exists($serviceName, $this->serviceUrls)) {
98
            // If service url is absolute
99 1
            if (preg_match('#http[s]*://#u', $this->serviceUrls[$serviceName])) {
100 1
                return $this->serviceUrls[$serviceName];
101
            }
102 1
            return $this->baseUrl . $this->serviceUrls[$serviceName];
103
        }
104
105 2
        return $this->baseUrl . '/json/v5/' . strtolower($serviceName);
106
    }
107
108
    /**
109
     * @param array $headers
110
     */
111 1
    public function setHeaders(array $headers)
112
    {
113 1
        $this->headers = array_merge($this->headers, $headers);
114 1
    }
115
116
    /**
117
     * @inheritdoc
118
     */
119 1
    public function setLogger(LoggerInterface $logger)
120
    {
121 1
        $this->logger = $logger;
122 1
    }
123
124
    /**
125
     * @inheritdoc
126
     */
127 1
    public function request(RequestInterface $request)
128
    {
129
        try {
130 1
            $client = $this->getHttpClient();
131
132 1
            $httpResponse = $client->request('POST', $this->getServiceUrl($request->getService()), [
133 1
                'headers' => $this->prepareHeaders($request),
134 1
                'body' => $this->prepareBody($request)
135 1
            ]);
136
137 1
            $httpResponseHeaders = $httpResponse->getHeaders();
138
139 1
            return new Response([
140 1
                'service' => $request->getService(),
141 1
                'method' => $request->getMethod(),
142 1
                'headers' => $httpResponse->getHeaders(),
143 1
                'body' => $httpResponse->getBody()->__toString(),
144 1
                'code' => $httpResponse->getStatusCode(),
145 1
                'requestId' => array_key_exists('RequestId', $httpResponseHeaders)
146 1
                    ? current($httpResponseHeaders['RequestId'])
147 1
                    : null,
148 1
                'units' => array_key_exists('Units', $httpResponseHeaders)
149 1
                    ? current($httpResponseHeaders['Units'])
150 1
                    : [null, null, null]
151 1
            ]);
152
        } catch (RequestException $e) {
153
            $this->getLogger()->error("Transport error: {$e->getMessage()} [CODE: {$e->getCode()}]");
154
            throw new TransportRequestException(
155
                $e->getMessage(),
156
                $e->getCode(),
157
                $e->getRequest()->getHeaders(),
158
                $e->getRequest()->getBody()->__toString(),
159
                $e->hasResponse() ? $e->getResponse()->getHeaders() : [],
160
                $e->hasResponse() ? $e->getResponse()->getBody()->__toString() : '',
161
                $e->getPrevious()
162
            );
163
        } catch (\Exception $e) {
164
            $this->getLogger()->error("Runtime error: {$e->getMessage()} [CODE: {$e->getCode()}]");
165
            throw new RuntimeException($e->getMessage(), $e->getCode(), $e->getPrevious());
166
        }
167
    }
168
169
    /**
170
     * @return ClientInterface
171
     */
172 1
    private function getHttpClient()
173
    {
174 1
        if ($this->httpClient === null) {
175
            $this->httpClient = new Client([
176
                'base_uri' => $this->baseUrl,
177
                'handler' => $this->getHttpHandlers()
178
            ]);
179
        }
180 1
        return $this->httpClient;
181 1
    }
182
183
    /**
184
     * @return LoggerInterface
185
     */
186 1
    private function getLogger()
187
    {
188
        // Use stub if logger is not initialized
189 1
        if ($this->logger === null) {
190
            $this->logger = new NullLogger;
191
        }
192 1
        return $this->logger;
193
    }
194
195
    /**
196
     * @return MessageFormatter
197
     */
198 1
    private function getMessageFormatter()
199
    {
200 1
        if ($this->logMessageFormatter === null) {
201 1
            $this->logMessageFormatter = new MessageFormatter(MessageFormatter::DEBUG);
202 1
        }
203 1
        return $this->logMessageFormatter;
204
    }
205
206
    /**
207
     * @return HandlerStack
208
     */
209 1
    private function getHttpHandlers()
210
    {
211 1
        $stack = HandlerStack::create();
212 1
        $stack->push(Middleware::log(
213 1
            $this->getLogger(),
214 1
            $this->getMessageFormatter()
215 1
        ));
216 1
        return $stack;
217
    }
218
219
    /**
220
     * @param RequestInterface $request
221
     * @return array
222
     */
223 1
    private function prepareHeaders(RequestInterface $request)
224
    {
225 1
        $headers = array_merge([
226 1
            'Authorization' => 'Bearer ' . $request->getCredentials()->getToken(),
227 1
            'Client-Login' => $request->getCredentials()->getLogin(),
228 1
        ], $this->headers, $request->getHeaders());
229
230 1
        if ($request->getService() === self::SERVICE_AGENCY_CLIENTS) {
231
            unset($headers['Client-Login']);
232
        }
233
234 1
        return $headers;
235
    }
236
237
    /**
238
     * @param RequestInterface $request
239
     * @return string
240
     * @throws InvalidArgumentException
241
     */
242 1
    private function prepareBody(RequestInterface $request)
243
    {
244 1
        return $this->prepareJsonBody($request);
245
    }
246
247
    /**
248
     * @param RequestInterface $request
249
     * @return string
250
     */
251 1
    private function prepareJsonBody(RequestInterface $request)
252
    {
253 1
        return json_encode(
254 1
            array_merge(['method' => $request->getMethod()], $request->getParams()),
255 1
            JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT
256 1
        );
257
    }
258
}
259