PluginProbe
Media Cloud Sync / 1.2.4
Media Cloud Sync v1.2.4
1.4.2 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 All 36 releases
media-cloud-sync / includes / sdk / google / google / gax / src / RequestBuilder.php

RequestBuilder.php in Media Cloud Sync 1.2.4, at includes/sdk/google/google/gax/src/RequestBuilder.php

235 lines 9.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /*
4 * Copyright 2018 Google LLC
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are
9 * met:
10 *
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following disclaimer
15 * in the documentation and/or other materials provided with the
16 * distribution.
17 * * Neither the name of Google Inc. nor the names of its
18 * contributors may be used to endorse or promote products derived from
19 * this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33 namespace Dudlewebs\WPMCS\Google\ApiCore;
34
35 use Dudlewebs\WPMCS\Google\ApiCore\ResourceTemplate\AbsoluteResourceTemplate;
36 use Dudlewebs\WPMCS\Google\Protobuf\Internal\Message;
37 use Dudlewebs\WPMCS\GuzzleHttp\Psr7\Request;
38 use Dudlewebs\WPMCS\GuzzleHttp\Psr7\Utils;
39 use Dudlewebs\WPMCS\Psr\Http\Message\RequestInterface;
40 use Dudlewebs\WPMCS\Psr\Http\Message\UriInterface;
41 /**
42 * Builds a PSR-7 request from a set of request information.
43 *
44 * @internal
45 */
46 class RequestBuilder
47 {
48 use ArrayTrait;
49 use UriTrait;
50 use ValidationTrait;
51 private $baseUri;
52 private $restConfig;
53 /**
54 * @param string $baseUri
55 * @param string $restConfigPath
56 * @throws ValidationException
57 */
58 public function __construct(string $baseUri, string $restConfigPath)
59 {
60 self::validateFileExists($restConfigPath);
61 $this->baseUri = $baseUri;
62 $this->restConfig = require $restConfigPath;
63 }
64 /**
65 * @param string $path
66 * @return bool
67 */
68 public function pathExists(string $path)
69 {
70 list($interface, $method) = explode('/', $path);
71 return isset($this->restConfig['interfaces'][$interface][$method]);
72 }
73 /**
74 * @param string $path
75 * @param Message $message
76 * @param array $headers
77 * @return RequestInterface
78 * @throws ValidationException
79 */
80 public function build(string $path, Message $message, array $headers = [])
81 {
82 list($interface, $method) = explode('/', $path);
83 if (!isset($this->restConfig['interfaces'][$interface][$method])) {
84 throw new ValidationException("Failed to build request, as the provided path ({$path}) was not found in the configuration.");
85 }
86 $numericEnums = isset($this->restConfig['numericEnums']) && $this->restConfig['numericEnums'];
87 $methodConfig = $this->restConfig['interfaces'][$interface][$method] + ['placeholders' => [], 'body' => null, 'additionalBindings' => null];
88 $bindings = $this->buildBindings($methodConfig['placeholders'], $message);
89 $uriTemplateConfigs = $this->getConfigsForUriTemplates($methodConfig);
90 foreach ($uriTemplateConfigs as $config) {
91 $pathTemplate = $this->tryRenderPathTemplate($config['uriTemplate'], $bindings);
92 if ($pathTemplate) {
93 // We found a valid uriTemplate - now build and return the Request
94 list($body, $queryParams) = $this->constructBodyAndQueryParameters($message, $config);
95 // Request enum fields will be encoded as numbers rather than strings (in the response).
96 if ($numericEnums) {
97 $queryParams['$alt'] = "json;enum-encoding=int";
98 }
99 $uri = $this->buildUri($pathTemplate, $queryParams);
100 return new Request($config['method'], $uri, ['Content-Type' => 'application/json'] + $headers, $body);
101 }
102 }
103 // No valid uriTemplate found - construct an exception
104 $uriTemplates = [];
105 foreach ($uriTemplateConfigs as $config) {
106 $uriTemplates[] = $config['uriTemplate'];
107 }
108 throw new ValidationException("Could not map bindings for {$path} to any Uri template.\n" . "Bindings: " . print_r($bindings, \true) . "UriTemplates: " . print_r($uriTemplates, \true));
109 }
110 /**
111 * Create a list of all possible configs using the additionalBindings
112 *
113 * @param array $config
114 * @return array[] An array of configs
115 */
116 private function getConfigsForUriTemplates(array $config)
117 {
118 $configs = [$config];
119 if ($config['additionalBindings']) {
120 foreach ($config['additionalBindings'] as $additionalBinding) {
121 $configs[] = $additionalBinding + $config;
122 }
123 }
124 return $configs;
125 }
126 /**
127 * @param Message $message
128 * @param array $config
129 * @return array Tuple [$body, $queryParams]
130 */
131 private function constructBodyAndQueryParameters(Message $message, array $config)
132 {
133 $messageDataJson = $message->serializeToJsonString();
134 if ($config['body'] === '*') {
135 return [$messageDataJson, []];
136 }
137 $body = null;
138 $queryParams = [];
139 $messageData = json_decode($messageDataJson, \true);
140 foreach ($messageData as $name => $value) {
141 if (array_key_exists($name, $config['placeholders'])) {
142 continue;
143 }
144 if (Serializer::toSnakeCase($name) === $config['body']) {
145 if (($bodyMessage = $message->{"get{$name}"}()) instanceof Message) {
146 $body = $bodyMessage->serializeToJsonString();
147 } else {
148 $body = json_encode($value);
149 }
150 continue;
151 }
152 if (is_array($value) && $this->isAssoc($value)) {
153 foreach ($value as $key => $value2) {
154 $queryParams[$name . '.' . $key] = $value2;
155 }
156 } else {
157 $queryParams[$name] = $value;
158 }
159 }
160 // Ensures required query params with default values are always sent
161 // over the wire.
162 if (isset($config['queryParams'])) {
163 foreach ($config['queryParams'] as $requiredQueryParam) {
164 $requiredQueryParam = Serializer::toCamelCase($requiredQueryParam);
165 if (!array_key_exists($requiredQueryParam, $queryParams)) {
166 $getter = Serializer::getGetter($requiredQueryParam);
167 $queryParamValue = $message->{$getter}();
168 if ($queryParamValue instanceof Message) {
169 // Decode message for the query parameter.
170 $queryParamValue = json_decode($queryParamValue->serializeToJsonString(), \true);
171 }
172 if (is_array($queryParamValue)) {
173 // If the message has properties, add them as nested querystring values.
174 // NOTE: This only supports nesting at one level of depth.
175 foreach ($queryParamValue as $key => $value) {
176 $queryParams[$requiredQueryParam . '.' . $key] = $value;
177 }
178 } else {
179 $queryParams[$requiredQueryParam] = $queryParamValue;
180 }
181 }
182 }
183 }
184 return [$body, $queryParams];
185 }
186 /**
187 * @param array $placeholders
188 * @param Message $message
189 * @return array Bindings from path template fields to values from message
190 */
191 private function buildBindings(array $placeholders, Message $message)
192 {
193 $bindings = [];
194 foreach ($placeholders as $placeholder => $metadata) {
195 $value = array_reduce($metadata['getters'], function (Message $result = null, $getter) {
196 if ($result) {
197 return $result->{$getter}();
198 }
199 }, $message);
200 $bindings[$placeholder] = $value;
201 }
202 return $bindings;
203 }
204 /**
205 * Try to render the resource name. The rendered resource name will always contain a leading '/'
206 *
207 * @param string $uriTemplate
208 * @param array $bindings
209 * @return null|string
210 * @throws ValidationException
211 */
212 private function tryRenderPathTemplate(string $uriTemplate, array $bindings)
213 {
214 $template = new AbsoluteResourceTemplate($uriTemplate);
215 try {
216 return $template->render($bindings);
217 } catch (ValidationException $e) {
218 return null;
219 }
220 }
221 /**
222 * @param string $path
223 * @param array $queryParams
224 * @return UriInterface
225 */
226 private function buildUri(string $path, array $queryParams)
227 {
228 $uri = Utils::uriFor(sprintf('https://%s%s', $this->baseUri, $path));
229 if ($queryParams) {
230 $uri = $this->buildUriWithQuery($uri, $queryParams);
231 }
232 return $uri;
233 }
234 }
235