UriTemplateHttpClient.php 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  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\Contracts\HttpClient\HttpClientInterface;
  12. use Symfony\Contracts\HttpClient\ResponseInterface;
  13. use Symfony\Contracts\Service\ResetInterface;
  14. class UriTemplateHttpClient implements HttpClientInterface, ResetInterface
  15. {
  16. use DecoratorTrait;
  17. /**
  18. * @var \Closure(string $url, array $vars):string|null
  19. */
  20. private $expander;
  21. /**
  22. * @var mixed[]
  23. */
  24. private $defaultVars = [];
  25. /**
  26. * @param (\Closure(string $url, array $vars): string)|null $expander
  27. * @param \Symfony\Contracts\HttpClient\HttpClientInterface|null $client
  28. * @param mixed[] $defaultVars
  29. */
  30. public function __construct($client = null, $expander = null, $defaultVars = [])
  31. {
  32. $this->expander = $expander;
  33. $this->defaultVars = $defaultVars;
  34. $this->client = $client ?? HttpClient::create();
  35. }
  36. /**
  37. * @param string $method
  38. * @param string $url
  39. * @param mixed[] $options
  40. */
  41. public function request($method, $url, $options = [])
  42. {
  43. $vars = $this->defaultVars;
  44. if (\array_key_exists('vars', $options)) {
  45. if (!\is_array($options['vars'])) {
  46. throw new \InvalidArgumentException('The "vars" option must be an array.');
  47. }
  48. $item1Unpacked = $options['vars'];
  49. $vars = array_merge($vars, $item1Unpacked);
  50. unset($options['vars']);
  51. }
  52. if ($vars) {
  53. $url = ($this->expander = $this->expander ?? $this->createExpanderFromPopularVendors())($url, $vars);
  54. }
  55. return $this->client->request($method, $url, $options);
  56. }
  57. /**
  58. * @return $this
  59. * @param mixed[] $options
  60. */
  61. public function withOptions($options)
  62. {
  63. if (!\is_array($options['vars'] ?? [])) {
  64. throw new \InvalidArgumentException('The "vars" option must be an array.');
  65. }
  66. $clone = clone $this;
  67. $item0Unpacked = $clone->defaultVars;
  68. $item1Unpacked = $options['vars'] ?? [];
  69. $clone->defaultVars = array_merge($item0Unpacked, $item1Unpacked);
  70. unset($options['vars']);
  71. $clone->client = $this->client->withOptions($options);
  72. return $clone;
  73. }
  74. /**
  75. * @return \Closure(string $url, array $vars): string
  76. */
  77. private function createExpanderFromPopularVendors()
  78. {
  79. if (class_exists(\GuzzleHttp\UriTemplate\UriTemplate::class)) {
  80. return \Closure::fromCallable([\GuzzleHttp\UriTemplate\UriTemplate::class, 'expand']);
  81. }
  82. if (class_exists(\League\Uri\UriTemplate::class)) {
  83. return static function (string $url, array $vars) : string {
  84. return (new \League\Uri\UriTemplate($url))->expand($vars);
  85. };
  86. }
  87. if (class_exists(\Rize\UriTemplate::class)) {
  88. return \Closure::fromCallable([new \Rize\UriTemplate(), 'expand']);
  89. }
  90. throw new \LogicException('Support for URI template requires a vendor to expand the URI. Run "composer require guzzlehttp/uri-template" or pass your own expander \Closure implementation.');
  91. }
  92. }