Completed
Push — master ( 6dcd59...79f11a )
by David
14s
created

src/Client.php (1 issue)

Severity

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
namespace Http\Mock;
4
5
use Http\Client\Common\HttpAsyncClientEmulator;
6
use Http\Client\Common\VersionBridgeClient;
7
use Http\Client\Exception;
8
use Http\Client\HttpAsyncClient;
9
use Http\Client\HttpClient;
10
use Http\Discovery\MessageFactoryDiscovery;
11
use Http\Message\RequestMatcher;
12
use Http\Message\ResponseFactory;
13
use Psr\Http\Client\ClientExceptionInterface;
14
use Psr\Http\Message\RequestInterface;
15
use Psr\Http\Message\ResponseInterface;
16
17
/**
18
 * An implementation of the HTTP client that is useful for automated tests.
19
 *
20
 * This mock does not send requests but stores them for later retrieval.
21
 * You can configure the mock with responses to return and/or exceptions to throw.
22
 *
23
 * @author David de Boer <[email protected]>
24
 */
25
class Client implements HttpClient, HttpAsyncClient
26
{
27
    use HttpAsyncClientEmulator;
28
    use VersionBridgeClient;
29
30
    /**
31
     * @var ResponseFactory
32
     */
33
    private $responseFactory;
34
35
    /**
36
     * @var array
37
     */
38
    private $conditionalResults = [];
39
40
    /**
41
     * @var RequestInterface[]
42
     */
43
    private $requests = [];
44
45
    /**
46
     * @var ResponseInterface[]
47
     */
48
    private $responses = [];
49
50
    /**
51
     * @var ResponseInterface|null
52
     */
53
    private $defaultResponse;
54
55
    /**
56
     * @var Exception[]
57
     */
58
    private $exceptions = [];
59
60
    /**
61
     * @var Exception|null
62
     */
63
    private $defaultException;
64
65 15
    public function __construct(ResponseFactory $responseFactory = null)
66
    {
67 15
        $this->responseFactory = $responseFactory ?: MessageFactoryDiscovery::find();
68 15
    }
69
70
    /**
71
     * {@inheritdoc}
72
     */
73 11
    public function doSendRequest(RequestInterface $request)
74
    {
75 11
        $this->requests[] = $request;
76
77 11
        foreach ($this->conditionalResults as $result) {
78
            /**
79
             * @var RequestMatcher
80
             */
81 4
            $matcher = $result['matcher'];
82
83
            /**
84
             * @var callable
85
             */
86 4
            $callable = $result['callable'];
87
88 4
            if ($matcher->matches($request)) {
89 4
                return $callable($request);
90
            }
91
        }
92
93 8
        if (count($this->exceptions) > 0) {
94 1
            throw array_shift($this->exceptions);
95
        }
96
97 7
        if (count($this->responses) > 0) {
98 3
            return array_shift($this->responses);
99
        }
100
101 4
        if ($this->defaultException) {
102 1
            throw $this->defaultException;
103
        }
104
105 3
        if ($this->defaultResponse) {
106 1
            return $this->defaultResponse;
107
        }
108
109
        // Return success response by default
110 2
        return $this->responseFactory->createResponse();
111
    }
112
113
    /**
114
     * Adds an exception to be thrown or response to be returned if the request
115
     * matcher matches.
116
     *
117
     * For more complex logic, pass a callable as $result. The method is given
118
     * the request and MUST either return a ResponseInterface or throw an
119
     * exception that implements the PSR-18 / HTTPlug exception interface.
120
     *
121
     * @param ResponseInterface|Exception|ClientExceptionInterface|callable $result
122
     */
123 4
    public function on(RequestMatcher $requestMatcher, $result)
124
    {
125 4
        $callable = null;
0 ignored issues
show
$callable is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
126
127
        switch (true) {
128 4
            case is_callable($result):
129 1
                $callable = $result;
130
131 1
                break;
132 3
            case $result instanceof ResponseInterface:
133
                $callable = function () use ($result) {
134 1
                    return $result;
135 2
                };
136
137 2
                break;
138 1
            case $result instanceof \Exception:
139 1
                $callable = function () use ($result) {
140 1
                    throw $result;
141 1
                };
142
143 1
                break;
144
            default:
145
                throw new \InvalidArgumentException('Result must be either a response, an exception, or a callable');
146
        }
147 4
        $this->conditionalResults[] = [
148 4
            'matcher' => $requestMatcher,
149 4
            'callable' => $callable,
150
        ];
151 4
    }
152
153
    /**
154
     * Adds an exception that will be thrown.
155
     */
156 2 View Code Duplication
    public function addException(\Exception $exception)
157
    {
158 2
        if (!$exception instanceof Exception) {
159
            @trigger_error('Clients may only throw exceptions of type '.Exception::class.'. Setting an exception of class '.get_class($exception).' will not be possible anymore in the future', E_USER_DEPRECATED);
160
        }
161
        $this->exceptions[] = $exception;
162
    }
163
164
    /**
165
     * Sets the default exception to throw when the list of added exceptions and responses is exhausted.
166
     *
167
     * If both a default exception and a default response are set, the exception will be thrown.
168
     */
169 View Code Duplication
    public function setDefaultException(\Exception $defaultException = null)
170
    {
171
        if (!$defaultException instanceof Exception) {
172
            @trigger_error('Clients may only throw exceptions of type '.Exception::class.'. Setting an exception of class '.get_class($defaultException).' will not be possible anymore in the future', E_USER_DEPRECATED);
173
        }
174
        $this->defaultException = $defaultException;
175
    }
176
177
    /**
178
     * Adds a response that will be returned in first in first out order.
179
     */
180
    public function addResponse(ResponseInterface $response)
181
    {
182
        $this->responses[] = $response;
183
    }
184
185
    /**
186
     * Sets the default response to be returned when the list of added exceptions and responses is exhausted.
187
     */
188
    public function setDefaultResponse(ResponseInterface $defaultResponse = null)
189
    {
190
        $this->defaultResponse = $defaultResponse;
191
    }
192
193
    /**
194
     * Returns requests that were sent.
195
     *
196
     * @return RequestInterface[]
197
     */
198
    public function getRequests()
199
    {
200
        return $this->requests;
201
    }
202
203
    public function getLastRequest()
204
    {
205
        return end($this->requests);
206
    }
207
208
    public function reset()
209
    {
210
        $this->responses = [];
211
        $this->exceptions = [];
212
        $this->requests = [];
213
        $this->setDefaultException();
214
        $this->setDefaultResponse();
215
    }
216
}
217