Test Failed
Push — develop ( 39caeb...ddfcb6 )
by Jens
11:52
created

Guzzle6Adapter::addHandler()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

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