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

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