PluginProbe
Plausible Analytics / trunk
Plausible Analytics vtrunk
2.6.1 2.6.0 trunk 1.0.0 1.0.1 1.1.0 1.2.0 1.2.1 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.3.0 1.3.1 1.3.2 1.3.3 1.3.4 1.3.5 1.3.6 2.0.0 2.0.1 2.0.2 2.0.3 2.0.4 All 52 releases
plausible-analytics / src / Client / lib / Lib / GuzzleHttp / Handler / MockHandler.php

MockHandler.php in Plausible Analytics trunk, at src/Client/lib/Lib/GuzzleHttp/Handler/MockHandler.php

213 lines 6.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Plausible\Analytics\WP\Client\Lib\GuzzleHttp\Handler;
4
5 use Plausible\Analytics\WP\Client\Lib\GuzzleHttp\Exception\RequestException;
6 use Plausible\Analytics\WP\Client\Lib\GuzzleHttp\HandlerStack;
7 use Plausible\Analytics\WP\Client\Lib\GuzzleHttp\Promise as P;
8 use Plausible\Analytics\WP\Client\Lib\GuzzleHttp\Promise\PromiseInterface;
9 use Plausible\Analytics\WP\Client\Lib\GuzzleHttp\TransferStats;
10 use Plausible\Analytics\WP\Client\Lib\GuzzleHttp\Utils;
11 use Plausible\Analytics\WP\Client\Lib\Psr\Http\Message\RequestInterface;
12 use Plausible\Analytics\WP\Client\Lib\Psr\Http\Message\ResponseInterface;
13 use Plausible\Analytics\WP\Client\Lib\Psr\Http\Message\StreamInterface;
14
15 /**
16 * Handler that returns responses or throw exceptions from a queue.
17 *
18 * @final
19 */
20 class MockHandler implements \Countable
21 {
22 /**
23 * @var array
24 */
25 private $queue = [];
26
27 /**
28 * @var RequestInterface|null
29 */
30 private $lastRequest;
31
32 /**
33 * @var array
34 */
35 private $lastOptions = [];
36
37 /**
38 * @var callable|null
39 */
40 private $onFulfilled;
41
42 /**
43 * @var callable|null
44 */
45 private $onRejected;
46
47 /**
48 * Creates a new MockHandler that uses the default handler stack list of
49 * middlewares.
50 *
51 * @param array|null $queue Array of responses, callables, or exceptions.
52 * @param callable|null $onFulfilled Callback to invoke when the return value is fulfilled.
53 * @param callable|null $onRejected Callback to invoke when the return value is rejected.
54 */
55 public static function createWithMiddleware( ?array $queue = null, ?callable $onFulfilled = null, ?callable $onRejected = null ): HandlerStack
56 {
57 return HandlerStack::create(new self($queue, $onFulfilled, $onRejected));
58 }
59
60 /**
61 * The passed in value must be an array of
62 * {@see \Plausible\Analytics\WP\Client\Lib\Psr\Http\Message\ResponseInterface} objects, Exceptions,
63 * callables, or Promises.
64 *
65 * @param array<int, mixed>|null $queue The parameters to be passed to the append function, as an indexed array.
66 * @param callable|null $onFulfilled Callback to invoke when the return value is fulfilled.
67 * @param callable|null $onRejected Callback to invoke when the return value is rejected.
68 */
69 public function __construct( ?array $queue = null, ?callable $onFulfilled = null, ?callable $onRejected = null )
70 {
71 $this->onFulfilled = $onFulfilled;
72 $this->onRejected = $onRejected;
73
74 if ($queue) {
75 // array_values included for BC
76 $this->append(...array_values($queue));
77 }
78 }
79
80 public function __invoke(RequestInterface $request, array $options): PromiseInterface
81 {
82 if (!$this->queue) {
83 throw new \OutOfBoundsException('Mock queue is empty');
84 }
85
86 if (isset($options['delay']) && \is_numeric($options['delay'])) {
87 \usleep((int) $options['delay'] * 1000);
88 }
89
90 $this->lastRequest = $request;
91 $this->lastOptions = $options;
92 $response = \array_shift($this->queue);
93
94 if (isset($options['on_headers'])) {
95 if (!\is_callable($options['on_headers'])) {
96 throw new \InvalidArgumentException('on_headers must be callable');
97 }
98 try {
99 $options['on_headers']($response);
100 } catch (\Exception $e) {
101 $msg = 'An error was encountered during the on_headers event';
102 $response = new RequestException($msg, $request, $response, $e);
103 }
104 }
105
106 if (\is_callable($response)) {
107 $response = $response($request, $options);
108 }
109
110 $response = $response instanceof \Throwable
111 ? P\Create::rejectionFor($response)
112 : P\Create::promiseFor($response);
113
114 return $response->then(
115 function (?ResponseInterface $value) use ($request, $options) {
116 $this->invokeStats($request, $options, $value);
117 if ($this->onFulfilled) {
118 ($this->onFulfilled)($value);
119 }
120
121 if ($value !== null && isset($options['sink'])) {
122 $contents = (string) $value->getBody();
123 $sink = $options['sink'];
124
125 if (\is_resource($sink)) {
126 \fwrite($sink, $contents);
127 } elseif (\is_string($sink)) {
128 \file_put_contents($sink, $contents);
129 } elseif ($sink instanceof StreamInterface) {
130 $sink->write($contents);
131 }
132 }
133
134 return $value;
135 },
136 function ($reason) use ($request, $options) {
137 $this->invokeStats($request, $options, null, $reason);
138 if ($this->onRejected) {
139 ($this->onRejected)($reason);
140 }
141
142 return P\Create::rejectionFor($reason);
143 }
144 );
145 }
146
147 /**
148 * Adds one or more variadic requests, exceptions, callables, or promises
149 * to the queue.
150 *
151 * @param mixed ...$values
152 */
153 public function append(...$values): void
154 {
155 foreach ($values as $value) {
156 if ($value instanceof ResponseInterface
157 || $value instanceof \Throwable
158 || $value instanceof PromiseInterface
159 || \is_callable($value)
160 ) {
161 $this->queue[] = $value;
162 } else {
163 throw new \TypeError('Expected a Response, Promise, Throwable or callable. Found '.Utils::describeType($value));
164 }
165 }
166 }
167
168 /**
169 * Get the last received request.
170 */
171 public function getLastRequest(): ?RequestInterface
172 {
173 return $this->lastRequest;
174 }
175
176 /**
177 * Get the last received request options.
178 */
179 public function getLastOptions(): array
180 {
181 return $this->lastOptions;
182 }
183
184 /**
185 * Returns the number of remaining items in the queue.
186 */
187 public function count(): int
188 {
189 return \count($this->queue);
190 }
191
192 public function reset(): void
193 {
194 $this->queue = [];
195 }
196
197 /**
198 * @param mixed $reason Promise or reason.
199 */
200 private function invokeStats(
201 RequestInterface $request,
202 array $options,
203 ?ResponseInterface $response = null,
204 $reason = null
205 ): void {
206 if (isset($options['on_stats'])) {
207 $transferTime = $options['transfer_time'] ?? 0;
208 $stats = new TransferStats($request, $response, $transferTime, $reason);
209 ($options['on_stats'])($stats);
210 }
211 }
212 }
213