Passed
Branch php-scrutinizer (0ac9d8)
by Jens
09:19
created

Guzzle6Adapter::executeBatch()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 23
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 3

Importance

Changes 0
Metric Value
dl 0
loc 23
ccs 15
cts 15
cp 1
rs 9.0856
c 0
b 0
f 0
cc 3
eloc 14
nc 3
nop 2
crap 3
1
<?php
2
/**
3
 * @author @jenschude <[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 113
    public function __construct(array $options = [])
35
    {
36 113
        $options = array_merge(
37
            [
38 113
                'allow_redirects' => false,
39
                'verify' => true,
40 113
                'timeout' => 60,
41 113
                'connect_timeout' => 10,
42 113
                'concurrency' => self::DEFAULT_CONCURRENCY
43
            ],
44 113
            $options
45
        );
46 113
        $this->concurrency = $options['concurrency'];
47 113
        $this->client = new Client($options);
48 113
    }
49
50 45
    public function setLogger(LoggerInterface $logger, $logLevel = LogLevel::INFO, $formatter = null)
51
    {
52 45
        if (is_null($formatter)) {
53 45
            $formatter = new MessageFormatter();
54
        }
55 45
        $this->logger = $logger;
56 45
        $this->addHandler(self::log($logger, $formatter, $logLevel));
57 45
    }
58
59
    public function setCorrelationIdProvider(CorrelationIdProvider $provider)
60
    {
61 573
        $this->addHandler(Middleware::mapRequest(function (RequestInterface $request) use ($provider) {
62 573
            return $request->withAddedHeader(
63 573
                AbstractApiResponse::X_CORRELATION_ID,
64 573
                $provider->getCorrelationId()
65
            );
66 74
        }));
67 74
    }
68
69
    public function setOAuthTokenProvider(TokenProvider $tokenProvider)
70
    {
71 562
        $this->addHandler(Middleware::mapRequest(function (RequestInterface $request) use ($tokenProvider) {
72 562
            return $request->withAddedHeader(
73 562
                'Authorization',
74 562
                'Bearer ' . $tokenProvider->getToken()->getToken()
75
            );
76 60
        }));
77 60
    }
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 546
            return function ($request, array $options) use ($handler, $logger, $formatter, $logLevel) {
93 546
                return $handler($request, $options)->then(
94 546
                    function ($response) use ($logger, $request, $formatter, $logLevel) {
95 546
                        $message = $formatter->format($request, $response);
96
                        $context = [
97 546
                            AbstractApiResponse::X_CORRELATION_ID => $response->getHeader(
98 546
                                AbstractApiResponse::X_CORRELATION_ID
99
                            )
100
                        ];
101 546
                        $logger->log($logLevel, $message, $context);
102 546
                        return $response;
103 546
                    },
104 546
                    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 546
                    }
119
                );
120 39
            };
121 45
        };
122
    }
123
124 75
    public function addHandler($handler)
125
    {
126 75
        $this->client->getConfig('handler')->push($handler);
127 75
    }
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 590
    public function execute(RequestInterface $request, array $clientOptions = [])
145
    {
146
        try {
147 590
            $response = $this->client->send($request, $clientOptions);
148 84
        } catch (RequestException $exception) {
149 84
            $response = $exception->getResponse();
150 84
            throw ApiException::create($request, $response, $exception);
151
        }
152
153 563
        return $response;
154
    }
155
156
    /**
157
     * @param RequestInterface[] $requests
158
     * @param array $clientOptions
159
     * @return ResponseInterface[]
160
     */
161 467
    public function executeBatch(array $requests, array $clientOptions = [])
162
    {
163 467
        $results = Pool::batch(
164 467
            $this->client,
165 467
            $requests,
166
            [
167 467
                'concurrency' => $this->concurrency,
168 467
                'options' => $clientOptions
169
            ]
170
        );
171
172 467
        $responses = [];
173 467
        foreach ($results as $key => $result) {
174 467
            $httpResponse = $result;
175 467
            if ($result instanceof RequestException) {
176 11
                $request = $requests[$key];
177 11
                $httpResponse = $result->getResponse();
178 11
                $httpResponse = ApiException::create($request, $httpResponse, $result);
179
            }
180 467
            $responses[$key] = $httpResponse;
181
        }
182
183 467
        return $responses;
184
    }
185
186
    /**
187
     * @param $oauthUri
188
     * @param $clientId
189
     * @param $clientSecret
190
     * @param $formParams
191
     * @return ResponseInterface
192
     */
193 46
    public function authenticate($oauthUri, $clientId, $clientSecret, $formParams)
194
    {
195
        $options = [
196 46
            'form_params' => $formParams,
197 46
            'auth' => [$clientId, $clientSecret]
198
        ];
199
200
        try {
201 46
            $response = $this->client->post($oauthUri, $options);
202 3
        } catch (RequestException $exception) {
203 3
            throw ApiException::create($exception->getRequest(), $exception->getResponse(), $exception);
204
        }
205 45
        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 76
    public static function getAdapterInfo()
221
    {
222 76
        return 'GuzzleHttp/' . Client::VERSION;
223
    }
224
}
225