Completed
Push — master ( 19ccef...73f17d )
by Fabien
07:49 queued 12s
created

ProfileClient::collectResponseInformations()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
dl 0
loc 9
ccs 0
cts 0
cp 0
rs 9.6666
c 0
b 0
f 0
cc 2
eloc 5
nc 2
nop 2
crap 6
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
12
/**
13
 * The ProfileClient decorates any client that implement both HttpClient and HttpAsyncClient interfaces to gather target
14
 * url and response status code.
15
 *
16
 * @author Fabien Bourigault <[email protected]>
17
 *
18
 * @internal
19
 */
20
class ProfileClient implements HttpClient, HttpAsyncClient
21
{
22
    /**
23
     * @var HttpClient|HttpAsyncClient
24
     */
25
    private $client;
26
27
    /**
28
     * @var Collector
29
     */
30
    private $collector;
31
32
    /**
33
     * @var Formatter
34
     */
35
    private $formatter;
36
37
    /**
38
     * @param HttpClient|HttpAsyncClient $client    The client to profile. Client must implement both HttpClient and
39
     *                                              HttpAsyncClient interfaces.
40
     * @param Collector                  $collector
41
     * @param Formatter                  $formatter
42
     */
43 4
    public function __construct($client, Collector $collector, Formatter $formatter)
44
    {
45 4
        if (!($client instanceof HttpClient && $client instanceof HttpAsyncClient)) {
46
            throw new \RuntimeException(sprintf(
47
                '%s first argument must implement %s and %s. Consider using %s.',
48
                    __METHOD__,
49
                    HttpClient::class,
50
                    HttpAsyncClient::class,
51
                    FlexibleHttpClient::class
52
            ));
53
        }
54
        $this->client = $client;
55
        $this->collector = $collector;
56
        $this->formatter = $formatter;
57
    }
58
59
    /**
60
     * {@inheritdoc}
61
     */
62
    public function sendAsyncRequest(RequestInterface $request)
63
    {
64
        $stack = $this->collector->getCurrentStack();
65
        $this->collectRequestInformations($request, $stack);
0 ignored issues
show
Bug introduced by
It seems like $stack defined by $this->collector->getCurrentStack() on line 64 can also be of type boolean; however, Http\HttplugBundle\Colle...ctRequestInformations() 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...
66
67
        return $this->client->sendAsyncRequest($request)->then(function (ResponseInterface $response) use ($stack) {
0 ignored issues
show
Bug introduced by
The method sendAsyncRequest does only exist in Http\Client\HttpAsyncClient, but not in Http\Client\HttpClient.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
68
            $this->collectResponseInformations($response, $stack);
0 ignored issues
show
Bug introduced by
It seems like $stack defined by $this->collector->getCurrentStack() on line 64 can also be of type boolean; however, Http\HttplugBundle\Colle...tResponseInformations() 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...
69
70
            return $response;
71
        }, function (\Exception $exception) use ($stack) {
72
            $this->collectExceptionInformations($exception, $stack);
0 ignored issues
show
Bug introduced by
It seems like $stack defined by $this->collector->getCurrentStack() on line 64 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...
73
74
            throw $exception;
75
        });
76
    }
77
78
    /**
79
     * {@inheritdoc}
80
     */
81
    public function sendRequest(RequestInterface $request)
82
    {
83
        $stack = $this->collector->getCurrentStack();
84
        $this->collectRequestInformations($request, $stack);
0 ignored issues
show
Bug introduced by
It seems like $stack defined by $this->collector->getCurrentStack() on line 83 can also be of type boolean; however, Http\HttplugBundle\Colle...ctRequestInformations() 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
        try {
87
            $response = $this->client->sendRequest($request);
0 ignored issues
show
Bug introduced by
The method sendRequest does only exist in Http\Client\HttpClient, but not in Http\Client\HttpAsyncClient.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
88
89
            $this->collectResponseInformations($response, $stack);
0 ignored issues
show
Bug introduced by
It seems like $stack defined by $this->collector->getCurrentStack() on line 83 can also be of type boolean; however, Http\HttplugBundle\Colle...tResponseInformations() 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...
90
91
            return $response;
92
        } catch (\Exception $e) {
93
            $this->collectExceptionInformations($e, $stack);
0 ignored issues
show
Bug introduced by
It seems like $stack defined by $this->collector->getCurrentStack() on line 83 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...
94
95
            throw $e;
96
        }
97
    }
98
99
    /**
100
     * @param RequestInterface $request
101
     * @param Stack|null       $stack
102
     */
103
    private function collectRequestInformations(RequestInterface $request, Stack $stack = null)
104
    {
105
        if (!$stack) {
106
            return;
107
        }
108
109
        $stack->setRequestTarget($request->getRequestTarget());
110
        $stack->setRequestMethod($request->getMethod());
111
        $stack->setRequestScheme($request->getUri()->getScheme());
112
        $stack->setRequestHost($request->getUri()->getHost());
113
        $stack->setClientRequest($this->formatter->formatRequest($request));
114
    }
115
116
    /**
117
     * @param ResponseInterface $response
118
     * @param Stack|null        $stack
119
     */
120
    private function collectResponseInformations(ResponseInterface $response, Stack $stack = null)
121
    {
122
        if (!$stack) {
123
            return;
124
        }
125
126
        $stack->setResponseCode($response->getStatusCode());
127
        $stack->setClientResponse($this->formatter->formatResponse($response));
128
    }
129
130
    /**
131
     * @param \Exception $exception
132
     * @param Stack|null $stack
133
     */
134
    private function collectExceptionInformations(\Exception $exception, Stack $stack = null)
135
    {
136
        if ($exception instanceof HttpException) {
137
            $this->collectResponseInformations($exception->getResponse(), $stack);
138
        }
139
140
        if (!$stack) {
141
            return;
142
        }
143
144
        $stack->setClientException($this->formatter->formatException($exception));
145
    }
146
}
147