PluginProbe
Media Cloud Sync / 1.2.12
Media Cloud Sync v1.2.12
1.4.0 1.3.12 1.3.11 1.3.10 trunk 1.0.0 1.0.1 1.0.2 1.0.3 1.1.0 1.1.1 1.2.0 1.2.10 1.2.11 1.2.12 1.2.13 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.2.7 1.2.8 1.2.9 1.3.0 All 34 releases
media-cloud-sync / includes / sdk / s3 / Aws / HandlerList.php

HandlerList.php in Media Cloud Sync 1.2.12, at includes/sdk/s3/Aws/HandlerList.php

392 lines 13.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Dudlewebs\WPMCS\s3\Aws;
4
5 /**
6 * Builds a single handler function from zero or more middleware functions and
7 * a handler. The handler function is then used to send command objects and
8 * return a promise that is resolved with an AWS result object.
9 *
10 * The "front" of the list is invoked before the "end" of the list. You can add
11 * middleware to the front of the list using one of the "prepend" method, and
12 * the end of the list using one of the "append" method. The last function
13 * invoked in a handler list is the handler (a function that does not accept a
14 * next handler but rather is responsible for returning a promise that is
15 * fulfilled with an Aws\ResultInterface object).
16 *
17 * Handlers are ordered using a "step" that describes the step at which the
18 * SDK is when sending a command. The available steps are:
19 *
20 * - init: The command is being initialized, allowing you to do things like add
21 * default options.
22 * - validate: The command is being validated before it is serialized
23 * - build: The command is being serialized into an HTTP request. A middleware
24 * in this step MUST serialize an HTTP request and populate the "@request"
25 * parameter of a command with the request such that it is available to
26 * subsequent middleware.
27 * - sign: The request is being signed and prepared to be sent over the wire.
28 *
29 * Middleware can be registered with a name to allow you to easily add a
30 * middleware before or after another middleware by name. This also allows you
31 * to remove a middleware by name (in addition to removing by instance).
32 */
33 class HandlerList implements \Countable
34 {
35 const INIT = 'init';
36 const VALIDATE = 'validate';
37 const BUILD = 'build';
38 const SIGN = 'sign';
39 const ATTEMPT = 'attempt';
40 /** @var callable */
41 private $handler;
42 /** @var array */
43 private $named = [];
44 /** @var array */
45 private $sorted;
46 /** @var callable|null */
47 private $interposeFn;
48 /** @var array Steps (in reverse order) */
49 private $steps = [self::ATTEMPT => [], self::SIGN => [], self::BUILD => [], self::VALIDATE => [], self::INIT => []];
50 /**
51 * @param callable $handler HTTP handler.
52 */
53 public function __construct(callable $handler = null)
54 {
55 $this->handler = $handler;
56 }
57 /**
58 * Dumps a string representation of the list.
59 *
60 * @return string
61 */
62 public function __toString()
63 {
64 $str = '';
65 $i = 0;
66 foreach (\array_reverse($this->steps) as $k => $step) {
67 foreach (\array_reverse($step) as $j => $tuple) {
68 $str .= "{$i}) Step: {$k}, ";
69 if ($tuple[1]) {
70 $str .= "Name: {$tuple[1]}, ";
71 }
72 $str .= "Function: " . $this->debugCallable($tuple[0]) . "\n";
73 $i++;
74 }
75 }
76 if ($this->handler) {
77 $str .= "{$i}) Handler: " . $this->debugCallable($this->handler) . "\n";
78 }
79 return $str;
80 }
81 /**
82 * Set the HTTP handler that actually returns a response.
83 *
84 * @param callable $handler Function that accepts a request and array of
85 * options and returns a Promise.
86 */
87 public function setHandler(callable $handler)
88 {
89 $this->handler = $handler;
90 }
91 /**
92 * Returns true if the builder has a handler.
93 *
94 * @return bool
95 */
96 public function hasHandler()
97 {
98 return (bool) $this->handler;
99 }
100 /**
101 * Append a middleware to the init step.
102 *
103 * @param callable $middleware Middleware function to add.
104 * @param string $name Name of the middleware.
105 */
106 public function appendInit(callable $middleware, $name = null)
107 {
108 $this->add(self::INIT, $name, $middleware);
109 }
110 /**
111 * Prepend a middleware to the init step.
112 *
113 * @param callable $middleware Middleware function to add.
114 * @param string $name Name of the middleware.
115 */
116 public function prependInit(callable $middleware, $name = null)
117 {
118 $this->add(self::INIT, $name, $middleware, \true);
119 }
120 /**
121 * Append a middleware to the validate step.
122 *
123 * @param callable $middleware Middleware function to add.
124 * @param string $name Name of the middleware.
125 */
126 public function appendValidate(callable $middleware, $name = null)
127 {
128 $this->add(self::VALIDATE, $name, $middleware);
129 }
130 /**
131 * Prepend a middleware to the validate step.
132 *
133 * @param callable $middleware Middleware function to add.
134 * @param string $name Name of the middleware.
135 */
136 public function prependValidate(callable $middleware, $name = null)
137 {
138 $this->add(self::VALIDATE, $name, $middleware, \true);
139 }
140 /**
141 * Append a middleware to the build step.
142 *
143 * @param callable $middleware Middleware function to add.
144 * @param string $name Name of the middleware.
145 */
146 public function appendBuild(callable $middleware, $name = null)
147 {
148 $this->add(self::BUILD, $name, $middleware);
149 }
150 /**
151 * Prepend a middleware to the build step.
152 *
153 * @param callable $middleware Middleware function to add.
154 * @param string $name Name of the middleware.
155 */
156 public function prependBuild(callable $middleware, $name = null)
157 {
158 $this->add(self::BUILD, $name, $middleware, \true);
159 }
160 /**
161 * Append a middleware to the sign step.
162 *
163 * @param callable $middleware Middleware function to add.
164 * @param string $name Name of the middleware.
165 */
166 public function appendSign(callable $middleware, $name = null)
167 {
168 $this->add(self::SIGN, $name, $middleware);
169 }
170 /**
171 * Prepend a middleware to the sign step.
172 *
173 * @param callable $middleware Middleware function to add.
174 * @param string $name Name of the middleware.
175 */
176 public function prependSign(callable $middleware, $name = null)
177 {
178 $this->add(self::SIGN, $name, $middleware, \true);
179 }
180 /**
181 * Append a middleware to the attempt step.
182 *
183 * @param callable $middleware Middleware function to add.
184 * @param string $name Name of the middleware.
185 */
186 public function appendAttempt(callable $middleware, $name = null)
187 {
188 $this->add(self::ATTEMPT, $name, $middleware);
189 }
190 /**
191 * Prepend a middleware to the attempt step.
192 *
193 * @param callable $middleware Middleware function to add.
194 * @param string $name Name of the middleware.
195 */
196 public function prependAttempt(callable $middleware, $name = null)
197 {
198 $this->add(self::ATTEMPT, $name, $middleware, \true);
199 }
200 /**
201 * Add a middleware before the given middleware by name.
202 *
203 * @param string|callable $findName Add before this
204 * @param string $withName Optional name to give the middleware
205 * @param callable $middleware Middleware to add.
206 */
207 public function before($findName, $withName, callable $middleware)
208 {
209 $this->splice($findName, $withName, $middleware, \true);
210 }
211 /**
212 * Add a middleware after the given middleware by name.
213 *
214 * @param string|callable $findName Add after this
215 * @param string $withName Optional name to give the middleware
216 * @param callable $middleware Middleware to add.
217 */
218 public function after($findName, $withName, callable $middleware)
219 {
220 $this->splice($findName, $withName, $middleware, \false);
221 }
222 /**
223 * Remove a middleware by name or by instance from the list.
224 *
225 * @param string|callable $nameOrInstance Middleware to remove.
226 */
227 public function remove($nameOrInstance)
228 {
229 if (\is_callable($nameOrInstance)) {
230 $this->removeByInstance($nameOrInstance);
231 } elseif (\is_string($nameOrInstance)) {
232 $this->removeByName($nameOrInstance);
233 }
234 }
235 /**
236 * Interpose a function between each middleware (e.g., allowing for a trace
237 * through the middleware layers).
238 *
239 * The interpose function is a function that accepts a "step" argument as a
240 * string and a "name" argument string. This function must then return a
241 * function that accepts the next handler in the list. This function must
242 * then return a function that accepts a CommandInterface and optional
243 * RequestInterface and returns a promise that is fulfilled with an
244 * Aws\ResultInterface or rejected with an Aws\Exception\AwsException
245 * object.
246 *
247 * @param callable|null $fn Pass null to remove any previously set function
248 */
249 public function interpose(callable $fn = null)
250 {
251 $this->sorted = null;
252 $this->interposeFn = $fn;
253 }
254 /**
255 * Compose the middleware and handler into a single callable function.
256 *
257 * @return callable
258 */
259 public function resolve()
260 {
261 if (!($prev = $this->handler)) {
262 throw new \LogicException('No handler has been specified');
263 }
264 if ($this->sorted === null) {
265 $this->sortMiddleware();
266 }
267 foreach ($this->sorted as $fn) {
268 $prev = $fn($prev);
269 }
270 return $prev;
271 }
272 /**
273 * @return int
274 */
275 #[\ReturnTypeWillChange]
276 public function count()
277 {
278 return \count($this->steps[self::INIT]) + \count($this->steps[self::VALIDATE]) + \count($this->steps[self::BUILD]) + \count($this->steps[self::SIGN]) + \count($this->steps[self::ATTEMPT]);
279 }
280 /**
281 * Splices a function into the middleware list at a specific position.
282 *
283 * @param $findName
284 * @param $withName
285 * @param callable $middleware
286 * @param $before
287 */
288 private function splice($findName, $withName, callable $middleware, $before)
289 {
290 if (!isset($this->named[$findName])) {
291 throw new \InvalidArgumentException("{$findName} not found");
292 }
293 $idx = $this->sorted = null;
294 $step = $this->named[$findName];
295 if ($withName) {
296 $this->named[$withName] = $step;
297 }
298 foreach ($this->steps[$step] as $i => $tuple) {
299 if ($tuple[1] === $findName) {
300 $idx = $i;
301 break;
302 }
303 }
304 $replacement = $before ? [$this->steps[$step][$idx], [$middleware, $withName]] : [[$middleware, $withName], $this->steps[$step][$idx]];
305 \array_splice($this->steps[$step], $idx, 1, $replacement);
306 }
307 /**
308 * Provides a debug string for a given callable.
309 *
310 * @param array|callable $fn Function to write as a string.
311 *
312 * @return string
313 */
314 private function debugCallable($fn)
315 {
316 if (\is_string($fn)) {
317 return "callable({$fn})";
318 }
319 if (\is_array($fn)) {
320 $ele = \is_string($fn[0]) ? $fn[0] : \get_class($fn[0]);
321 return "callable(['{$ele}', '{$fn[1]}'])";
322 }
323 return 'callable(' . \spl_object_hash($fn) . ')';
324 }
325 /**
326 * Sort the middleware, and interpose if needed in the sorted list.
327 */
328 private function sortMiddleware()
329 {
330 $this->sorted = [];
331 if (!$this->interposeFn) {
332 foreach ($this->steps as $step) {
333 foreach ($step as $fn) {
334 $this->sorted[] = $fn[0];
335 }
336 }
337 return;
338 }
339 $ifn = $this->interposeFn;
340 // Interpose the interposeFn into the handler stack.
341 foreach ($this->steps as $stepName => $step) {
342 foreach ($step as $fn) {
343 $this->sorted[] = $ifn($stepName, $fn[1]);
344 $this->sorted[] = $fn[0];
345 }
346 }
347 }
348 private function removeByName($name)
349 {
350 if (!isset($this->named[$name])) {
351 return;
352 }
353 $this->sorted = null;
354 $step = $this->named[$name];
355 $this->steps[$step] = \array_values(\array_filter($this->steps[$step], function ($tuple) use($name) {
356 return $tuple[1] !== $name;
357 }));
358 }
359 private function removeByInstance(callable $fn)
360 {
361 foreach ($this->steps as $k => $step) {
362 foreach ($step as $j => $tuple) {
363 if ($tuple[0] === $fn) {
364 $this->sorted = null;
365 unset($this->named[$this->steps[$k][$j][1]]);
366 unset($this->steps[$k][$j]);
367 }
368 }
369 }
370 }
371 /**
372 * Add a middleware to a step.
373 *
374 * @param string $step Middleware step.
375 * @param string $name Middleware name.
376 * @param callable $middleware Middleware function to add.
377 * @param bool $prepend Prepend instead of append.
378 */
379 private function add($step, $name, callable $middleware, $prepend = \false)
380 {
381 $this->sorted = null;
382 if ($prepend) {
383 $this->steps[$step][] = [$middleware, $name];
384 } else {
385 \array_unshift($this->steps[$step], [$middleware, $name]);
386 }
387 if ($name) {
388 $this->named[$name] = $step;
389 }
390 }
391 }
392