PluginProbe
Media Cloud Sync / 1.2.11
Media Cloud Sync v1.2.11
1.4.1 1.4.0 1.3.12 1.3.11 1.3.10 trunk 1.0.0 1.0.1 1.0.2 1.0.3 1.1.0 1.1.1 1.2.0 1.2.10 1.2.11 1.2.12 1.2.13 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.2.7 1.2.8 1.2.9 All 35 releases
media-cloud-sync / includes / sdk / s3 / Aws / Api / Serializer / RestSerializer.php

RestSerializer.php in Media Cloud Sync 1.2.11, at includes/sdk/s3/Aws/Api/Serializer/RestSerializer.php

201 lines 8.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Dudlewebs\WPMCS\s3\Aws\Api\Serializer;
4
5 use Dudlewebs\WPMCS\s3\Aws\Api\MapShape;
6 use Dudlewebs\WPMCS\s3\Aws\Api\Service;
7 use Dudlewebs\WPMCS\s3\Aws\Api\Operation;
8 use Dudlewebs\WPMCS\s3\Aws\Api\Shape;
9 use Dudlewebs\WPMCS\s3\Aws\Api\StructureShape;
10 use Dudlewebs\WPMCS\s3\Aws\Api\TimestampShape;
11 use Dudlewebs\WPMCS\s3\Aws\CommandInterface;
12 use Dudlewebs\WPMCS\s3\GuzzleHttp\Psr7;
13 use Dudlewebs\WPMCS\s3\GuzzleHttp\Psr7\Uri;
14 use Dudlewebs\WPMCS\s3\GuzzleHttp\Psr7\UriResolver;
15 use Dudlewebs\WPMCS\s3\Psr\Http\Message\RequestInterface;
16 /**
17 * Serializes HTTP locations like header, uri, payload, etc...
18 * @internal
19 */
20 abstract class RestSerializer
21 {
22 /** @var Service */
23 private $api;
24 /** @var Psr7\Uri */
25 private $endpoint;
26 /**
27 * @param Service $api Service API description
28 * @param string $endpoint Endpoint to connect to
29 */
30 public function __construct(Service $api, $endpoint)
31 {
32 $this->api = $api;
33 $this->endpoint = Psr7\Utils::uriFor($endpoint);
34 }
35 /**
36 * @param CommandInterface $command Command to serialized
37 *
38 * @return RequestInterface
39 */
40 public function __invoke(CommandInterface $command)
41 {
42 $operation = $this->api->getOperation($command->getName());
43 $args = $command->toArray();
44 $opts = $this->serialize($operation, $args);
45 $uri = $this->buildEndpoint($operation, $args, $opts);
46 return new Psr7\Request($operation['http']['method'], $uri, isset($opts['headers']) ? $opts['headers'] : [], isset($opts['body']) ? $opts['body'] : null);
47 }
48 /**
49 * Modifies a hash of request options for a payload body.
50 *
51 * @param StructureShape $member Member to serialize
52 * @param array $value Value to serialize
53 * @param array $opts Request options to modify.
54 */
55 protected abstract function payload(StructureShape $member, array $value, array &$opts);
56 private function serialize(Operation $operation, array $args)
57 {
58 $opts = [];
59 $input = $operation->getInput();
60 // Apply the payload trait if present
61 if ($payload = $input['payload']) {
62 $this->applyPayload($input, $payload, $args, $opts);
63 }
64 foreach ($args as $name => $value) {
65 if ($input->hasMember($name)) {
66 $member = $input->getMember($name);
67 $location = $member['location'];
68 if (!$payload && !$location) {
69 $bodyMembers[$name] = $value;
70 } elseif ($location == 'header') {
71 $this->applyHeader($name, $member, $value, $opts);
72 } elseif ($location == 'querystring') {
73 $this->applyQuery($name, $member, $value, $opts);
74 } elseif ($location == 'headers') {
75 $this->applyHeaderMap($name, $member, $value, $opts);
76 }
77 }
78 }
79 if (isset($bodyMembers)) {
80 $this->payload($operation->getInput(), $bodyMembers, $opts);
81 } else {
82 if (!isset($opts['body']) && $this->hasPayloadParam($input, $payload)) {
83 $this->payload($operation->getInput(), [], $opts);
84 }
85 }
86 return $opts;
87 }
88 private function applyPayload(StructureShape $input, $name, array $args, array &$opts)
89 {
90 if (!isset($args[$name])) {
91 return;
92 }
93 $m = $input->getMember($name);
94 if ($m['streaming'] || ($m['type'] == 'string' || $m['type'] == 'blob')) {
95 // Streaming bodies or payloads that are strings are
96 // always just a stream of data.
97 $opts['body'] = Psr7\Utils::streamFor($args[$name]);
98 return;
99 }
100 $this->payload($m, $args[$name], $opts);
101 }
102 private function applyHeader($name, Shape $member, $value, array &$opts)
103 {
104 if ($member->getType() === 'timestamp') {
105 $timestampFormat = !empty($member['timestampFormat']) ? $member['timestampFormat'] : 'rfc822';
106 $value = TimestampShape::format($value, $timestampFormat);
107 } elseif ($member->getType() === 'boolean') {
108 $value = $value ? 'true' : 'false';
109 }
110 if ($member['jsonvalue']) {
111 $value = \json_encode($value);
112 if (empty($value) && \JSON_ERROR_NONE !== \json_last_error()) {
113 throw new \InvalidArgumentException('Unable to encode the provided value' . ' with \'json_encode\'. ' . \json_last_error_msg());
114 }
115 $value = \base64_encode($value);
116 }
117 $opts['headers'][$member['locationName'] ?: $name] = $value;
118 }
119 /**
120 * Note: This is currently only present in the Amazon S3 model.
121 */
122 private function applyHeaderMap($name, Shape $member, array $value, array &$opts)
123 {
124 $prefix = $member['locationName'];
125 foreach ($value as $k => $v) {
126 $opts['headers'][$prefix . $k] = $v;
127 }
128 }
129 private function applyQuery($name, Shape $member, $value, array &$opts)
130 {
131 if ($member instanceof MapShape) {
132 $opts['query'] = isset($opts['query']) && \is_array($opts['query']) ? $opts['query'] + $value : $value;
133 } elseif ($value !== null) {
134 $type = $member->getType();
135 if ($type === 'boolean') {
136 $value = $value ? 'true' : 'false';
137 } elseif ($type === 'timestamp') {
138 $timestampFormat = !empty($member['timestampFormat']) ? $member['timestampFormat'] : 'iso8601';
139 $value = TimestampShape::format($value, $timestampFormat);
140 }
141 $opts['query'][$member['locationName'] ?: $name] = $value;
142 }
143 }
144 private function buildEndpoint(Operation $operation, array $args, array $opts)
145 {
146 $varspecs = [];
147 // Create an associative array of varspecs used in expansions
148 foreach ($operation->getInput()->getMembers() as $name => $member) {
149 if ($member['location'] == 'uri') {
150 $varspecs[$member['locationName'] ?: $name] = isset($args[$name]) ? $args[$name] : null;
151 }
152 }
153 $relative = \preg_replace_callback('/\\{([^\\}]+)\\}/', function (array $matches) use($varspecs) {
154 $isGreedy = \substr($matches[1], -1, 1) == '+';
155 $k = $isGreedy ? \substr($matches[1], 0, -1) : $matches[1];
156 if (!isset($varspecs[$k])) {
157 return '';
158 }
159 if ($isGreedy) {
160 return \str_replace('%2F', '/', \rawurlencode($varspecs[$k]));
161 }
162 return \rawurlencode($varspecs[$k]);
163 }, $operation['http']['requestUri']);
164 // Add the query string variables or appending to one if needed.
165 if (!empty($opts['query'])) {
166 $append = Psr7\Query::build($opts['query']);
167 $relative .= \strpos($relative, '?') ? "&{$append}" : "?{$append}";
168 }
169 // If endpoint has path, remove leading '/' to preserve URI resolution.
170 $path = $this->endpoint->getPath();
171 if ($path && $relative[0] === '/') {
172 $relative = \substr($relative, 1);
173 }
174 // Expand path place holders using Amazon's slightly different URI
175 // template syntax.
176 return UriResolver::resolve($this->endpoint, new Uri($relative));
177 }
178 /**
179 * @param StructureShape $input
180 */
181 private function hasPayloadParam(StructureShape $input, $payload)
182 {
183 if ($payload) {
184 $potentiallyEmptyTypes = ['blob', 'string'];
185 if ($this->api->getMetadata('protocol') == 'rest-xml') {
186 $potentiallyEmptyTypes[] = 'structure';
187 }
188 $payloadMember = $input->getMember($payload);
189 if (\in_array($payloadMember['type'], $potentiallyEmptyTypes)) {
190 return \false;
191 }
192 }
193 foreach ($input->getMembers() as $member) {
194 if (!isset($member['location'])) {
195 return \true;
196 }
197 }
198 return \false;
199 }
200 }
201