Subversion Repositories cheapmusic

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
103 - 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
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;
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
    // code for leading slash
259
    $requestUrl = $this->servicePath . $restPath;
260
    if ($this->rootUrl) {
261
      if ('/' !== substr($this->rootUrl, -1) && '/' !== substr($requestUrl, 0, 1)) {
262
        $requestUrl = '/' . $requestUrl;
263
      }
264
      $requestUrl = $this->rootUrl . $requestUrl;
265
    }
266
    $uriTemplateVars = array();
267
    $queryVars = array();
268
    foreach ($params as $paramName => $paramSpec) {
269
      if ($paramSpec['type'] == 'boolean') {
270
        $paramSpec['value'] = $paramSpec['value'] ? 'true' : 'false';
271
      }
272
      if ($paramSpec['location'] == 'path') {
273
        $uriTemplateVars[$paramName] = $paramSpec['value'];
274
      } else if ($paramSpec['location'] == 'query') {
275
        if (isset($paramSpec['repeated']) && is_array($paramSpec['value'])) {
276
          foreach ($paramSpec['value'] as $value) {
277
            $queryVars[] = $paramName . '=' . rawurlencode(rawurldecode($value));
278
          }
279
        } else {
280
          $queryVars[] = $paramName . '=' . rawurlencode(rawurldecode($paramSpec['value']));
281
        }
282
      }
283
    }
284
 
285
    if (count($uriTemplateVars)) {
286
      $uriTemplateParser = new Google_Utils_UriTemplate();
287
      $requestUrl = $uriTemplateParser->parse($requestUrl, $uriTemplateVars);
288
    }
289
 
290
    if (count($queryVars)) {
291
      $requestUrl .= '?' . implode($queryVars, '&');
292
    }
293
 
294
    return $requestUrl;
295
  }
296
}