Serializer.php 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. <?php
  2. namespace GuzzleHttp\Command\Guzzle;
  3. use GuzzleHttp\Command\CommandInterface;
  4. use GuzzleHttp\Command\Guzzle\RequestLocation\BodyLocation;
  5. use GuzzleHttp\Command\Guzzle\RequestLocation\FormParamLocation;
  6. use GuzzleHttp\Command\Guzzle\RequestLocation\HeaderLocation;
  7. use GuzzleHttp\Command\Guzzle\RequestLocation\JsonLocation;
  8. use GuzzleHttp\Command\Guzzle\RequestLocation\MultiPartLocation;
  9. use GuzzleHttp\Command\Guzzle\RequestLocation\QueryLocation;
  10. use GuzzleHttp\Command\Guzzle\RequestLocation\RequestLocationInterface;
  11. use GuzzleHttp\Command\Guzzle\RequestLocation\XmlLocation;
  12. use GuzzleHttp\Psr7\Request;
  13. use GuzzleHttp\Psr7\Uri;
  14. use GuzzleHttp\Psr7\UriResolver;
  15. use GuzzleHttp\UriTemplate\UriTemplate;
  16. use Psr\Http\Message\RequestInterface;
  17. /**
  18. * Serializes requests for a given command.
  19. */
  20. class Serializer
  21. {
  22. /** @var RequestLocationInterface[] */
  23. private $locations;
  24. /** @var DescriptionInterface */
  25. private $description;
  26. /**
  27. * @param DescriptionInterface $description
  28. * @param RequestLocationInterface[] $requestLocations Extra request locations
  29. */
  30. public function __construct(
  31. DescriptionInterface $description,
  32. array $requestLocations = []
  33. ) {
  34. static $defaultRequestLocations;
  35. if (!$defaultRequestLocations) {
  36. $defaultRequestLocations = [
  37. 'body' => new BodyLocation(),
  38. 'query' => new QueryLocation(),
  39. 'header' => new HeaderLocation(),
  40. 'json' => new JsonLocation(),
  41. 'xml' => new XmlLocation(),
  42. 'formParam' => new FormParamLocation(),
  43. 'multipart' => new MultiPartLocation(),
  44. ];
  45. }
  46. $this->locations = $requestLocations + $defaultRequestLocations;
  47. $this->description = $description;
  48. }
  49. /**
  50. * @param CommandInterface $command
  51. * @return RequestInterface
  52. */
  53. public function __invoke(CommandInterface $command)
  54. {
  55. $request = $this->createRequest($command);
  56. return $this->prepareRequest($command, $request);
  57. }
  58. /**
  59. * Prepares a request for sending using location visitors
  60. *
  61. * @param CommandInterface $command
  62. * @param RequestInterface $request Request being created
  63. * @return RequestInterface
  64. * @throws \RuntimeException If a location cannot be handled
  65. */
  66. protected function prepareRequest(
  67. CommandInterface $command,
  68. RequestInterface $request
  69. ) {
  70. $visitedLocations = [];
  71. $operation = $this->description->getOperation($command->getName());
  72. // Visit each actual parameter
  73. foreach ($operation->getParams() as $name => $param) {
  74. /* @var Parameter $param */
  75. $location = $param->getLocation();
  76. // Skip parameters that have not been set or are URI location
  77. if ($location == 'uri' || !$command->hasParam($name)) {
  78. continue;
  79. }
  80. if (!isset($this->locations[$location])) {
  81. throw new \RuntimeException("No location registered for $name");
  82. }
  83. $visitedLocations[$location] = true;
  84. $request = $this->locations[$location]->visit($command, $request, $param);
  85. }
  86. // Ensure that the after() method is invoked for additionalParameters
  87. /** @var Parameter $additional */
  88. if ($additional = $operation->getAdditionalParameters()) {
  89. $visitedLocations[$additional->getLocation()] = true;
  90. }
  91. // Call the after() method for each visited location
  92. foreach (array_keys($visitedLocations) as $location) {
  93. $request = $this->locations[$location]->after($command, $request, $operation);
  94. }
  95. return $request;
  96. }
  97. /**
  98. * Create a request for the command and operation
  99. *
  100. * @param CommandInterface $command
  101. *
  102. * @return RequestInterface
  103. * @throws \RuntimeException
  104. */
  105. protected function createRequest(CommandInterface $command)
  106. {
  107. $operation = $this->description->getOperation($command->getName());
  108. // If command does not specify a template, assume the client's base URL.
  109. if (null === $operation->getUri()) {
  110. return new Request(
  111. $operation->getHttpMethod() ?: 'GET',
  112. $this->description->getBaseUri()
  113. );
  114. }
  115. return $this->createCommandWithUri($operation, $command);
  116. }
  117. /**
  118. * Create a request for an operation with a uri merged onto a base URI
  119. *
  120. * @param \GuzzleHttp\Command\Guzzle\Operation $operation
  121. * @param \GuzzleHttp\Command\CommandInterface $command
  122. *
  123. * @return \GuzzleHttp\Psr7\Request
  124. */
  125. private function createCommandWithUri(
  126. Operation $operation,
  127. CommandInterface $command
  128. ) {
  129. // Get the path values and use the client config settings
  130. $variables = [];
  131. foreach ($operation->getParams() as $name => $arg) {
  132. /* @var Parameter $arg */
  133. if ($arg->getLocation() == 'uri') {
  134. if (isset($command[$name])) {
  135. $variables[$name] = $arg->filter($command[$name]);
  136. if (!is_array($variables[$name])) {
  137. $variables[$name] = (string) $variables[$name];
  138. }
  139. }
  140. }
  141. }
  142. // Expand the URI template.
  143. $uri = new Uri(UriTemplate::expand($operation->getUri(), $variables));
  144. return new Request(
  145. $operation->getHttpMethod() ?: 'GET',
  146. UriResolver::resolve($this->description->getBaseUri(), $uri)
  147. );
  148. }
  149. }