Service.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431
  1. <?php
  2. namespace Aws\Api;
  3. use Aws\Api\Serializer\QuerySerializer;
  4. use Aws\Api\Serializer\Ec2ParamBuilder;
  5. use Aws\Api\Parser\QueryParser;
  6. /**
  7. * Represents a web service API model.
  8. */
  9. class Service extends AbstractModel
  10. {
  11. /** @var callable */
  12. private $apiProvider;
  13. /** @var string */
  14. private $serviceName;
  15. /** @var string */
  16. private $apiVersion;
  17. /** @var Operation[] */
  18. private $operations = [];
  19. /** @var array */
  20. private $paginators = null;
  21. /** @var array */
  22. private $waiters = null;
  23. /**
  24. * @param array $definition
  25. * @param callable $provider
  26. *
  27. * @internal param array $definition Service description
  28. */
  29. public function __construct(array $definition, callable $provider)
  30. {
  31. static $defaults = [
  32. 'operations' => [],
  33. 'shapes' => [],
  34. 'metadata' => []
  35. ], $defaultMeta = [
  36. 'apiVersion' => null,
  37. 'serviceFullName' => null,
  38. 'endpointPrefix' => null,
  39. 'signingName' => null,
  40. 'signatureVersion' => null,
  41. 'protocol' => null,
  42. 'uid' => null
  43. ];
  44. $definition += $defaults;
  45. $definition['metadata'] += $defaultMeta;
  46. $this->definition = $definition;
  47. $this->apiProvider = $provider;
  48. parent::__construct($definition, new ShapeMap($definition['shapes']));
  49. if (isset($definition['metadata']['serviceIdentifier'])) {
  50. $this->serviceName = $this->getServiceName();
  51. } else {
  52. $this->serviceName = $this->getEndpointPrefix();
  53. }
  54. $this->apiVersion = $this->getApiVersion();
  55. }
  56. /**
  57. * Creates a request serializer for the provided API object.
  58. *
  59. * @param Service $api API that contains a protocol.
  60. * @param string $endpoint Endpoint to send requests to.
  61. *
  62. * @return callable
  63. * @throws \UnexpectedValueException
  64. */
  65. public static function createSerializer(Service $api, $endpoint)
  66. {
  67. static $mapping = [
  68. 'json' => 'Aws\Api\Serializer\JsonRpcSerializer',
  69. 'query' => 'Aws\Api\Serializer\QuerySerializer',
  70. 'rest-json' => 'Aws\Api\Serializer\RestJsonSerializer',
  71. 'rest-xml' => 'Aws\Api\Serializer\RestXmlSerializer'
  72. ];
  73. $proto = $api->getProtocol();
  74. if (isset($mapping[$proto])) {
  75. return new $mapping[$proto]($api, $endpoint);
  76. } elseif ($proto == 'ec2') {
  77. return new QuerySerializer($api, $endpoint, new Ec2ParamBuilder());
  78. }
  79. throw new \UnexpectedValueException(
  80. 'Unknown protocol: ' . $api->getProtocol()
  81. );
  82. }
  83. /**
  84. * Creates an error parser for the given protocol.
  85. *
  86. * @param string $protocol Protocol to parse (e.g., query, json, etc.)
  87. *
  88. * @return callable
  89. * @throws \UnexpectedValueException
  90. */
  91. public static function createErrorParser($protocol)
  92. {
  93. static $mapping = [
  94. 'json' => 'Aws\Api\ErrorParser\JsonRpcErrorParser',
  95. 'query' => 'Aws\Api\ErrorParser\XmlErrorParser',
  96. 'rest-json' => 'Aws\Api\ErrorParser\RestJsonErrorParser',
  97. 'rest-xml' => 'Aws\Api\ErrorParser\XmlErrorParser',
  98. 'ec2' => 'Aws\Api\ErrorParser\XmlErrorParser'
  99. ];
  100. if (isset($mapping[$protocol])) {
  101. return new $mapping[$protocol]();
  102. }
  103. throw new \UnexpectedValueException("Unknown protocol: $protocol");
  104. }
  105. /**
  106. * Applies the listeners needed to parse client models.
  107. *
  108. * @param Service $api API to create a parser for
  109. * @return callable
  110. * @throws \UnexpectedValueException
  111. */
  112. public static function createParser(Service $api)
  113. {
  114. static $mapping = [
  115. 'json' => 'Aws\Api\Parser\JsonRpcParser',
  116. 'query' => 'Aws\Api\Parser\QueryParser',
  117. 'rest-json' => 'Aws\Api\Parser\RestJsonParser',
  118. 'rest-xml' => 'Aws\Api\Parser\RestXmlParser'
  119. ];
  120. $proto = $api->getProtocol();
  121. if (isset($mapping[$proto])) {
  122. return new $mapping[$proto]($api);
  123. } elseif ($proto == 'ec2') {
  124. return new QueryParser($api, null, false);
  125. }
  126. throw new \UnexpectedValueException(
  127. 'Unknown protocol: ' . $api->getProtocol()
  128. );
  129. }
  130. /**
  131. * Get the full name of the service
  132. *
  133. * @return string
  134. */
  135. public function getServiceFullName()
  136. {
  137. return $this->definition['metadata']['serviceFullName'];
  138. }
  139. /**
  140. * Get the API version of the service
  141. *
  142. * @return string
  143. */
  144. public function getApiVersion()
  145. {
  146. return $this->definition['metadata']['apiVersion'];
  147. }
  148. /**
  149. * Get the API version of the service
  150. *
  151. * @return string
  152. */
  153. public function getEndpointPrefix()
  154. {
  155. return $this->definition['metadata']['endpointPrefix'];
  156. }
  157. /**
  158. * Get the signing name used by the service.
  159. *
  160. * @return string
  161. */
  162. public function getSigningName()
  163. {
  164. return $this->definition['metadata']['signingName']
  165. ?: $this->definition['metadata']['endpointPrefix'];
  166. }
  167. /**
  168. * Get the service name.
  169. *
  170. * @return string
  171. */
  172. public function getServiceName()
  173. {
  174. return $this->definition['metadata']['serviceIdentifier'];
  175. }
  176. /**
  177. * Get the default signature version of the service.
  178. *
  179. * Note: this method assumes "v4" when not specified in the model.
  180. *
  181. * @return string
  182. */
  183. public function getSignatureVersion()
  184. {
  185. return $this->definition['metadata']['signatureVersion'] ?: 'v4';
  186. }
  187. /**
  188. * Get the protocol used by the service.
  189. *
  190. * @return string
  191. */
  192. public function getProtocol()
  193. {
  194. return $this->definition['metadata']['protocol'];
  195. }
  196. /**
  197. * Get the uid string used by the service
  198. *
  199. * @return string
  200. */
  201. public function getUid()
  202. {
  203. return $this->definition['metadata']['uid'];
  204. }
  205. /**
  206. * Check if the description has a specific operation by name.
  207. *
  208. * @param string $name Operation to check by name
  209. *
  210. * @return bool
  211. */
  212. public function hasOperation($name)
  213. {
  214. return isset($this['operations'][$name]);
  215. }
  216. /**
  217. * Get an operation by name.
  218. *
  219. * @param string $name Operation to retrieve by name
  220. *
  221. * @return Operation
  222. * @throws \InvalidArgumentException If the operation is not found
  223. */
  224. public function getOperation($name)
  225. {
  226. if (!isset($this->operations[$name])) {
  227. if (!isset($this->definition['operations'][$name])) {
  228. throw new \InvalidArgumentException("Unknown operation: $name");
  229. }
  230. $this->operations[$name] = new Operation(
  231. $this->definition['operations'][$name],
  232. $this->shapeMap
  233. );
  234. }
  235. return $this->operations[$name];
  236. }
  237. /**
  238. * Get all of the operations of the description.
  239. *
  240. * @return Operation[]
  241. */
  242. public function getOperations()
  243. {
  244. $result = [];
  245. foreach ($this->definition['operations'] as $name => $definition) {
  246. $result[$name] = $this->getOperation($name);
  247. }
  248. return $result;
  249. }
  250. /**
  251. * Get all of the service metadata or a specific metadata key value.
  252. *
  253. * @param string|null $key Key to retrieve or null to retrieve all metadata
  254. *
  255. * @return mixed Returns the result or null if the key is not found
  256. */
  257. public function getMetadata($key = null)
  258. {
  259. if (!$key) {
  260. return $this['metadata'];
  261. } elseif (isset($this->definition['metadata'][$key])) {
  262. return $this->definition['metadata'][$key];
  263. }
  264. return null;
  265. }
  266. /**
  267. * Gets an associative array of available paginator configurations where
  268. * the key is the name of the paginator, and the value is the paginator
  269. * configuration.
  270. *
  271. * @return array
  272. * @unstable The configuration format of paginators may change in the future
  273. */
  274. public function getPaginators()
  275. {
  276. if (!isset($this->paginators)) {
  277. $res = call_user_func(
  278. $this->apiProvider,
  279. 'paginator',
  280. $this->serviceName,
  281. $this->apiVersion
  282. );
  283. $this->paginators = isset($res['pagination'])
  284. ? $res['pagination']
  285. : [];
  286. }
  287. return $this->paginators;
  288. }
  289. /**
  290. * Determines if the service has a paginator by name.
  291. *
  292. * @param string $name Name of the paginator.
  293. *
  294. * @return bool
  295. */
  296. public function hasPaginator($name)
  297. {
  298. return isset($this->getPaginators()[$name]);
  299. }
  300. /**
  301. * Retrieve a paginator by name.
  302. *
  303. * @param string $name Paginator to retrieve by name. This argument is
  304. * typically the operation name.
  305. * @return array
  306. * @throws \UnexpectedValueException if the paginator does not exist.
  307. * @unstable The configuration format of paginators may change in the future
  308. */
  309. public function getPaginatorConfig($name)
  310. {
  311. static $defaults = [
  312. 'input_token' => null,
  313. 'output_token' => null,
  314. 'limit_key' => null,
  315. 'result_key' => null,
  316. 'more_results' => null,
  317. ];
  318. if ($this->hasPaginator($name)) {
  319. return $this->paginators[$name] + $defaults;
  320. }
  321. throw new \UnexpectedValueException("There is no {$name} "
  322. . "paginator defined for the {$this->serviceName} service.");
  323. }
  324. /**
  325. * Gets an associative array of available waiter configurations where the
  326. * key is the name of the waiter, and the value is the waiter
  327. * configuration.
  328. *
  329. * @return array
  330. */
  331. public function getWaiters()
  332. {
  333. if (!isset($this->waiters)) {
  334. $res = call_user_func(
  335. $this->apiProvider,
  336. 'waiter',
  337. $this->serviceName,
  338. $this->apiVersion
  339. );
  340. $this->waiters = isset($res['waiters'])
  341. ? $res['waiters']
  342. : [];
  343. }
  344. return $this->waiters;
  345. }
  346. /**
  347. * Determines if the service has a waiter by name.
  348. *
  349. * @param string $name Name of the waiter.
  350. *
  351. * @return bool
  352. */
  353. public function hasWaiter($name)
  354. {
  355. return isset($this->getWaiters()[$name]);
  356. }
  357. /**
  358. * Get a waiter configuration by name.
  359. *
  360. * @param string $name Name of the waiter by name.
  361. *
  362. * @return array
  363. * @throws \UnexpectedValueException if the waiter does not exist.
  364. */
  365. public function getWaiterConfig($name)
  366. {
  367. // Error if the waiter is not defined
  368. if ($this->hasWaiter($name)) {
  369. return $this->waiters[$name];
  370. }
  371. throw new \UnexpectedValueException("There is no {$name} waiter "
  372. . "defined for the {$this->serviceName} service.");
  373. }
  374. /**
  375. * Get the shape map used by the API.
  376. *
  377. * @return ShapeMap
  378. */
  379. public function getShapeMap()
  380. {
  381. return $this->shapeMap;
  382. }
  383. }