PluginChain.php 1.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061
  1. <?php
  2. declare(strict_types=1);
  3. namespace Http\Client\Common;
  4. use Http\Client\Common\Exception\LoopException;
  5. use Http\Promise\Promise;
  6. use Psr\Http\Message\RequestInterface;
  7. final class PluginChain
  8. {
  9. /** @var Plugin[] */
  10. private $plugins;
  11. /** @var callable(RequestInterface): Promise */
  12. private $clientCallable;
  13. /** @var int */
  14. private $maxRestarts;
  15. /** @var int */
  16. private $restarts = 0;
  17. /**
  18. * @param Plugin[] $plugins A plugin chain
  19. * @param callable(RequestInterface): Promise $clientCallable Callable making the HTTP call
  20. * @param array{'max_restarts'?: int} $options
  21. */
  22. public function __construct(array $plugins, callable $clientCallable, array $options = [])
  23. {
  24. $this->plugins = $plugins;
  25. $this->clientCallable = $clientCallable;
  26. $this->maxRestarts = (int) ($options['max_restarts'] ?? 0);
  27. }
  28. private function createChain(): callable
  29. {
  30. $lastCallable = $this->clientCallable;
  31. $reversedPlugins = \array_reverse($this->plugins);
  32. foreach ($reversedPlugins as $plugin) {
  33. $lastCallable = function (RequestInterface $request) use ($plugin, $lastCallable) {
  34. return $plugin->handleRequest($request, $lastCallable, $this);
  35. };
  36. }
  37. return $lastCallable;
  38. }
  39. public function __invoke(RequestInterface $request): Promise
  40. {
  41. if ($this->restarts > $this->maxRestarts) {
  42. throw new LoopException('Too many restarts in plugin client', $request);
  43. }
  44. ++$this->restarts;
  45. return $this->createChain()($request);
  46. }
  47. }