1 | <?php |
||||
2 | /** |
||||
3 | * Copyright 2010 Google Inc. |
||||
4 | * |
||||
5 | * Licensed under the Apache License, Version 2.0 (the "License"); |
||||
6 | * you may not use this file except in compliance with the License. |
||||
7 | * You may obtain a copy of the License at |
||||
8 | * |
||||
9 | * http://www.apache.org/licenses/LICENSE-2.0 |
||||
10 | * |
||||
11 | * Unless required by applicable law or agreed to in writing, software |
||||
12 | * distributed under the License is distributed on an "AS IS" BASIS, |
||||
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
14 | * See the License for the specific language governing permissions and |
||||
15 | * limitations under the License. |
||||
16 | */ |
||||
17 | |||||
18 | use GuzzleHttp\Psr7\Request; |
||||
19 | |||||
20 | /** |
||||
21 | * Implements the actual methods/resources of the discovered Google API using magic function |
||||
22 | * calling overloading (__call()), which on call will see if the method name (plus.activities.list) |
||||
23 | * is available in this service, and if so construct an apiHttpRequest representing it. |
||||
24 | * |
||||
25 | */ |
||||
26 | class Google_Service_Resource |
||||
27 | { |
||||
28 | // Valid query parameters that work, but don't appear in discovery. |
||||
29 | private $stackParameters = array( |
||||
30 | 'alt' => array('type' => 'string', 'location' => 'query'), |
||||
31 | 'fields' => array('type' => 'string', 'location' => 'query'), |
||||
32 | 'trace' => array('type' => 'string', 'location' => 'query'), |
||||
33 | 'userIp' => array('type' => 'string', 'location' => 'query'), |
||||
34 | 'quotaUser' => array('type' => 'string', 'location' => 'query'), |
||||
35 | 'data' => array('type' => 'string', 'location' => 'body'), |
||||
36 | 'mimeType' => array('type' => 'string', 'location' => 'header'), |
||||
37 | 'uploadType' => array('type' => 'string', 'location' => 'query'), |
||||
38 | 'mediaUpload' => array('type' => 'complex', 'location' => 'query'), |
||||
39 | 'prettyPrint' => array('type' => 'string', 'location' => 'query'), |
||||
40 | ); |
||||
41 | |||||
42 | /** @var string $rootUrl */ |
||||
43 | private $rootUrl; |
||||
44 | |||||
45 | /** @var Google_Client $client */ |
||||
46 | private $client; |
||||
47 | |||||
48 | /** @var string $serviceName */ |
||||
49 | private $serviceName; |
||||
50 | |||||
51 | /** @var string $servicePath */ |
||||
52 | private $servicePath; |
||||
53 | |||||
54 | /** @var string $resourceName */ |
||||
55 | private $resourceName; |
||||
56 | |||||
57 | /** @var array $methods */ |
||||
58 | private $methods; |
||||
59 | |||||
60 | public function __construct($service, $serviceName, $resourceName, $resource) |
||||
61 | { |
||||
62 | $this->rootUrl = $service->rootUrl; |
||||
63 | $this->client = $service->getClient(); |
||||
64 | $this->servicePath = $service->servicePath; |
||||
65 | $this->serviceName = $serviceName; |
||||
66 | $this->resourceName = $resourceName; |
||||
67 | $this->methods = is_array($resource) && isset($resource['methods']) ? |
||||
68 | $resource['methods'] : |
||||
69 | array($resourceName => $resource); |
||||
70 | } |
||||
71 | |||||
72 | /** |
||||
73 | * TODO: This function needs simplifying. |
||||
74 | * @param $name |
||||
75 | * @param $arguments |
||||
76 | * @param $expectedClass - optional, the expected class name |
||||
0 ignored issues
–
show
Documentation
Bug
introduced
by
![]() |
|||||
77 | * @return Google_Http_Request|expectedClass |
||||
78 | * @throws Google_Exception |
||||
79 | */ |
||||
80 | public function call($name, $arguments, $expectedClass = null) |
||||
81 | { |
||||
82 | if (! isset($this->methods[$name])) { |
||||
83 | $this->client->getLogger()->error( |
||||
84 | 'Service method unknown', |
||||
85 | array( |
||||
86 | 'service' => $this->serviceName, |
||||
87 | 'resource' => $this->resourceName, |
||||
88 | 'method' => $name |
||||
89 | ) |
||||
90 | ); |
||||
91 | |||||
92 | throw new Google_Exception( |
||||
93 | "Unknown function: " . |
||||
94 | "{$this->serviceName}->{$this->resourceName}->{$name}()" |
||||
95 | ); |
||||
96 | } |
||||
97 | $method = $this->methods[$name]; |
||||
98 | $parameters = $arguments[0]; |
||||
99 | |||||
100 | // postBody is a special case since it's not defined in the discovery |
||||
101 | // document as parameter, but we abuse the param entry for storing it. |
||||
102 | $postBody = null; |
||||
103 | if (isset($parameters['postBody'])) { |
||||
104 | if ($parameters['postBody'] instanceof Google_Model) { |
||||
105 | // In the cases the post body is an existing object, we want |
||||
106 | // to use the smart method to create a simple object for |
||||
107 | // for JSONification. |
||||
108 | $parameters['postBody'] = $parameters['postBody']->toSimpleObject(); |
||||
109 | } else if (is_object($parameters['postBody'])) { |
||||
110 | // If the post body is another kind of object, we will try and |
||||
111 | // wrangle it into a sensible format. |
||||
112 | $parameters['postBody'] = |
||||
113 | $this->convertToArrayAndStripNulls($parameters['postBody']); |
||||
114 | } |
||||
115 | $postBody = (array) $parameters['postBody']; |
||||
116 | unset($parameters['postBody']); |
||||
117 | } |
||||
118 | |||||
119 | // TODO: optParams here probably should have been |
||||
120 | // handled already - this may well be redundant code. |
||||
121 | if (isset($parameters['optParams'])) { |
||||
122 | $optParams = $parameters['optParams']; |
||||
123 | unset($parameters['optParams']); |
||||
124 | $parameters = array_merge($parameters, $optParams); |
||||
125 | } |
||||
126 | |||||
127 | if (!isset($method['parameters'])) { |
||||
128 | $method['parameters'] = array(); |
||||
129 | } |
||||
130 | |||||
131 | $method['parameters'] = array_merge( |
||||
132 | $this->stackParameters, |
||||
133 | $method['parameters'] |
||||
134 | ); |
||||
135 | |||||
136 | foreach ($parameters as $key => $val) { |
||||
137 | if ($key != 'postBody' && ! isset($method['parameters'][$key])) { |
||||
138 | $this->client->getLogger()->error( |
||||
139 | 'Service parameter unknown', |
||||
140 | array( |
||||
141 | 'service' => $this->serviceName, |
||||
142 | 'resource' => $this->resourceName, |
||||
143 | 'method' => $name, |
||||
144 | 'parameter' => $key |
||||
145 | ) |
||||
146 | ); |
||||
147 | throw new Google_Exception("($name) unknown parameter: '$key'"); |
||||
148 | } |
||||
149 | } |
||||
150 | |||||
151 | foreach ($method['parameters'] as $paramName => $paramSpec) { |
||||
152 | if (isset($paramSpec['required']) && |
||||
153 | $paramSpec['required'] && |
||||
154 | ! isset($parameters[$paramName]) |
||||
155 | ) { |
||||
156 | $this->client->getLogger()->error( |
||||
157 | 'Service parameter missing', |
||||
158 | array( |
||||
159 | 'service' => $this->serviceName, |
||||
160 | 'resource' => $this->resourceName, |
||||
161 | 'method' => $name, |
||||
162 | 'parameter' => $paramName |
||||
163 | ) |
||||
164 | ); |
||||
165 | throw new Google_Exception("($name) missing required param: '$paramName'"); |
||||
166 | } |
||||
167 | if (isset($parameters[$paramName])) { |
||||
168 | $value = $parameters[$paramName]; |
||||
169 | $parameters[$paramName] = $paramSpec; |
||||
170 | $parameters[$paramName]['value'] = $value; |
||||
171 | unset($parameters[$paramName]['required']); |
||||
172 | } else { |
||||
173 | // Ensure we don't pass nulls. |
||||
174 | unset($parameters[$paramName]); |
||||
175 | } |
||||
176 | } |
||||
177 | |||||
178 | $this->client->getLogger()->info( |
||||
179 | 'Service Call', |
||||
180 | array( |
||||
181 | 'service' => $this->serviceName, |
||||
182 | 'resource' => $this->resourceName, |
||||
183 | 'method' => $name, |
||||
184 | 'arguments' => $parameters, |
||||
185 | ) |
||||
186 | ); |
||||
187 | |||||
188 | // build the service uri |
||||
189 | $url = $this->createRequestUri( |
||||
190 | $method['path'], |
||||
191 | $parameters |
||||
192 | ); |
||||
193 | |||||
194 | // NOTE: because we're creating the request by hand, |
||||
195 | // and because the service has a rootUrl property |
||||
196 | // the "base_uri" of the Http Client is not accounted for |
||||
197 | $request = new Request( |
||||
198 | $method['httpMethod'], |
||||
199 | $url, |
||||
200 | ['content-type' => 'application/json'], |
||||
201 | $postBody ? json_encode($postBody) : '' |
||||
202 | ); |
||||
203 | |||||
204 | // support uploads |
||||
205 | if (isset($parameters['data'])) { |
||||
206 | $mimeType = isset($parameters['mimeType']) |
||||
207 | ? $parameters['mimeType']['value'] |
||||
208 | : 'application/octet-stream'; |
||||
209 | $data = $parameters['data']['value']; |
||||
210 | $upload = new Google_Http_MediaFileUpload($this->client, $request, $mimeType, $data); |
||||
211 | |||||
212 | // pull down the modified request |
||||
213 | $request = $upload->getRequest(); |
||||
214 | } |
||||
215 | |||||
216 | // if this is a media type, we will return the raw response |
||||
217 | // rather than using an expected class |
||||
218 | if (isset($parameters['alt']) && $parameters['alt']['value'] == 'media') { |
||||
219 | $expectedClass = null; |
||||
220 | } |
||||
221 | |||||
222 | // if the client is marked for deferring, rather than |
||||
223 | // execute the request, return the response |
||||
224 | if ($this->client->shouldDefer()) { |
||||
225 | // @TODO find a better way to do this |
||||
226 | $request = $request |
||||
227 | ->withHeader('X-Php-Expected-Class', $expectedClass); |
||||
228 | |||||
229 | return $request; |
||||
0 ignored issues
–
show
|
|||||
230 | } |
||||
231 | |||||
232 | return $this->client->execute($request, $expectedClass); |
||||
233 | } |
||||
234 | |||||
235 | protected function convertToArrayAndStripNulls($o) |
||||
236 | { |
||||
237 | $o = (array) $o; |
||||
238 | foreach ($o as $k => $v) { |
||||
239 | if ($v === null) { |
||||
240 | unset($o[$k]); |
||||
241 | } elseif (is_object($v) || is_array($v)) { |
||||
242 | $o[$k] = $this->convertToArrayAndStripNulls($o[$k]); |
||||
243 | } |
||||
244 | } |
||||
245 | return $o; |
||||
246 | } |
||||
247 | |||||
248 | /** |
||||
249 | * Parse/expand request parameters and create a fully qualified |
||||
250 | * request uri. |
||||
251 | * @static |
||||
252 | * @param string $restPath |
||||
253 | * @param array $params |
||||
254 | * @return string $requestUrl |
||||
255 | */ |
||||
256 | public function createRequestUri($restPath, $params) |
||||
257 | { |
||||
258 | // Override the default servicePath address if the $restPath use a / |
||||
259 | if ('/' == substr($restPath, 0, 1)) { |
||||
260 | $requestUrl = substr($restPath, 1); |
||||
261 | } else { |
||||
262 | $requestUrl = $this->servicePath . $restPath; |
||||
263 | } |
||||
264 | |||||
265 | // code for leading slash |
||||
266 | if ($this->rootUrl) { |
||||
267 | if ('/' !== substr($this->rootUrl, -1) && '/' !== substr($requestUrl, 0, 1)) { |
||||
268 | $requestUrl = '/' . $requestUrl; |
||||
269 | } |
||||
270 | $requestUrl = $this->rootUrl . $requestUrl; |
||||
271 | } |
||||
272 | $uriTemplateVars = array(); |
||||
273 | $queryVars = array(); |
||||
274 | foreach ($params as $paramName => $paramSpec) { |
||||
275 | if ($paramSpec['type'] == 'boolean') { |
||||
276 | $paramSpec['value'] = $paramSpec['value'] ? 'true' : 'false'; |
||||
277 | } |
||||
278 | if ($paramSpec['location'] == 'path') { |
||||
279 | $uriTemplateVars[$paramName] = $paramSpec['value']; |
||||
280 | } else if ($paramSpec['location'] == 'query') { |
||||
281 | if (is_array($paramSpec['value'])) { |
||||
282 | foreach ($paramSpec['value'] as $value) { |
||||
283 | $queryVars[] = $paramName . '=' . rawurlencode(rawurldecode($value)); |
||||
284 | } |
||||
285 | } else { |
||||
286 | $queryVars[] = $paramName . '=' . rawurlencode(rawurldecode($paramSpec['value'])); |
||||
287 | } |
||||
288 | } |
||||
289 | } |
||||
290 | |||||
291 | if (count($uriTemplateVars)) { |
||||
292 | $uriTemplateParser = new Google_Utils_UriTemplate(); |
||||
293 | $requestUrl = $uriTemplateParser->parse($requestUrl, $uriTemplateVars); |
||||
294 | } |
||||
295 | |||||
296 | if (count($queryVars)) { |
||||
297 | $requestUrl .= '?' . implode($queryVars, '&'); |
||||
0 ignored issues
–
show
The call to
implode() has too many arguments starting with '&' .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue. If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above. ![]() |
|||||
298 | } |
||||
299 | |||||
300 | return $requestUrl; |
||||
301 | } |
||||
302 | } |
||||
303 |