Completed
Pull Request — master (#135)
by
unknown
06:43
created

ProfileClient::sendAsyncRequest()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 19
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 19
ccs 0
cts 0
cp 0
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 12
nc 1
nop 1
crap 2
1
<?php
2
3
namespace Http\HttplugBundle\Collector;
4
5
use Http\Client\Common\FlexibleHttpClient;
6
use Http\Client\Exception\HttpException;
7
use Http\Client\HttpAsyncClient;
8
use Http\Client\HttpClient;
9
use Psr\Http\Message\RequestInterface;
10
use Psr\Http\Message\ResponseInterface;
11
use Symfony\Component\Stopwatch\Stopwatch;
12
use Symfony\Component\Stopwatch\StopwatchEvent;
13
14
/**
15
 * The ProfileClient decorates any client that implement both HttpClient and HttpAsyncClient interfaces to gather target
16
 * url and response status code.
17
 *
18
 * @author Fabien Bourigault <[email protected]>
19
 *
20
 * @internal
21
 */
22
class ProfileClient implements HttpClient, HttpAsyncClient
23
{
24
    /**
25
     * @var HttpClient|HttpAsyncClient
26
     */
27
    private $client;
28
29
    /**
30
     * @var Collector
31
     */
32
    private $collector;
33
34
    /**
35
     * @var Formatter
36
     */
37
    private $formatter;
38
39
    /**
40
     * @var Stopwatch
41
     */
42
    private $stopwatch;
43
44
    /**
45
     * @param HttpClient|HttpAsyncClient $client    The client to profile. Client must implement both HttpClient and
46
     *                                              HttpAsyncClient interfaces.
47
     * @param Collector                  $collector
48
     * @param Formatter                  $formatter
49
     * @param Stopwatch                  $stopwatch
50
     */
51 4
    public function __construct($client, Collector $collector, Formatter $formatter, Stopwatch $stopwatch)
52
    {
53 4
        if (!($client instanceof HttpClient && $client instanceof HttpAsyncClient)) {
54
            throw new \RuntimeException(sprintf(
55
                '%s first argument must implement %s and %s. Consider using %s.',
56
                    __METHOD__,
57
                    HttpClient::class,
58
                    HttpAsyncClient::class,
59
                    FlexibleHttpClient::class
60
            ));
61
        }
62
        $this->client = $client;
63
        $this->collector = $collector;
64
        $this->formatter = $formatter;
65
        $this->stopwatch = $stopwatch;
66
    }
67
68
    /**
69
     * {@inheritdoc}
70
     */
71
    public function sendAsyncRequest(RequestInterface $request)
72
    {
73
        $stack = $this->collector->getCurrentStack();
74
        $this->collectRequestInformations($request, $stack);
75
        $event = $this->stopwatch->start($this->getStopwatchEventName($request));
76
77
        return $this->client->sendAsyncRequest($request)->then(
78
            function (ResponseInterface $response) use ($event, $stack) {
79
                $event->stop();
80
                $this->collectResponseInformations($response, $event, $stack);
81
82
                return $response;
83
            }, function (\Exception $exception) use ($event, $stack) {
84
                $this->collectExceptionInformations($exception, $event, $stack);
0 ignored issues
show
Bug introduced by
It seems like $stack defined by $this->collector->getCurrentStack() on line 73 can also be of type boolean; however, Http\HttplugBundle\Colle...ExceptionInformations() does only seem to accept null|object<Http\HttplugBundle\Collector\Stack>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
85
86
                throw $exception;
87
            }
88
        );
89
    }
90
91
    /**
92
     * {@inheritdoc}
93
     */
94
    public function sendRequest(RequestInterface $request)
95
    {
96
        $stack = $this->collector->getCurrentStack();
97
        $this->collectRequestInformations($request, $stack);
98
        $event = $this->stopwatch->start($this->getStopwatchEventName($request));
99
100
        try {
101
            $response = $this->client->sendRequest($request);
102
            $event->stop();
103
104
            $this->collectResponseInformations($response, $event, $stack);
105
106
            return $response;
107
        } catch (\Exception $e) {
108
            $event->stop();
109
            $this->collectExceptionInformations($e, $event, $stack);
110
111
            throw $e;
112
        }
113
    }
114
115
    /**
116
     * @param RequestInterface $request
117
     * @param Stack|null       $stack
118
     */
119
    private function collectRequestInformations(RequestInterface $request, Stack $stack = null)
120
    {
121
        if (!$stack) {
122
            return;
123
        }
124
125
        $stack->setRequestTarget($request->getRequestTarget());
126
        $stack->setRequestMethod($request->getMethod());
127
        $stack->setRequestScheme($request->getUri()->getScheme());
128
        $stack->setRequestHost($request->getUri()->getHost());
129
        $stack->setClientRequest($this->formatter->formatRequest($request));
130
    }
131
132
    /**
133
     * @param ResponseInterface $response
134
     * @param StopwatchEvent    $event
135
     * @param Stack|null        $stack
136
     */
137
    private function collectResponseInformations(ResponseInterface $response, StopwatchEvent $event, Stack $stack = null)
138
    {
139
        if (!$stack) {
140
            return;
141
        }
142
143
        $stack->setDuration($event->getDuration());
144
        $stack->setResponseCode($response->getStatusCode());
145
        $stack->setClientResponse($this->formatter->formatResponse($response));
146
    }
147
148
    /**
149
     * @param \Exception     $exception
150
     * @param StopwatchEvent $event
151
     * @param Stack|null     $stack
152
     */
153
    private function collectExceptionInformations(\Exception $exception, StopwatchEvent $event, Stack $stack = null)
154
    {
155
        if ($exception instanceof HttpException) {
156
            $this->collectResponseInformations($exception->getResponse(), $event, $stack);
157
        }
158
159
        if (!$stack) {
160
            return;
161
        }
162
163
        $stack->setDuration($event->getDuration());
164
        $stack->setClientException($this->formatter->formatException($exception));
165
    }
166
167
    /**
168
     * Generates the event name.
169
     *
170
     * @param RequestInterface $request
171
     *
172
     * @return string
173
     */
174
    private function getStopwatchEventName(RequestInterface $request)
175
    {
176
        return sprintf('%s %s', $request->getMethod(), $request->getUri()->__toString());
177
    }
178
}
179