Passed
Push — develop ( 166b0f...9fc299 )
by Jens
04:57
created

Guzzle6Adapter   A

Complexity

Total Complexity 18

Size/Duplication

Total Lines 180
Duplicated Lines 2.78 %

Coupling/Cohesion

Components 1
Dependencies 13

Test Coverage

Coverage 87.65%

Importance

Changes 0
Metric Value
wmc 18
lcom 1
cbo 13
dl 5
loc 180
ccs 71
cts 81
cp 0.8765
rs 10
c 0
b 0
f 0

11 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 14 1
A setLogger() 0 8 2
A setCorrelationIdProvider() 0 9 1
A setOAuthTokenProvider() 0 9 1
B log() 0 32 3
A addHandler() 0 4 1
A execute() 0 11 2
A executeBatch() 5 20 3
A authenticate() 0 14 2
A executeAsync() 0 6 1
A getAdapterInfo() 0 4 1

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

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 GuzzleHttp\Promise\PromiseInterface;
17
use Psr\Http\Message\RequestInterface;
18
use Psr\Http\Message\ResponseInterface;
19
use Psr\Log\LoggerInterface;
20
use Commercetools\Core\Error\Message;
21
use Commercetools\Core\Error\ApiException;
22
use Psr\Log\LogLevel;
23
24
class Guzzle6Adapter implements AdapterInterface, CorrelationIdAware, TokenProviderAware
25
{
26
    /**
27
     * @var Client
28
     */
29
    protected $client;
30
31
    protected $logger;
32
33 111
    public function __construct(array $options = [])
34
    {
35 111
        $options = array_merge(
36
            [
37 111
                'allow_redirects' => false,
38
                'verify' => true,
39
                'timeout' => 60,
40
                'connect_timeout' => 10,
41
                'pool_size' => 25
42
            ],
43 111
            $options
44
        );
45 111
        $this->client = new Client($options);
46 111
    }
47
48 44
    public function setLogger(LoggerInterface $logger, $logLevel = LogLevel::INFO, $formatter = null)
49
    {
50 44
        if (is_null($formatter)) {
51 44
            $formatter = new MessageFormatter();
52
        }
53 44
        $this->logger = $logger;
54 44
        $this->addHandler(self::log($logger, $formatter, $logLevel));
55 44
    }
56
57
    public function setCorrelationIdProvider(CorrelationIdProvider $provider)
58
    {
59 474
        $this->addHandler(Middleware::mapRequest(function (RequestInterface $request) use ($provider) {
60 474
            return $request->withAddedHeader(
61 474
                AbstractApiResponse::X_CORRELATION_ID,
62 474
                $provider->getCorrelationId()
63
            );
64 39
        }));
65 39
    }
66
67
    public function setOAuthTokenProvider(TokenProvider $tokenProvider)
68
    {
69 496
        $this->addHandler(Middleware::mapRequest(function (RequestInterface $request) use ($tokenProvider) {
70 496
            return $request->withAddedHeader(
71 496
                'Authorization',
72 496
                'Bearer ' . $tokenProvider->getToken()->getToken()
73
            );
74 58
        }));
75 58
    }
76
77
    /**
78
     * Middleware that logs requests, responses, and errors using a message
79
     * formatter.
80
     *
81
     * @param LoggerInterface  $logger Logs messages.
82
     * @param MessageFormatter $formatter Formatter used to create message strings.
83
     * @param string           $logLevel Level at which to log requests.
84
     *
85
     * @return callable Returns a function that accepts the next handler.
86
     */
87
    private static function log(LoggerInterface $logger, MessageFormatter $formatter, $logLevel = LogLevel::INFO)
88
    {
89
        return function (callable $handler) use ($logger, $formatter, $logLevel) {
90 480
            return function ($request, array $options) use ($handler, $logger, $formatter, $logLevel) {
91 480
                return $handler($request, $options)->then(
92 480
                    function ($response) use ($logger, $request, $formatter, $logLevel) {
93 480
                        $message = $formatter->format($request, $response);
94 480
                        $context[AbstractApiResponse::X_CORRELATION_ID] = $response->getHeader(
0 ignored issues
show
Coding Style Comprehensibility introduced by
$context was never initialized. Although not strictly required by PHP, it is generally a good practice to add $context = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
95 480
                            AbstractApiResponse::X_CORRELATION_ID
96
                        );
97 480
                        $logger->log($logLevel, $message, $context);
98 480
                        return $response;
99 480
                    },
100 480
                    function ($reason) use ($logger, $request, $formatter) {
101
                        $response = null;
102
                        $context = [];
103
                        if ($reason instanceof RequestException) {
104
                            $response = $reason->getResponse();
105
                            if (!is_null($response)) {
106
                                $context[AbstractApiResponse::X_CORRELATION_ID] = $response->getHeader(
107
                                    AbstractApiResponse::X_CORRELATION_ID
108
                                );
109
                            }
110
                        }
111
                        $message = $formatter->format($request, $response, $reason);
112
                        $logger->notice($message, $context);
113
                        return \GuzzleHttp\Promise\rejection_for($reason);
114 480
                    }
115
                );
116 39
            };
117 44
        };
118
    }
119
120 65
    public function addHandler($handler)
121
    {
122 65
        $this->client->getConfig('handler')->push($handler);
123 65
    }
124
125
    /**
126
     * @param RequestInterface $request
127
     * @return ResponseInterface
128
     */
129 524
    public function execute(RequestInterface $request)
130
    {
131
        try {
132 524
            $response = $this->client->send($request);
133 111
        } catch (RequestException $exception) {
134 111
            $response = $exception->getResponse();
135 111
            throw ApiException::create($request, $response, $exception);
136
        }
137
138 498
        return $response;
139
    }
140
141
    /**
142
     * @param RequestInterface[] $requests
143
     * @return ResponseInterface[]
144
     */
145 402
    public function executeBatch(array $requests)
146
    {
147 402
        $results = Pool::batch(
148 402
            $this->client,
149 402
            $requests
150
        );
151
152 402
        $responses = [];
153 402
        foreach ($results as $key => $result) {
154 402
            $httpResponse = $result;
155 402 View Code Duplication
            if ($result instanceof RequestException) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
156 16
                $request = $requests[$key];
157 16
                $httpResponse = $result->getResponse();
158 16
                $httpResponse = ApiException::create($request, $httpResponse, $result);
159
            }
160 402
            $responses[$key] = $httpResponse;
161
        }
162
163 402
        return $responses;
164
    }
165
166
    /**
167
     * @param $oauthUri
168
     * @param $clientId
169
     * @param $clientSecret
170
     * @param $formParams
171
     * @return ResponseInterface
172
     */
173 45
    public function authenticate($oauthUri, $clientId, $clientSecret, $formParams)
174
    {
175
        $options = [
176 45
            'form_params' => $formParams,
177 45
            'auth' => [$clientId, $clientSecret]
178
        ];
179
180
        try {
181 45
            $response = $this->client->post($oauthUri, $options);
182 3
        } catch (RequestException $exception) {
183 3
            throw ApiException::create($exception->getRequest(), $exception->getResponse(), $exception);
184
        }
185 44
        return $response;
186
    }
187
188
    /**
189
     * @param RequestInterface $request
190
     * @return AdapterPromiseInterface
191
     */
192 4
    public function executeAsync(RequestInterface $request)
193
    {
194 4
        $guzzlePromise = $this->client->sendAsync($request);
195
196 4
        return new Guzzle6Promise($guzzlePromise);
197
    }
198
199 74
    public static function getAdapterInfo()
200
    {
201 74
        return 'GuzzleHttp/' . Client::VERSION;
202
    }
203
}
204