GuzzleHttpHandlerStack

Creates a composed Guzzle handler function by stacking middlewares on top of an HTTP handler function.

Defined (1)

The class is defined in the following location(s).

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