Completed
Pull Request — develop (#333)
by Jens
14:58
created

Guzzle6Adapter   A

Complexity

Total Complexity 17

Size/Duplication

Total Lines 170
Duplicated Lines 2.94 %

Coupling/Cohesion

Components 1
Dependencies 11

Test Coverage

Coverage 86.67%

Importance

Changes 0
Metric Value
wmc 17
lcom 1
cbo 11
dl 5
loc 170
ccs 65
cts 75
cp 0.8667
rs 10
c 0
b 0
f 0

10 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 14 1
A setLogger() 0 8 2
A setCorrelationIdProvider() 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\Helper\CorrelationIdProvider;
9
use Commercetools\Core\Response\AbstractApiResponse;
10
use GuzzleHttp\Client;
11
use GuzzleHttp\Exception\RequestException;
12
use GuzzleHttp\MessageFormatter;
13
use GuzzleHttp\Middleware;
14
use GuzzleHttp\Pool;
15
use GuzzleHttp\Promise\PromiseInterface;
16
use Psr\Http\Message\RequestInterface;
17
use Psr\Http\Message\ResponseInterface;
18
use Psr\Log\LoggerInterface;
19
use Commercetools\Core\Error\Message;
20
use Commercetools\Core\Error\ApiException;
21
use Psr\Log\LogLevel;
22
23
class Guzzle6Adapter implements AdapterInterface, CorrelationIdAware
24
{
25
    /**
26
     * @var Client
27
     */
28
    protected $client;
29
30
    protected $logger;
31
32 110
    public function __construct(array $options = [])
33
    {
34 110
        $options = array_merge(
35
            [
36 110
                'allow_redirects' => false,
37
                'verify' => true,
38
                'timeout' => 60,
39
                'connect_timeout' => 10,
40
                'pool_size' => 25
41
            ],
42 110
            $options
43
        );
44 110
        $this->client = new Client($options);
45 110
    }
46
47 44
    public function setLogger(LoggerInterface $logger, $logLevel = LogLevel::INFO, $formatter = null)
48
    {
49 44
        if (is_null($formatter)) {
50 44
            $formatter = new MessageFormatter();
51
        }
52 44
        $this->logger = $logger;
53 44
        $this->addHandler(self::log($logger, $formatter, $logLevel));
54 44
    }
55
56
    public function setCorrelationIdProvider(CorrelationIdProvider $provider)
57
    {
58 475
        $this->addHandler(Middleware::mapRequest(function (RequestInterface $request) use ($provider) {
59 475
            return $request->withAddedHeader(
60 475
                AbstractApiResponse::X_CORRELATION_ID,
61 475
                $provider->getCorrelationId()
62
            );
63 39
        }));
64 39
    }
65
66
    /**
67
     * Middleware that logs requests, responses, and errors using a message
68
     * formatter.
69
     *
70
     * @param LoggerInterface  $logger Logs messages.
71
     * @param MessageFormatter $formatter Formatter used to create message strings.
72
     * @param string           $logLevel Level at which to log requests.
73
     *
74
     * @return callable Returns a function that accepts the next handler.
75
     */
76
    private static function log(LoggerInterface $logger, MessageFormatter $formatter, $logLevel = LogLevel::INFO)
77
    {
78
        return function (callable $handler) use ($logger, $formatter, $logLevel) {
79 481
            return function ($request, array $options) use ($handler, $logger, $formatter, $logLevel) {
80 481
                return $handler($request, $options)->then(
81 481
                    function ($response) use ($logger, $request, $formatter, $logLevel) {
82 481
                        $message = $formatter->format($request, $response);
83 481
                        $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...
84 481
                            AbstractApiResponse::X_CORRELATION_ID
85
                        );
86 481
                        $logger->log($logLevel, $message, $context);
87 481
                        return $response;
88 481
                    },
89 481
                    function ($reason) use ($logger, $request, $formatter) {
90
                        $response = null;
91
                        $context = [];
92
                        if ($reason instanceof RequestException) {
93
                            $response = $reason->getResponse();
94
                            if (!is_null($response)) {
95
                                $context[AbstractApiResponse::X_CORRELATION_ID] = $response->getHeader(
96
                                    AbstractApiResponse::X_CORRELATION_ID
97
                                );
98
                            }
99
                        }
100
                        $message = $formatter->format($request, $response, $reason);
101
                        $logger->notice($message, $context);
102
                        return \GuzzleHttp\Promise\rejection_for($reason);
103 481
                    }
104
                );
105 39
            };
106 44
        };
107
    }
108
109 47
    public function addHandler($handler)
110
    {
111 47
        $this->client->getConfig('handler')->push($handler);
112 47
    }
113
114
    /**
115
     * @param RequestInterface $request
116
     * @return ResponseInterface
117
     */
118 524
    public function execute(RequestInterface $request)
119
    {
120
        try {
121 524
            $response = $this->client->send($request);
122 111
        } catch (RequestException $exception) {
123 111
            $response = $exception->getResponse();
124 111
            throw ApiException::create($request, $response, $exception);
125
        }
126
127 498
        return $response;
128
    }
129
130
    /**
131
     * @param RequestInterface[] $requests
132
     * @return ResponseInterface[]
133
     */
134 402
    public function executeBatch(array $requests)
135
    {
136 402
        $results = Pool::batch(
137 402
            $this->client,
138 402
            $requests
139
        );
140
141 402
        $responses = [];
142 402
        foreach ($results as $key => $result) {
143 402
            $httpResponse = $result;
144 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...
145 16
                $request = $requests[$key];
146 16
                $httpResponse = $result->getResponse();
147 16
                $httpResponse = ApiException::create($request, $httpResponse, $result);
148
            }
149 402
            $responses[$key] = $httpResponse;
150
        }
151
152 402
        return $responses;
153
    }
154
155
    /**
156
     * @param $oauthUri
157
     * @param $clientId
158
     * @param $clientSecret
159
     * @param $formParams
160
     * @return ResponseInterface
161
     */
162 45
    public function authenticate($oauthUri, $clientId, $clientSecret, $formParams)
163
    {
164
        $options = [
165 45
            'form_params' => $formParams,
166 45
            'auth' => [$clientId, $clientSecret]
167
        ];
168
169
        try {
170 45
            $response = $this->client->post($oauthUri, $options);
171 3
        } catch (RequestException $exception) {
172 3
            throw ApiException::create($exception->getRequest(), $exception->getResponse(), $exception);
173
        }
174 44
        return $response;
175
    }
176
177
    /**
178
     * @param RequestInterface $request
179
     * @return AdapterPromiseInterface
180
     */
181 4
    public function executeAsync(RequestInterface $request)
182
    {
183 4
        $guzzlePromise = $this->client->sendAsync($request);
184
185 4
        return new Guzzle6Promise($guzzlePromise);
186
    }
187
188 74
    public static function getAdapterInfo()
189
    {
190 74
        return 'GuzzleHttp/' . Client::VERSION;
191
    }
192
}
193