| 1 | 1 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,212 @@ |
| 1 |
+<?php |
|
| 2 |
+ |
|
| 3 |
+namespace GuzzleHttp\Handler; |
|
| 4 |
+ |
|
| 5 |
+use GuzzleHttp\Exception\RequestException; |
|
| 6 |
+use GuzzleHttp\HandlerStack; |
|
| 7 |
+use GuzzleHttp\Promise as P; |
|
| 8 |
+use GuzzleHttp\Promise\PromiseInterface; |
|
| 9 |
+use GuzzleHttp\TransferStats; |
|
| 10 |
+use GuzzleHttp\Utils; |
|
| 11 |
+use Psr\Http\Message\RequestInterface; |
|
| 12 |
+use Psr\Http\Message\ResponseInterface; |
|
| 13 |
+use 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 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 |
+} |
| 1 | 1 |
deleted file mode 100644 |
| ... | ... |
@@ -1,211 +0,0 @@ |
| 1 |
-<?php |
|
| 2 |
- |
|
| 3 |
-namespace GuzzleHttp\Handler; |
|
| 4 |
- |
|
| 5 |
-use GuzzleHttp\Exception\RequestException; |
|
| 6 |
-use GuzzleHttp\HandlerStack; |
|
| 7 |
-use GuzzleHttp\Promise as P; |
|
| 8 |
-use GuzzleHttp\Promise\PromiseInterface; |
|
| 9 |
-use GuzzleHttp\TransferStats; |
|
| 10 |
-use GuzzleHttp\Utils; |
|
| 11 |
-use Psr\Http\Message\RequestInterface; |
|
| 12 |
-use Psr\Http\Message\ResponseInterface; |
|
| 13 |
-use 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 \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 |
- return P\Create::rejectionFor($reason); |
|
| 142 |
- } |
|
| 143 |
- ); |
|
| 144 |
- } |
|
| 145 |
- |
|
| 146 |
- /** |
|
| 147 |
- * Adds one or more variadic requests, exceptions, callables, or promises |
|
| 148 |
- * to the queue. |
|
| 149 |
- * |
|
| 150 |
- * @param mixed ...$values |
|
| 151 |
- */ |
|
| 152 |
- public function append(...$values): void |
|
| 153 |
- {
|
|
| 154 |
- foreach ($values as $value) {
|
|
| 155 |
- if ($value instanceof ResponseInterface |
|
| 156 |
- || $value instanceof \Throwable |
|
| 157 |
- || $value instanceof PromiseInterface |
|
| 158 |
- || \is_callable($value) |
|
| 159 |
- ) {
|
|
| 160 |
- $this->queue[] = $value; |
|
| 161 |
- } else {
|
|
| 162 |
- throw new \TypeError('Expected a Response, Promise, Throwable or callable. Found ' . Utils::describeType($value));
|
|
| 163 |
- } |
|
| 164 |
- } |
|
| 165 |
- } |
|
| 166 |
- |
|
| 167 |
- /** |
|
| 168 |
- * Get the last received request. |
|
| 169 |
- */ |
|
| 170 |
- public function getLastRequest(): ?RequestInterface |
|
| 171 |
- {
|
|
| 172 |
- return $this->lastRequest; |
|
| 173 |
- } |
|
| 174 |
- |
|
| 175 |
- /** |
|
| 176 |
- * Get the last received request options. |
|
| 177 |
- */ |
|
| 178 |
- public function getLastOptions(): array |
|
| 179 |
- {
|
|
| 180 |
- return $this->lastOptions; |
|
| 181 |
- } |
|
| 182 |
- |
|
| 183 |
- /** |
|
| 184 |
- * Returns the number of remaining items in the queue. |
|
| 185 |
- */ |
|
| 186 |
- public function count(): int |
|
| 187 |
- {
|
|
| 188 |
- return \count($this->queue); |
|
| 189 |
- } |
|
| 190 |
- |
|
| 191 |
- public function reset(): void |
|
| 192 |
- {
|
|
| 193 |
- $this->queue = []; |
|
| 194 |
- } |
|
| 195 |
- |
|
| 196 |
- /** |
|
| 197 |
- * @param mixed $reason Promise or reason. |
|
| 198 |
- */ |
|
| 199 |
- private function invokeStats( |
|
| 200 |
- RequestInterface $request, |
|
| 201 |
- array $options, |
|
| 202 |
- ResponseInterface $response = null, |
|
| 203 |
- $reason = null |
|
| 204 |
- ): void {
|
|
| 205 |
- if (isset($options['on_stats'])) {
|
|
| 206 |
- $transferTime = $options['transfer_time'] ?? 0; |
|
| 207 |
- $stats = new TransferStats($request, $response, $transferTime, $reason); |
|
| 208 |
- ($options['on_stats'])($stats); |
|
| 209 |
- } |
|
| 210 |
- } |
|
| 211 |
-} |
| 1 | 1 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,211 @@ |
| 1 |
+<?php |
|
| 2 |
+ |
|
| 3 |
+namespace GuzzleHttp\Handler; |
|
| 4 |
+ |
|
| 5 |
+use GuzzleHttp\Exception\RequestException; |
|
| 6 |
+use GuzzleHttp\HandlerStack; |
|
| 7 |
+use GuzzleHttp\Promise as P; |
|
| 8 |
+use GuzzleHttp\Promise\PromiseInterface; |
|
| 9 |
+use GuzzleHttp\TransferStats; |
|
| 10 |
+use GuzzleHttp\Utils; |
|
| 11 |
+use Psr\Http\Message\RequestInterface; |
|
| 12 |
+use Psr\Http\Message\ResponseInterface; |
|
| 13 |
+use 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 \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 |
+ return P\Create::rejectionFor($reason); |
|
| 142 |
+ } |
|
| 143 |
+ ); |
|
| 144 |
+ } |
|
| 145 |
+ |
|
| 146 |
+ /** |
|
| 147 |
+ * Adds one or more variadic requests, exceptions, callables, or promises |
|
| 148 |
+ * to the queue. |
|
| 149 |
+ * |
|
| 150 |
+ * @param mixed ...$values |
|
| 151 |
+ */ |
|
| 152 |
+ public function append(...$values): void |
|
| 153 |
+ {
|
|
| 154 |
+ foreach ($values as $value) {
|
|
| 155 |
+ if ($value instanceof ResponseInterface |
|
| 156 |
+ || $value instanceof \Throwable |
|
| 157 |
+ || $value instanceof PromiseInterface |
|
| 158 |
+ || \is_callable($value) |
|
| 159 |
+ ) {
|
|
| 160 |
+ $this->queue[] = $value; |
|
| 161 |
+ } else {
|
|
| 162 |
+ throw new \TypeError('Expected a Response, Promise, Throwable or callable. Found ' . Utils::describeType($value));
|
|
| 163 |
+ } |
|
| 164 |
+ } |
|
| 165 |
+ } |
|
| 166 |
+ |
|
| 167 |
+ /** |
|
| 168 |
+ * Get the last received request. |
|
| 169 |
+ */ |
|
| 170 |
+ public function getLastRequest(): ?RequestInterface |
|
| 171 |
+ {
|
|
| 172 |
+ return $this->lastRequest; |
|
| 173 |
+ } |
|
| 174 |
+ |
|
| 175 |
+ /** |
|
| 176 |
+ * Get the last received request options. |
|
| 177 |
+ */ |
|
| 178 |
+ public function getLastOptions(): array |
|
| 179 |
+ {
|
|
| 180 |
+ return $this->lastOptions; |
|
| 181 |
+ } |
|
| 182 |
+ |
|
| 183 |
+ /** |
|
| 184 |
+ * Returns the number of remaining items in the queue. |
|
| 185 |
+ */ |
|
| 186 |
+ public function count(): int |
|
| 187 |
+ {
|
|
| 188 |
+ return \count($this->queue); |
|
| 189 |
+ } |
|
| 190 |
+ |
|
| 191 |
+ public function reset(): void |
|
| 192 |
+ {
|
|
| 193 |
+ $this->queue = []; |
|
| 194 |
+ } |
|
| 195 |
+ |
|
| 196 |
+ /** |
|
| 197 |
+ * @param mixed $reason Promise or reason. |
|
| 198 |
+ */ |
|
| 199 |
+ private function invokeStats( |
|
| 200 |
+ RequestInterface $request, |
|
| 201 |
+ array $options, |
|
| 202 |
+ ResponseInterface $response = null, |
|
| 203 |
+ $reason = null |
|
| 204 |
+ ): void {
|
|
| 205 |
+ if (isset($options['on_stats'])) {
|
|
| 206 |
+ $transferTime = $options['transfer_time'] ?? 0; |
|
| 207 |
+ $stats = new TransferStats($request, $response, $transferTime, $reason); |
|
| 208 |
+ ($options['on_stats'])($stats); |
|
| 209 |
+ } |
|
| 210 |
+ } |
|
| 211 |
+} |