Completed
Pull Request — master (#1867)
by
unknown
02:27
created

MockHandler   A

Complexity

Total Complexity 28

Size/Duplication

Total Lines 175
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 4

Importance

Changes 0
Metric Value
dl 0
loc 175
rs 10
c 0
b 0
f 0
wmc 28
lcom 1
cbo 4

8 Methods

Rating   Name   Duplication   Size   Complexity  
A createWithMiddleware() 0 7 1
A __construct() 0 12 2
C __invoke() 0 64 14
A append() 0 15 6
A getLastRequest() 0 4 1
A getLastOptions() 0 4 1
A count() 0 4 1
A invokeStats() 0 11 2
1
<?php
2
namespace GuzzleHttp\Handler;
3
4
use GuzzleHttp\Exception\RequestException;
5
use GuzzleHttp\HandlerStack;
6
use GuzzleHttp\Promise\PromiseInterface;
7
use GuzzleHttp\Promise\RejectedPromise;
8
use GuzzleHttp\TransferStats;
9
use Psr\Http\Message\RequestInterface;
10
use Psr\Http\Message\ResponseInterface;
11
12
/**
13
 * Handler that returns responses or throw exceptions from a queue.
14
 */
15
class MockHandler implements \Countable
16
{
17
    private $queue = [];
18
    private $lastRequest;
19
    private $lastOptions;
20
    private $onFulfilled;
21
    private $onRejected;
22
23
    /**
24
     * Creates a new MockHandler that uses the default handler stack list of
25
     * middlewares.
26
     *
27
     * @param array $queue Array of responses, callables, or exceptions.
28
     * @param callable $onFulfilled Callback to invoke when the return value is fulfilled.
29
     * @param callable $onRejected  Callback to invoke when the return value is rejected.
30
     *
31
     * @return HandlerStack
32
     */
33
    public static function createWithMiddleware(
34
        array $queue = null,
35
        callable $onFulfilled = null,
36
        callable $onRejected = null
37
    ) {
38
        return HandlerStack::create(new self($queue, $onFulfilled, $onRejected));
39
    }
40
41
    /**
42
     * The passed in value must be an array of
43
     * {@see Psr7\Http\Message\ResponseInterface} objects, Exceptions,
44
     * callables, or Promises.
45
     *
46
     * @param array $queue
47
     * @param callable $onFulfilled Callback to invoke when the return value is fulfilled.
48
     * @param callable $onRejected  Callback to invoke when the return value is rejected.
49
     */
50
    public function __construct(
51
        array $queue = null,
52
        callable $onFulfilled = null,
53
        callable $onRejected = null
54
    ) {
55
        $this->onFulfilled = $onFulfilled;
56
        $this->onRejected = $onRejected;
57
58
        if ($queue) {
59
            call_user_func_array([$this, 'append'], $queue);
60
        }
61
    }
62
63
    public function __invoke(RequestInterface $request, array $options)
64
    {
65
        if (!$this->queue) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->queue of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
66
            throw new \OutOfBoundsException('Mock queue is empty');
67
        }
68
69
        if (isset($options['delay'])) {
70
            usleep($options['delay'] * 1000);
71
        }
72
73
        $this->lastRequest = $request;
74
        $this->lastOptions = $options;
75
        $response = array_shift($this->queue);
76
77
        if (isset($options['on_headers'])) {
78
            if (!is_callable($options['on_headers'])) {
79
                throw new \InvalidArgumentException('on_headers must be callable');
80
            }
81
            try {
82
                $options['on_headers']($response);
83
            } catch (\Exception $e) {
84
                $msg = 'An error was encountered during the on_headers event';
85
                $response = new RequestException($msg, $request, $response, $e);
86
            }
87
        }
88
89
        if (is_callable($response)) {
90
            $response = call_user_func($response, $request, $options);
91
        }
92
93
        $response = $response instanceof \Exception
94
            ? \GuzzleHttp\Promise\rejection_for($response)
95
            : \GuzzleHttp\Promise\promise_for($response);
96
97
        return $response->then(
98
            function ($value) use ($request, $options) {
99
                $this->invokeStats($request, $options, $value);
100
                if ($this->onFulfilled) {
101
                    call_user_func($this->onFulfilled, $value);
102
                }
103
                if (isset($options['sink'])) {
104
                    $contents = (string) $value->getBody();
105
                    $sink = $options['sink'];
106
107
                    if (is_resource($sink)) {
108
                        fwrite($sink, $contents);
109
                    } elseif (is_string($sink)) {
110
                        file_put_contents($sink, $contents);
111
                    } elseif ($sink instanceof \Psr\Http\Message\StreamInterface) {
112
                        $sink->write($contents);
113
                    }
114
                }
115
116
                return $value;
117
            },
118
            function ($reason) use ($request, $options) {
119
                $this->invokeStats($request, $options, null, $reason);
120
                if ($this->onRejected) {
121
                    call_user_func($this->onRejected, $reason);
122
                }
123
                return \GuzzleHttp\Promise\rejection_for($reason);
124
            }
125
        );
126
    }
127
128
    /**
129
     * Adds one or more variadic requests, exceptions, callables, or promises
130
     * to the queue.
131
     */
132
    public function append()
133
    {
134
        foreach (func_get_args() as $value) {
135
            if ($value instanceof ResponseInterface
136
                || $value instanceof \Exception
137
                || $value instanceof PromiseInterface
138
                || is_callable($value)
139
            ) {
140
                $this->queue[] = $value;
141
            } else {
142
                throw new \InvalidArgumentException('Expected a response or '
143
                    . 'exception. Found ' . \GuzzleHttp\describe_type($value));
144
            }
145
        }
146
    }
147
148
    /**
149
     * Get the last received request.
150
     *
151
     * @return RequestInterface
152
     */
153
    public function getLastRequest()
154
    {
155
        return $this->lastRequest;
156
    }
157
158
    /**
159
     * Get the last received request options.
160
     *
161
     * @return array
162
     */
163
    public function getLastOptions()
164
    {
165
        return $this->lastOptions;
166
    }
167
168
    /**
169
     * Returns the number of remaining items in the queue.
170
     *
171
     * @return int
172
     */
173
    public function count()
174
    {
175
        return count($this->queue);
176
    }
177
178
    private function invokeStats(
179
        RequestInterface $request,
180
        array $options,
181
        ResponseInterface $response = null,
182
        $reason = null
183
    ) {
184
        if (isset($options['on_stats'])) {
185
            $stats = new TransferStats($request, $response, 0, $reason);
186
            call_user_func($options['on_stats'], $stats);
187
        }
188
    }
189
}
190