PluginProbe
Depicter — Popup & Slider Builder / 1.9.6
Depicter — Popup & Slider Builder v1.9.6
4.8.1 trunk 1.0.0 1.1.0 1.1.2 1.1.4 1.1.6 1.1.7 1.1.8 1.1.9 1.2.0 1.3.0 1.3.1 1.3.2 1.3.3 1.3.5 1.3.8 1.5.0 1.5.1 1.5.2 1.5.5 1.6.0 1.6.1 1.6.2 1.7.0 All 76 releases
depicter / modules / GuzzleHttp / HandlerStack.php

HandlerStack.php in Depicter — Popup & Slider Builder 1.9.6, at modules/GuzzleHttp/HandlerStack.php

276 lines 8.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Depicter\GuzzleHttp;
4
5 use Depicter\GuzzleHttp\Promise\PromiseInterface;
6 use Depicter\Psr\Http\Message\RequestInterface;
7 use Depicter\Psr\Http\Message\ResponseInterface;
8
9 /**
10 * Creates a composed Guzzle handler function by stacking middlewares on top of
11 * an HTTP handler function.
12 *
13 * @final
14 */
15 class HandlerStack
16 {
17 /**
18 * @var (callable(RequestInterface, array): PromiseInterface)|null
19 */
20 private $handler;
21
22 /**
23 * @var array{(callable(callable(RequestInterface, array): PromiseInterface): callable), (string|null)}[]
24 */
25 private $stack = [];
26
27 /**
28 * @var (callable(RequestInterface, array): PromiseInterface)|null
29 */
30 private $cached;
31
32 /**
33 * Creates a default handler stack that can be used by clients.
34 *
35 * The returned handler will wrap the provided handler or use the most
36 * appropriate default handler for your system. The returned HandlerStack has
37 * support for cookies, redirects, HTTP error exceptions, and preparing a body
38 * before sending.
39 *
40 * The returned handler stack can be passed to a client in the "handler"
41 * option.
42 *
43 * @param (callable(RequestInterface, array): PromiseInterface)|null $handler HTTP handler function to use with the stack. If no
44 * handler is provided, the best handler for your
45 * system will be utilized.
46 */
47 public static function create(?callable $handler = null): self
48 {
49 $stack = new self($handler ?: Utils::chooseHandler());
50 $stack->push(Middleware::httpErrors(), 'http_errors');
51 $stack->push(Middleware::redirect(), 'allow_redirects');
52 $stack->push(Middleware::cookies(), 'cookies');
53 $stack->push(Middleware::prepareBody(), 'prepare_body');
54
55 return $stack;
56 }
57
58 /**
59 * @param (callable(RequestInterface, array): PromiseInterface)|null $handler Underlying HTTP handler.
60 */
61 public function __construct(callable $handler = null)
62 {
63 $this->handler = $handler;
64 }
65
66 /**
67 * Invokes the handler stack as a composed handler
68 *
69 * @return ResponseInterface|PromiseInterface
70 */
71 public function __invoke(RequestInterface $request, array $options)
72 {
73 $handler = $this->resolve();
74
75 return $handler($request, $options);
76 }
77
78 /**
79 * Dumps a string representation of the stack.
80 *
81 * @return string
82 */
83 public function __toString()
84 {
85 $depth = 0;
86 $stack = [];
87
88 if ($this->handler !== null) {
89 $stack[] = "0) Handler: " . $this->debugCallable($this->handler);
90 }
91
92 $result = '';
93 foreach (\array_reverse($this->stack) as $tuple) {
94 $depth++;
95 $str = "{$depth}) Name: '{$tuple[1]}', ";
96 $str .= "Function: " . $this->debugCallable($tuple[0]);
97 $result = "> {$str}\n{$result}";
98 $stack[] = $str;
99 }
100
101 foreach (\array_keys($stack) as $k) {
102 $result .= "< {$stack[$k]}\n";
103 }
104
105 return $result;
106 }
107
108 /**
109 * Set the HTTP handler that actually returns a promise.
110 *
111 * @param callable(RequestInterface, array): PromiseInterface $handler Accepts a request and array of options and
112 * returns a Promise.
113 */
114 public function setHandler(callable $handler): void
115 {
116 $this->handler = $handler;
117 $this->cached = null;
118 }
119
120 /**
121 * Returns true if the builder has a handler.
122 */
123 public function hasHandler(): bool
124 {
125 return $this->handler !== null ;
126 }
127
128 /**
129 * Unshift a middleware to the bottom of the stack.
130 *
131 * @param callable(callable): callable $middleware Middleware function
132 * @param string $name Name to register for this middleware.
133 */
134 public function unshift(callable $middleware, ?string $name = null): void
135 {
136 \array_unshift($this->stack, [$middleware, $name]);
137 $this->cached = null;
138 }
139
140 /**
141 * Push a middleware to the top of the stack.
142 *
143 * @param callable(callable): callable $middleware Middleware function
144 * @param string $name Name to register for this middleware.
145 */
146 public function push(callable $middleware, string $name = ''): void
147 {
148 $this->stack[] = [$middleware, $name];
149 $this->cached = null;
150 }
151
152 /**
153 * Add a middleware before another middleware by name.
154 *
155 * @param string $findName Middleware to find
156 * @param callable(callable): callable $middleware Middleware function
157 * @param string $withName Name to register for this middleware.
158 */
159 public function before(string $findName, callable $middleware, string $withName = ''): void
160 {
161 $this->splice($findName, $withName, $middleware, true);
162 }
163
164 /**
165 * Add a middleware after another middleware by name.
166 *
167 * @param string $findName Middleware to find
168 * @param callable(callable): callable $middleware Middleware function
169 * @param string $withName Name to register for this middleware.
170 */
171 public function after(string $findName, callable $middleware, string $withName = ''): void
172 {
173 $this->splice($findName, $withName, $middleware, false);
174 }
175
176 /**
177 * Remove a middleware by instance or name from the stack.
178 *
179 * @param callable|string $remove Middleware to remove by instance or name.
180 */
181 public function remove($remove): void
182 {
183 if (!is_string($remove) && !is_callable($remove)) {
184 trigger_deprecation('guzzlehttp/guzzle', '7.4', 'Not passing a callable or string to %s::%s() is deprecated and will cause an error in 8.0.', __CLASS__, __FUNCTION__);
185 }
186
187 $this->cached = null;
188 $idx = \is_callable($remove) ? 0 : 1;
189 $this->stack = \array_values(\array_filter(
190 $this->stack,
191 static function ($tuple) use ($idx, $remove) {
192 return $tuple[$idx] !== $remove;
193 }
194 ));
195 }
196
197 /**
198 * Compose the middleware and handler into a single callable function.
199 *
200 * @return callable(RequestInterface, array): PromiseInterface
201 */
202 public function resolve(): callable
203 {
204 if ($this->cached === null) {
205 if (($prev = $this->handler) === null) {
206 throw new \LogicException('No handler has been specified');
207 }
208
209 foreach (\array_reverse($this->stack) as $fn) {
210 /** @var callable(RequestInterface, array): PromiseInterface $prev */
211 $prev = $fn[0]($prev);
212 }
213
214 $this->cached = $prev;
215 }
216
217 return $this->cached;
218 }
219
220 private function findByName(string $name): int
221 {
222 foreach ($this->stack as $k => $v) {
223 if ($v[1] === $name) {
224 return $k;
225 }
226 }
227
228 throw new \InvalidArgumentException("Middleware not found: $name");
229 }
230
231 /**
232 * Splices a function into the middleware list at a specific position.
233 */
234 private function splice(string $findName, string $withName, callable $middleware, bool $before): void
235 {
236 $this->cached = null;
237 $idx = $this->findByName($findName);
238 $tuple = [$middleware, $withName];
239
240 if ($before) {
241 if ($idx === 0) {
242 \array_unshift($this->stack, $tuple);
243 } else {
244 $replacement = [$tuple, $this->stack[$idx]];
245 \array_splice($this->stack, $idx, 1, $replacement);
246 }
247 } elseif ($idx === \count($this->stack) - 1) {
248 $this->stack[] = $tuple;
249 } else {
250 $replacement = [$this->stack[$idx], $tuple];
251 \array_splice($this->stack, $idx, 1, $replacement);
252 }
253 }
254
255 /**
256 * Provides a debug string for a given callable.
257 *
258 * @param callable|string $fn Function to write as a string.
259 */
260 private function debugCallable($fn): string
261 {
262 if (\is_string($fn)) {
263 return "callable({$fn})";
264 }
265
266 if (\is_array($fn)) {
267 return \is_string($fn[0])
268 ? "callable({$fn[0]}::{$fn[1]})"
269 : "callable(['" . \get_class($fn[0]) . "', '{$fn[1]}'])";
270 }
271
272 /** @var object $fn */
273 return 'callable(' . \spl_object_hash($fn) . ')';
274 }
275 }
276