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