Completed
Push — master ( 3f2d2e...78eab5 )
by Jens
09:03
created

Guzzle6Adapter::log()   B

Complexity

Conditions 2
Paths 1

Size

Total Lines 30
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 16
CRAP Score 2

Importance

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