PluginProbe ʕ •ᴥ•ʔ
ShareThis Dashboard for Google Analytics / trunk
ShareThis Dashboard for Google Analytics vtrunk
3.3.2 trunk 1.0.7 2.0.0 2.0.1 2.0.2 2.0.3 2.0.4 2.0.5 2.1 2.1.2 2.1.3 2.1.4 2.1.5 2.2.5 2.3.5 2.3.6 2.3.7 2.3.8 2.4.0 2.4.1 2.5.0 2.5.1 2.5.2 2.5.3 2.5.4 2.5.5 3.0.0 3.1.0 3.1.1 3.1.2 3.1.3 3.1.4 3.1.5 3.1.6 3.1.7 3.2.0 3.2.1 3.2.2 3.2.3 3.2.4 3.3.0 3.3.1
googleanalytics / lib / analytics-admin / vendor / google / gax / src / RequestBuilder.php
googleanalytics / lib / analytics-admin / vendor / google / gax / src Last commit date
Middleware 3 years ago ResourceTemplate 3 years ago Testing 3 years ago Transport 3 years ago AgentHeader.php 3 years ago ApiException.php 3 years ago ApiStatus.php 3 years ago ArrayTrait.php 3 years ago BidiStream.php 3 years ago Call.php 3 years ago ClientStream.php 3 years ago CredentialsWrapper.php 3 years ago FixedSizeCollection.php 3 years ago GPBLabel.php 3 years ago GPBType.php 3 years ago GapicClientTrait.php 3 years ago GrpcSupportTrait.php 3 years ago OperationResponse.php 3 years ago Page.php 3 years ago PageStreamingDescriptor.php 3 years ago PagedListResponse.php 3 years ago PathTemplate.php 3 years ago PollingTrait.php 3 years ago RequestBuilder.php 3 years ago RequestParamsHeaderDescriptor.php 3 years ago RetrySettings.php 3 years ago Serializer.php 3 years ago ServerStream.php 3 years ago ServerStreamingCallInterface.php 3 years ago ServiceAddressTrait.php 3 years ago UriTrait.php 3 years ago ValidationException.php 3 years ago ValidationTrait.php 3 years ago Version.php 3 years ago
RequestBuilder.php
278 lines
1 <?php
2 /*
3 * Copyright 2018 Google LLC
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
9 *
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above
13 * copyright notice, this list of conditions and the following disclaimer
14 * in the documentation and/or other materials provided with the
15 * distribution.
16 * * Neither the name of Google Inc. nor the names of its
17 * contributors may be used to endorse or promote products derived from
18 * this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 namespace Google\ApiCore;
34
35 use Google\ApiCore\ResourceTemplate\AbsoluteResourceTemplate;
36 use Google\Protobuf\Internal\Message;
37 use GuzzleHttp\Psr7\Request;
38 use GuzzleHttp\Psr7\Utils;
39 use Psr\Http\Message\RequestInterface;
40 use Psr\Http\Message\UriInterface;
41
42 /**
43 * Builds a PSR-7 request from a set of request information.
44 *
45 * @internal
46 */
47 class RequestBuilder
48 {
49 use ArrayTrait;
50 use UriTrait;
51 use ValidationTrait;
52
53 private $baseUri;
54 private $restConfig;
55
56 /**
57 * @param string $baseUri
58 * @param string $restConfigPath
59 * @throws ValidationException
60 */
61 public function __construct(string $baseUri, string $restConfigPath)
62 {
63 self::validateFileExists($restConfigPath);
64 $this->baseUri = $baseUri;
65 $this->restConfig = require($restConfigPath);
66 }
67
68 /**
69 * @param string $path
70 * @return bool
71 */
72 public function pathExists(string $path)
73 {
74 list($interface, $method) = explode('/', $path);
75 return isset($this->restConfig['interfaces'][$interface][$method]);
76 }
77
78 /**
79 * @param string $path
80 * @param Message $message
81 * @param array $headers
82 * @return RequestInterface
83 * @throws ValidationException
84 */
85 public function build(string $path, Message $message, array $headers = [])
86 {
87 list($interface, $method) = explode('/', $path);
88
89 if (!isset($this->restConfig['interfaces'][$interface][$method])) {
90 throw new ValidationException(
91 "Failed to build request, as the provided path ($path) was not found in the configuration."
92 );
93 }
94
95 $numericEnums = isset($this->restConfig['numericEnums']) && $this->restConfig['numericEnums'];
96 $methodConfig = $this->restConfig['interfaces'][$interface][$method] + [
97 'placeholders' => [],
98 'body' => null,
99 'additionalBindings' => null,
100 ];
101 $bindings = $this->buildBindings($methodConfig['placeholders'], $message);
102 $uriTemplateConfigs = $this->getConfigsForUriTemplates($methodConfig);
103
104 foreach ($uriTemplateConfigs as $config) {
105 $pathTemplate = $this->tryRenderPathTemplate($config['uriTemplate'], $bindings);
106
107 if ($pathTemplate) {
108 // We found a valid uriTemplate - now build and return the Request
109
110 list($body, $queryParams) = $this->constructBodyAndQueryParameters($message, $config);
111
112 // Request enum fields will be encoded as numbers rather than strings (in the response).
113 if ($numericEnums) {
114 $queryParams['$alt'] = "json;enum-encoding=int";
115 }
116
117 $uri = $this->buildUri($pathTemplate, $queryParams);
118
119 return new Request(
120 $config['method'],
121 $uri,
122 ['Content-Type' => 'application/json'] + $headers,
123 $body
124 );
125 }
126 }
127
128 // No valid uriTemplate found - construct an exception
129 $uriTemplates = [];
130 foreach ($uriTemplateConfigs as $config) {
131 $uriTemplates[] = $config['uriTemplate'];
132 }
133
134 throw new ValidationException("Could not map bindings for $path to any Uri template.\n" .
135 "Bindings: " . print_r($bindings, true) .
136 "UriTemplates: " . print_r($uriTemplates, true));
137 }
138
139 /**
140 * Create a list of all possible configs using the additionalBindings
141 *
142 * @param array $config
143 * @return array[] An array of configs
144 */
145 private function getConfigsForUriTemplates(array $config)
146 {
147 $configs = [$config];
148
149 if ($config['additionalBindings']) {
150 foreach ($config['additionalBindings'] as $additionalBinding) {
151 $configs[] = $additionalBinding + $config;
152 }
153 }
154
155 return $configs;
156 }
157
158 /**
159 * @param Message $message
160 * @param array $config
161 * @return array Tuple [$body, $queryParams]
162 */
163 private function constructBodyAndQueryParameters(Message $message, array $config)
164 {
165 $messageDataJson = $message->serializeToJsonString();
166
167 if ($config['body'] === '*') {
168 return [$messageDataJson, []];
169 }
170
171 $body = null;
172 $queryParams = [];
173 $messageData = json_decode($messageDataJson, true);
174 foreach ($messageData as $name => $value) {
175 if (array_key_exists($name, $config['placeholders'])) {
176 continue;
177 }
178
179 if (Serializer::toSnakeCase($name) === $config['body']) {
180 if (($bodyMessage = $message->{"get$name"}()) instanceof Message) {
181 $body = $bodyMessage->serializeToJsonString();
182 } else {
183 $body = json_encode($value);
184 }
185 continue;
186 }
187
188 if (is_array($value) && $this->isAssoc($value)) {
189 foreach ($value as $key => $value2) {
190 $queryParams[$name . '.' . $key] = $value2;
191 }
192 } else {
193 $queryParams[$name] = $value;
194 }
195 }
196
197 // Ensures required query params with default values are always sent
198 // over the wire.
199 if (isset($config['queryParams'])) {
200 foreach ($config['queryParams'] as $requiredQueryParam) {
201 $requiredQueryParam = Serializer::toCamelCase($requiredQueryParam);
202 if (!array_key_exists($requiredQueryParam, $queryParams)) {
203 $getter = Serializer::getGetter($requiredQueryParam);
204 $queryParams[$requiredQueryParam] = $message->$getter();
205 }
206 }
207 }
208
209 return [$body, $queryParams];
210 }
211
212 /**
213 * @param array $placeholders
214 * @param Message $message
215 * @return array Bindings from path template fields to values from message
216 */
217 private function buildBindings(array $placeholders, Message $message)
218 {
219 $bindings = [];
220 foreach ($placeholders as $placeholder => $metadata) {
221 $value = array_reduce(
222 $metadata['getters'],
223 function (Message $result = null, $getter) {
224 if ($result) {
225 return $result->$getter();
226 }
227 },
228 $message
229 );
230
231 $bindings[$placeholder] = $value;
232 }
233 return $bindings;
234 }
235
236 /**
237 * Try to render the resource name. The rendered resource name will always contain a leading '/'
238 *
239 * @param string $uriTemplate
240 * @param array $bindings
241 * @return null|string
242 * @throws ValidationException
243 */
244 private function tryRenderPathTemplate(string $uriTemplate, array $bindings)
245 {
246 $template = new AbsoluteResourceTemplate($uriTemplate);
247
248 try {
249 return $template->render($bindings);
250 } catch (ValidationException $e) {
251 return null;
252 }
253 }
254
255 /**
256 * @param string $path
257 * @param array $queryParams
258 * @return UriInterface
259 */
260 private function buildUri(string $path, array $queryParams)
261 {
262 $uri = Utils::uriFor(
263 sprintf(
264 'https://%s%s',
265 $this->baseUri,
266 $path
267 )
268 );
269 if ($queryParams) {
270 $uri = $this->buildUriWithQuery(
271 $uri,
272 $queryParams
273 );
274 }
275 return $uri;
276 }
277 }
278