MockHttpClient.php 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Symfony\Component\HttpClient;
  11. use Symfony\Component\HttpClient\Exception\TransportException;
  12. use Symfony\Component\HttpClient\Response\MockResponse;
  13. use Symfony\Component\HttpClient\Response\ResponseStream;
  14. use Symfony\Contracts\HttpClient\HttpClientInterface;
  15. use Symfony\Contracts\HttpClient\ResponseInterface;
  16. use Symfony\Contracts\HttpClient\ResponseStreamInterface;
  17. /**
  18. * A test-friendly HttpClient that doesn't make actual HTTP requests.
  19. *
  20. * @author Nicolas Grekas <p@tchwork.com>
  21. */
  22. class MockHttpClient implements HttpClientInterface
  23. {
  24. use HttpClientTrait;
  25. private $responseFactory;
  26. private $baseUri;
  27. private $requestsCount = 0;
  28. /**
  29. * @param callable|callable[]|ResponseInterface|ResponseInterface[]|iterable|null $responseFactory
  30. */
  31. public function __construct($responseFactory = null, string $baseUri = null)
  32. {
  33. if ($responseFactory instanceof ResponseInterface) {
  34. $responseFactory = [$responseFactory];
  35. }
  36. if (!$responseFactory instanceof \Iterator && null !== $responseFactory && !\is_callable($responseFactory)) {
  37. $responseFactory = (static function () use ($responseFactory) {
  38. yield from $responseFactory;
  39. })();
  40. }
  41. $this->responseFactory = $responseFactory;
  42. $this->baseUri = $baseUri;
  43. }
  44. /**
  45. * {@inheritdoc}
  46. */
  47. public function request(string $method, string $url, array $options = []): ResponseInterface
  48. {
  49. [$url, $options] = $this->prepareRequest($method, $url, $options, ['base_uri' => $this->baseUri], true);
  50. $url = implode('', $url);
  51. if (null === $this->responseFactory) {
  52. $response = new MockResponse();
  53. } elseif (\is_callable($this->responseFactory)) {
  54. $response = ($this->responseFactory)($method, $url, $options);
  55. } elseif (!$this->responseFactory->valid()) {
  56. throw new TransportException('The response factory iterator passed to MockHttpClient is empty.');
  57. } else {
  58. $responseFactory = $this->responseFactory->current();
  59. $response = \is_callable($responseFactory) ? $responseFactory($method, $url, $options) : $responseFactory;
  60. $this->responseFactory->next();
  61. }
  62. ++$this->requestsCount;
  63. if (!$response instanceof ResponseInterface) {
  64. throw new TransportException(sprintf('The response factory passed to MockHttpClient must return/yield an instance of ResponseInterface, "%s" given.', \is_object($response) ? \get_class($response) : \gettype($response)));
  65. }
  66. return MockResponse::fromRequest($method, $url, $options, $response);
  67. }
  68. /**
  69. * {@inheritdoc}
  70. */
  71. public function stream($responses, float $timeout = null): ResponseStreamInterface
  72. {
  73. if ($responses instanceof ResponseInterface) {
  74. $responses = [$responses];
  75. } elseif (!is_iterable($responses)) {
  76. throw new \TypeError(sprintf('"%s()" expects parameter 1 to be an iterable of MockResponse objects, "%s" given.', __METHOD__, get_debug_type($responses)));
  77. }
  78. return new ResponseStream(MockResponse::stream($responses, $timeout));
  79. }
  80. public function getRequestsCount(): int
  81. {
  82. return $this->requestsCount;
  83. }
  84. }