vendor/guzzlehttp/guzzle/src/HandlerStack.php line 71

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