Passed
Push — develop ( b1701d...b569c3 )
by Jens
24:20
created

Guzzle5Adapter::__construct()   A

Complexity

Conditions 5
Paths 8

Size

Total Lines 25
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 6.9683

Importance

Changes 0
Metric Value
eloc 16
dl 0
loc 25
ccs 8
cts 14
cp 0.5714
rs 9.4222
c 0
b 0
f 0
cc 5
nc 8
nop 1
crap 6.9683
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\Helper\Subscriber\CorrelationIdSubscriber;
11
use Commercetools\Core\Helper\Subscriber\TokenSubscriber;
12
use GuzzleHttp\Client;
13
use GuzzleHttp\Exception\RequestException;
14
use GuzzleHttp\Pool;
15
use GuzzleHttp\Psr7\Request;
16
use GuzzleHttp\Psr7\Response;
17
use Psr\Http\Message\RequestInterface;
18
use Psr\Http\Message\ResponseInterface;
19
use Psr\Log\LoggerInterface;
20
use Commercetools\Core\Helper\Subscriber\Log\LogSubscriber;
21
use Commercetools\Core\Error\ApiException;
22
use Psr\Log\LogLevel;
23
24
class Guzzle5Adapter implements AdapterOptionInterface, CorrelationIdAware, TokenProviderAware, ConfigAware
25
{
26
    const DEFAULT_CONCURRENCY = 25;
27
28
    /**
29
     * @var Client
30
     */
31
    protected $client;
32
33
    /**
34
     * @var LoggerInterface
35
     */
36
    protected $logger;
37
38
    private $concurrency = self::DEFAULT_CONCURRENCY;
39
40
    /**
41
     * @param array $options
42
     */
43 1
    public function __construct(array $options = [])
44
    {
45 1
        if (isset($options['base_uri'])) {
46
            $options['base_url'] = $options['base_uri'];
47
            unset($options['base_uri']);
48
        }
49 1
        if (isset($options['concurrency'])) {
50
            $this->concurrency = $options['concurrency'];
51
            unset($options['concurrency']);
52
        }
53 1
        if (isset($options['headers'])) {
54
            $options['defaults']['headers'] = $options['headers'];
55
            unset($options['headers']);
56
        }
57 1
        $options['defaults'] = array_merge(
58
            [
59 1
                'allow_redirects' => false,
60
                'verify' => true,
61
                'timeout' => 60,
62
                'connect_timeout' => 10
63
            ],
64 1
            isset($options['defaults']) ? $options['defaults'] : []
65
        );
66
67 1
        $this->client = new Client($options);
68 1
    }
69
70
    public function setLogger(LoggerInterface $logger, $logLevel = LogLevel::INFO, $formatter = null)
71
    {
72
        $this->logger = $logger;
73
        if ($logger instanceof LoggerInterface) {
0 ignored issues
show
introduced by
$logger is always a sub-type of Psr\Log\LoggerInterface.
Loading history...
74
            $this->getEmitter()->attach(new LogSubscriber($logger, $formatter, $logLevel));
75
        }
76
    }
77
78
    public function addHandler($handler)
79
    {
80
        $this->getEmitter()->attach($handler);
81
    }
82
83
    public function setCorrelationIdProvider(CorrelationIdProvider $provider)
84
    {
85
        $this->addHandler(new CorrelationIdSubscriber($provider));
86
    }
87
88
    public function setOAuthTokenProvider(TokenProvider $tokenProvider)
89
    {
90
        $this->addHandler(new TokenSubscriber($tokenProvider));
91
    }
92
93
    /**
94
     * @internal
95
     * @return \GuzzleHttp\Event\Emitter|\GuzzleHttp\Event\EmitterInterface
96
     */
97
    public function getEmitter()
98
    {
99
        return $this->client->getEmitter();
0 ignored issues
show
Deprecated Code introduced by
The function GuzzleHttp\Client::__call() has been deprecated: Client::__call will be removed in guzzlehttp/guzzle:8.0. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

99
        return /** @scrutinizer ignore-deprecated */ $this->client->getEmitter();

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
Bug Best Practice introduced by
The expression return $this->client->getEmitter() returns the type GuzzleHttp\Promise\Promi...ssage\ResponseInterface which is incompatible with the documented return type GuzzleHttp\Event\Emitter...\Event\EmitterInterface.
Loading history...
100
    }
101
102
    /**
103
     * @param RequestInterface $request
104
     * @param array $clientOptions
105
     * @return ResponseInterface
106
     * @throws \Commercetools\Core\Error\ApiException
107
     * @throws \Commercetools\Core\Error\BadGatewayException
108
     * @throws \Commercetools\Core\Error\ConcurrentModificationException
109
     * @throws \Commercetools\Core\Error\ErrorResponseException
110
     * @throws \Commercetools\Core\Error\GatewayTimeoutException
111
     * @throws \Commercetools\Core\Error\InternalServerErrorException
112
     * @throws \Commercetools\Core\Error\InvalidTokenException
113
     * @throws \Commercetools\Core\Error\NotFoundException
114
     * @throws \Commercetools\Core\Error\ServiceUnavailableException
115
     */
116
    public function execute(RequestInterface $request, array $clientOptions = [])
117
    {
118
        $options = [
119
            'headers' => $request->getHeaders(),
120
            'body' => (string)$request->getBody()
121
        ];
122
        if (count($clientOptions)) {
123
            $options = array_merge($options, $clientOptions);
124
        }
125
126
        try {
127
            $guzzleRequest = $this->client->createRequest($request->getMethod(), (string)$request->getUri(), $options);
0 ignored issues
show
Deprecated Code introduced by
The function GuzzleHttp\Client::__call() has been deprecated: Client::__call will be removed in guzzlehttp/guzzle:8.0. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

127
            $guzzleRequest = /** @scrutinizer ignore-deprecated */ $this->client->createRequest($request->getMethod(), (string)$request->getUri(), $options);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
128
            $guzzleResponse = $this->client->send($guzzleRequest);
0 ignored issues
show
Bug introduced by
$guzzleRequest of type GuzzleHttp\Promise\Promi...ssage\ResponseInterface is incompatible with the type Psr\Http\Message\RequestInterface expected by parameter $request of GuzzleHttp\Client::send(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

128
            $guzzleResponse = $this->client->send(/** @scrutinizer ignore-type */ $guzzleRequest);
Loading history...
129
            $response = $this->packResponse($guzzleResponse);
130
        } catch (RequestException $exception) {
131
            $response = $this->packResponse($exception->getResponse());
132
            throw ApiException::create($request, $response, $exception);
133
        }
134
135
        return $response;
136
    }
137
138
    protected function packResponse(\GuzzleHttp\Message\ResponseInterface $response = null)
139
    {
140
        if (!$response instanceof \GuzzleHttp\Message\ResponseInterface) {
141
            return null;
142
        }
143
        return new Response(
144
            $response->getStatusCode(),
145
            $response->getHeaders(),
146
            (string)$response->getBody()
147
        );
148
    }
149
150
    /**
151
     * @param RequestInterface[] $requests
152
     * @param array $clientOptions
153
     * @return \Psr\Http\Message\ResponseInterface[]
154
     * @throws \Commercetools\Core\Error\ApiException
155
     * @throws \Commercetools\Core\Error\BadGatewayException
156
     * @throws \Commercetools\Core\Error\ConcurrentModificationException
157
     * @throws \Commercetools\Core\Error\ErrorResponseException
158
     * @throws \Commercetools\Core\Error\GatewayTimeoutException
159
     * @throws \Commercetools\Core\Error\InternalServerErrorException
160
     * @throws \Commercetools\Core\Error\InvalidTokenException
161
     * @throws \Commercetools\Core\Error\NotFoundException
162
     * @throws \Commercetools\Core\Error\ServiceUnavailableException
163
     */
164
    public function executeBatch(array $requests, array $clientOptions = [])
165
    {
166
        $results = Pool::batch(
167
            $this->client,
168
            $this->getBatchHttpRequests($requests, $clientOptions),
169
            ['pool_size' => $this->concurrency]
170
        );
171
172
        $responses = [];
173
        foreach ($results as $key => $result) {
174
            if (!$result instanceof RequestException) {
175
                $response = $this->packResponse($result);
176
            } else {
177
                $httpResponse = $this->packResponse($result->getResponse());
178
                $request = $requests[$key];
179
                $response = ApiException::create($request, $httpResponse, $result);
180
            }
181
            $responses[$key] = $response;
182
        }
183
184
        return $responses;
185
    }
186
187
    /**
188
     * @param array $requests
189
     * @param array $clientOptions
190
     * @return array
191
     */
192
    protected function getBatchHttpRequests(array $requests, array $clientOptions = [])
193
    {
194
        $requests = array_map(
195
            function ($request) use ($clientOptions) {
196
                $options = ['headers' => $request->getHeaders()];
197
                if (count($clientOptions)) {
198
                    $options = array_merge($options, $clientOptions);
199
                }
200
201
                /**
202
                 * @var RequestInterface $request
203
                 */
204
                return $this->client->createRequest(
0 ignored issues
show
Deprecated Code introduced by
The function GuzzleHttp\Client::__call() has been deprecated: Client::__call will be removed in guzzlehttp/guzzle:8.0. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

204
                return /** @scrutinizer ignore-deprecated */ $this->client->createRequest(

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
205
                    $request->getMethod(),
206
                    (string)$request->getUri(),
207
                    $options
208
                );
209
            },
210
            $requests
211
        );
212
213
        return $requests;
214
    }
215
216
    /**
217
     * @param $oauthUri
218
     * @param $clientId
219
     * @param $clientSecret
220
     * @param $formParams
221
     * @return ResponseInterface
222
     */
223
    public function authenticate($oauthUri, $clientId, $clientSecret, $formParams)
224
    {
225
        $options = [
226
            'body' => $formParams,
227
            'auth' => [$clientId, $clientSecret]
228
        ];
229
230
        try {
231
            $response = $this->client->post($oauthUri, $options);
232
        } catch (RequestException $exception) {
233
            $authRequest = $exception->getRequest();
234
            $request = new Request(
235
                $authRequest->getMethod(),
236
                $authRequest->getUrl(),
237
                $authRequest->getHeaders(),
238
                (string)$authRequest->getBody()
239
            );
240
            $response = $this->packResponse($exception->getResponse());
241
            throw ApiException::create($request, $response, $exception);
242
        }
243
        return $response;
244
    }
245
246
    /**
247
     * @param RequestInterface $request
248
     * @param array $clientOptions
249
     * @return AdapterPromiseInterface
250
     */
251
    public function executeAsync(RequestInterface $request, array $clientOptions = [])
252
    {
253
        $options = [
254
            'future' => true,
255
            'exceptions' => false,
256
            'headers' => $request->getHeaders()
257
        ];
258
        if (count($clientOptions)) {
259
            $options = array_merge($options, $clientOptions);
260
        }
261
        $request = $this->client->createRequest($request->getMethod(), (string)$request->getUri(), $options);
0 ignored issues
show
Deprecated Code introduced by
The function GuzzleHttp\Client::__call() has been deprecated: Client::__call will be removed in guzzlehttp/guzzle:8.0. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

261
        $request = /** @scrutinizer ignore-deprecated */ $this->client->createRequest($request->getMethod(), (string)$request->getUri(), $options);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
262
        $guzzlePromise = $this->client->send($request, $options);
0 ignored issues
show
Bug introduced by
$request of type GuzzleHttp\Promise\Promi...ssage\ResponseInterface is incompatible with the type Psr\Http\Message\RequestInterface expected by parameter $request of GuzzleHttp\Client::send(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

262
        $guzzlePromise = $this->client->send(/** @scrutinizer ignore-type */ $request, $options);
Loading history...
263
264
        $promise = new Guzzle5Promise($guzzlePromise);
265
        $promise->then(
266
            function (\GuzzleHttp\Message\ResponseInterface $response) {
267
                return new Response(
268
                    $response->getStatusCode(),
269
                    $response->getHeaders(),
270
                    (string)$response->getBody(),
271
                    $response->getProtocolVersion(),
272
                    $response->getReasonPhrase()
273
                );
274
            }
275
        );
276
277
        return $promise;
278
    }
279
280
    public static function getAdapterInfo()
281
    {
282
        return 'GuzzleHttp/' . Client::VERSION;
0 ignored issues
show
Bug introduced by
The constant GuzzleHttp\Client::VERSION was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
283
    }
284
285
    /**
286
     * @inheritdoc
287
     */
288
    public function getConfig($option)
289
    {
290
        return $this->client->getDefaultOption($option);
0 ignored issues
show
Deprecated Code introduced by
The function GuzzleHttp\Client::__call() has been deprecated: Client::__call will be removed in guzzlehttp/guzzle:8.0. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

290
        return /** @scrutinizer ignore-deprecated */ $this->client->getDefaultOption($option);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
291
    }
292
}
293