Completed
Push — master ( 44676f...b7bc18 )
by Jens
13:18
created

Guzzle6Adapter::executeBatch()   B

Complexity

Conditions 3
Paths 3

Size

Total Lines 24
Code Lines 15

Duplication

Lines 5
Ratio 20.83 %

Code Coverage

Tests 15
CRAP Score 3

Importance

Changes 0
Metric Value
dl 5
loc 24
ccs 15
cts 15
cp 1
rs 8.9713
c 0
b 0
f 0
cc 3
eloc 15
nc 3
nop 2
crap 3
1
<?php
2
/**
3
 * @author @jayS-de <[email protected]>
4
 */
5
6
namespace Commercetools\Core\Client\Adapter;
7
8
use Commercetools\Core\Client\OAuth\TokenProvider;
9
use Commercetools\Core\Helper\CorrelationIdProvider;
10
use Commercetools\Core\Response\AbstractApiResponse;
11
use GuzzleHttp\Client;
12
use GuzzleHttp\Exception\RequestException;
13
use GuzzleHttp\MessageFormatter;
14
use GuzzleHttp\Middleware;
15
use GuzzleHttp\Pool;
16
use Psr\Http\Message\RequestInterface;
17
use Psr\Http\Message\ResponseInterface;
18
use Psr\Log\LoggerInterface;
19
use Commercetools\Core\Error\ApiException;
20
use Psr\Log\LogLevel;
21
22
class Guzzle6Adapter implements AdapterOptionInterface, CorrelationIdAware, TokenProviderAware
23
{
24
    const DEFAULT_CONCURRENCY = 25;
25
    /**
26
     * @var Client
27
     */
28
    protected $client;
29
30
    protected $logger;
31
32
    private $concurrency;
33
34 112
    public function __construct(array $options = [])
35
    {
36 112
        $options = array_merge(
37
            [
38 112
                'allow_redirects' => false,
39
                'verify' => true,
40 112
                'timeout' => 60,
41 112
                'connect_timeout' => 10,
42 112
                'concurrency' => self::DEFAULT_CONCURRENCY
43
            ],
44 112
            $options
45
        );
46 112
        $this->concurrency = $options['concurrency'];
47 112
        $this->client = new Client($options);
48 112
    }
49
50 44
    public function setLogger(LoggerInterface $logger, $logLevel = LogLevel::INFO, $formatter = null)
51
    {
52 44
        if (is_null($formatter)) {
53 44
            $formatter = new MessageFormatter();
54
        }
55 44
        $this->logger = $logger;
56 44
        $this->addHandler(self::log($logger, $formatter, $logLevel));
57 44
    }
58
59
    public function setCorrelationIdProvider(CorrelationIdProvider $provider)
60
    {
61 530
        $this->addHandler(Middleware::mapRequest(function (RequestInterface $request) use ($provider) {
62 530
            return $request->withAddedHeader(
63 530
                AbstractApiResponse::X_CORRELATION_ID,
64 530
                $provider->getCorrelationId()
65
            );
66 73
        }));
67 73
    }
68
69
    public function setOAuthTokenProvider(TokenProvider $tokenProvider)
70
    {
71 519
        $this->addHandler(Middleware::mapRequest(function (RequestInterface $request) use ($tokenProvider) {
72 519
            return $request->withAddedHeader(
73 519
                'Authorization',
74 519
                'Bearer ' . $tokenProvider->getToken()->getToken()
75
            );
76 59
        }));
77 59
    }
78
79
    /**
80
     * Middleware that logs requests, responses, and errors using a message
81
     * formatter.
82
     *
83
     * @param LoggerInterface  $logger Logs messages.
84
     * @param MessageFormatter $formatter Formatter used to create message strings.
85
     * @param string           $logLevel Level at which to log requests.
86
     *
87
     * @return callable Returns a function that accepts the next handler.
88
     */
89
    private static function log(LoggerInterface $logger, MessageFormatter $formatter, $logLevel = LogLevel::INFO)
90
    {
91
        return function (callable $handler) use ($logger, $formatter, $logLevel) {
92 503
            return function ($request, array $options) use ($handler, $logger, $formatter, $logLevel) {
93 503
                return $handler($request, $options)->then(
94 503
                    function ($response) use ($logger, $request, $formatter, $logLevel) {
95 503
                        $message = $formatter->format($request, $response);
96
                        $context = [
97 503
                            AbstractApiResponse::X_CORRELATION_ID => $response->getHeader(
98 503
                                AbstractApiResponse::X_CORRELATION_ID
99
                            )
100
                        ];
101 503
                        $logger->log($logLevel, $message, $context);
102 503
                        return $response;
103 503
                    },
104 503
                    function ($reason) use ($logger, $request, $formatter) {
105
                        $response = null;
106
                        $context = [];
107
                        if ($reason instanceof RequestException) {
108
                            $response = $reason->getResponse();
109
                            if (!is_null($response)) {
110
                                $context[AbstractApiResponse::X_CORRELATION_ID] = $response->getHeader(
111
                                    AbstractApiResponse::X_CORRELATION_ID
112
                                );
113
                            }
114
                        }
115
                        $message = $formatter->format($request, $response, $reason);
116
                        $logger->notice($message, $context);
117
                        return \GuzzleHttp\Promise\rejection_for($reason);
118 503
                    }
119
                );
120 39
            };
121 44
        };
122
    }
123
124 74
    public function addHandler($handler)
125
    {
126 74
        $this->client->getConfig('handler')->push($handler);
127 74
    }
128
129
    /**
130
     * @param RequestInterface $request
131
     * @param array $clientOptions
132
     * @return ResponseInterface
133
     * @throws ApiException
134
     * @throws \Commercetools\Core\Error\ApiException
135
     * @throws \Commercetools\Core\Error\BadGatewayException
136
     * @throws \Commercetools\Core\Error\ConcurrentModificationException
137
     * @throws \Commercetools\Core\Error\ErrorResponseException
138
     * @throws \Commercetools\Core\Error\GatewayTimeoutException
139
     * @throws \Commercetools\Core\Error\InternalServerErrorException
140
     * @throws \Commercetools\Core\Error\InvalidTokenException
141
     * @throws \Commercetools\Core\Error\NotFoundException
142
     * @throws \Commercetools\Core\Error\ServiceUnavailableException
143
     */
144 547
    public function execute(RequestInterface $request, array $clientOptions = [])
145
    {
146
        try {
147 547
            $response = $this->client->send($request, $clientOptions);
148 110
        } catch (RequestException $exception) {
149 110
            $response = $exception->getResponse();
150 110
            throw ApiException::create($request, $response, $exception);
151
        }
152
153 521
        return $response;
154
    }
155
156
    /**
157
     * @param RequestInterface[] $requests
158
     * @param array $clientOptions
159
     * @return ResponseInterface[]
160
     */
161 421
    public function executeBatch(array $requests, array $clientOptions = [])
162
    {
163 421
        $results = Pool::batch(
164 421
            $this->client,
165 421
            $requests,
166
            [
167 421
                'concurrency' => $this->concurrency,
168 421
                'options' => $clientOptions
169
            ]
170
        );
171
172 421
        $responses = [];
173 421
        foreach ($results as $key => $result) {
174 421
            $httpResponse = $result;
175 421 View Code Duplication
            if ($result instanceof RequestException) {
176 17
                $request = $requests[$key];
177 17
                $httpResponse = $result->getResponse();
178 17
                $httpResponse = ApiException::create($request, $httpResponse, $result);
179
            }
180 421
            $responses[$key] = $httpResponse;
181
        }
182
183 421
        return $responses;
184
    }
185
186
    /**
187
     * @param $oauthUri
188
     * @param $clientId
189
     * @param $clientSecret
190
     * @param $formParams
191
     * @return ResponseInterface
192
     */
193 45
    public function authenticate($oauthUri, $clientId, $clientSecret, $formParams)
194
    {
195
        $options = [
196 45
            'form_params' => $formParams,
197 45
            'auth' => [$clientId, $clientSecret]
198
        ];
199
200
        try {
201 45
            $response = $this->client->post($oauthUri, $options);
202 3
        } catch (RequestException $exception) {
203 3
            throw ApiException::create($exception->getRequest(), $exception->getResponse(), $exception);
204
        }
205 44
        return $response;
206
    }
207
208
    /**
209
     * @param RequestInterface $request
210
     * @param array $clientOptions
211
     * @return AdapterPromiseInterface
212
     */
213 4
    public function executeAsync(RequestInterface $request, array $clientOptions = [])
214
    {
215 4
        $guzzlePromise = $this->client->sendAsync($request, $clientOptions);
216
217 4
        return new Guzzle6Promise($guzzlePromise);
218
    }
219
220 75
    public static function getAdapterInfo()
221
    {
222 75
        return 'GuzzleHttp/' . Client::VERSION;
223
    }
224
}
225