Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.3.x will end 7 October 2024 (12 months).
  • Bug fixes for security issues in 4.3.x will end 21 April 2025 (18 months).
  • PHP version: minimum PHP 8.0.0 Note: minimum PHP version has increased since Moodle 4.1. PHP 8.2.x is supported too.

Differences Between: [Versions 310 and 403] [Versions 311 and 403] [Versions 39 and 403] [Versions 400 and 403] [Versions 401 and 403]

   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  if (!class_exists('Google_Client')) {
  19    require_once dirname(__FILE__) . '/../autoload.php';
  20  }
  21  
  22  /**
  23   * Implements the actual methods/resources of the discovered Google API using magic function
  24   * calling overloading (__call()), which on call will see if the method name (plus.activities.list)
  25   * is available in this service, and if so construct an apiHttpRequest representing it.
  26   *
  27   */
  28  #[AllowDynamicProperties]
  29  class Google_Service_Resource
  30  {
  31    // Valid query parameters that work, but don't appear in discovery.
  32    private $stackParameters = array(
  33        'alt' => array('type' => 'string', 'location' => 'query'),
  34        'fields' => array('type' => 'string', 'location' => 'query'),
  35        'trace' => array('type' => 'string', 'location' => 'query'),
  36        'userIp' => array('type' => 'string', 'location' => 'query'),
  37        'quotaUser' => array('type' => 'string', 'location' => 'query'),
  38        'data' => array('type' => 'string', 'location' => 'body'),
  39        'mimeType' => array('type' => 'string', 'location' => 'header'),
  40        'uploadType' => array('type' => 'string', 'location' => 'query'),
  41        'mediaUpload' => array('type' => 'complex', 'location' => 'query'),
  42        'prettyPrint' => array('type' => 'string', 'location' => 'query'),
  43    );
  44  
  45    /** @var string $rootUrl */
  46    private $rootUrl;
  47  
  48    /** @var Google_Client $client */
  49    private $client;
  50  
  51    /** @var string $serviceName */
  52    private $serviceName;
  53  
  54    /** @var string $servicePath */
  55    private $servicePath;
  56  
  57    /** @var string $resourceName */
  58    private $resourceName;
  59  
  60    /** @var array $methods */
  61    private $methods;
  62  
  63    public function __construct($service, $serviceName, $resourceName, $resource)
  64    {
  65      $this->rootUrl = $service->rootUrl;
  66      $this->client = $service->getClient();
  67      $this->servicePath = $service->servicePath;
  68      $this->serviceName = $serviceName;
  69      $this->resourceName = $resourceName;
  70      $this->methods = is_array($resource) && isset($resource['methods']) ?
  71          $resource['methods'] :
  72          array($resourceName => $resource);
  73    }
  74  
  75    /**
  76     * TODO: This function needs simplifying.
  77     * @param $name
  78     * @param $arguments
  79     * @param $expected_class - optional, the expected class name
  80     * @return Google_Http_Request|expected_class
  81     * @throws Google_Exception
  82     */
  83    public function call($name, $arguments, $expected_class = null)
  84    {
  85      if (! isset($this->methods[$name])) {
  86        $this->client->getLogger()->error(
  87            'Service method unknown',
  88            array(
  89                'service' => $this->serviceName,
  90                'resource' => $this->resourceName,
  91                'method' => $name
  92            )
  93        );
  94  
  95        throw new Google_Exception(
  96            "Unknown function: " .
  97            "{$this->serviceName}->{$this->resourceName}->{$name}()"
  98        );
  99      }
 100      $method = $this->methods[$name];
 101      $parameters = $arguments[0];
 102  
 103      // postBody is a special case since it's not defined in the discovery
 104      // document as parameter, but we abuse the param entry for storing it.
 105      $postBody = null;
 106      if (isset($parameters['postBody'])) {
 107        if ($parameters['postBody'] instanceof Google_Model) {
 108          // In the cases the post body is an existing object, we want
 109          // to use the smart method to create a simple object for
 110          // for JSONification.
 111          $parameters['postBody'] = $parameters['postBody']->toSimpleObject();
 112        } else if (is_object($parameters['postBody'])) {
 113          // If the post body is another kind of object, we will try and
 114          // wrangle it into a sensible format.
 115          $parameters['postBody'] =
 116              $this->convertToArrayAndStripNulls($parameters['postBody']);
 117        }
 118        $postBody = json_encode($parameters['postBody']);
 119        if ($postBody === false && $parameters['postBody'] !== false) {
 120          throw new Google_Exception("JSON encoding failed. Ensure all strings in the request are UTF-8 encoded.");
 121        }
 122        unset($parameters['postBody']);
 123      }
 124  
 125      // TODO: optParams here probably should have been
 126      // handled already - this may well be redundant code.
 127      if (isset($parameters['optParams'])) {
 128        $optParams = $parameters['optParams'];
 129        unset($parameters['optParams']);
 130        $parameters = array_merge($parameters, $optParams);
 131      }
 132  
 133      if (!isset($method['parameters'])) {
 134        $method['parameters'] = array();
 135      }
 136  
 137      $method['parameters'] = array_merge(
 138          $this->stackParameters,
 139          $method['parameters']
 140      );
 141      foreach ($parameters as $key => $val) {
 142        if ($key != 'postBody' && ! isset($method['parameters'][$key])) {
 143          $this->client->getLogger()->error(
 144              'Service parameter unknown',
 145              array(
 146                  'service' => $this->serviceName,
 147                  'resource' => $this->resourceName,
 148                  'method' => $name,
 149                  'parameter' => $key
 150              )
 151          );
 152          throw new Google_Exception("($name) unknown parameter: '$key'");
 153        }
 154      }
 155  
 156      foreach ($method['parameters'] as $paramName => $paramSpec) {
 157        if (isset($paramSpec['required']) &&
 158            $paramSpec['required'] &&
 159            ! isset($parameters[$paramName])
 160        ) {
 161          $this->client->getLogger()->error(
 162              'Service parameter missing',
 163              array(
 164                  'service' => $this->serviceName,
 165                  'resource' => $this->resourceName,
 166                  'method' => $name,
 167                  'parameter' => $paramName
 168              )
 169          );
 170          throw new Google_Exception("($name) missing required param: '$paramName'");
 171        }
 172        if (isset($parameters[$paramName])) {
 173          $value = $parameters[$paramName];
 174          $parameters[$paramName] = $paramSpec;
 175          $parameters[$paramName]['value'] = $value;
 176          unset($parameters[$paramName]['required']);
 177        } else {
 178          // Ensure we don't pass nulls.
 179          unset($parameters[$paramName]);
 180        }
 181      }
 182  
 183      $this->client->getLogger()->info(
 184          'Service Call',
 185          array(
 186              'service' => $this->serviceName,
 187              'resource' => $this->resourceName,
 188              'method' => $name,
 189              'arguments' => $parameters,
 190          )
 191      );
 192  
 193      $url = Google_Http_REST::createRequestUri(
 194          $this->servicePath,
 195          $method['path'],
 196          $parameters
 197      );
 198      $httpRequest = new Google_Http_Request(
 199          $url,
 200          $method['httpMethod'],
 201          null,
 202          $postBody
 203      );
 204  
 205      if ($this->rootUrl) {
 206        $httpRequest->setBaseComponent($this->rootUrl);
 207      } else {
 208        $httpRequest->setBaseComponent($this->client->getBasePath());
 209      }
 210  
 211      if ($postBody) {
 212        $contentTypeHeader = array();
 213        $contentTypeHeader['content-type'] = 'application/json; charset=UTF-8';
 214        $httpRequest->setRequestHeaders($contentTypeHeader);
 215        $httpRequest->setPostBody($postBody);
 216      }
 217  
 218      $httpRequest = $this->client->getAuth()->sign($httpRequest);
 219      $httpRequest->setExpectedClass($expected_class);
 220  
 221      if (isset($parameters['data']) &&
 222          ($parameters['uploadType']['value'] == 'media' || $parameters['uploadType']['value'] == 'multipart')) {
 223        // If we are doing a simple media upload, trigger that as a convenience.
 224        $mfu = new Google_Http_MediaFileUpload(
 225            $this->client,
 226            $httpRequest,
 227            isset($parameters['mimeType']) ? $parameters['mimeType']['value'] : 'application/octet-stream',
 228            $parameters['data']['value']
 229        );
 230      }
 231  
 232      if (isset($parameters['alt']) && $parameters['alt']['value'] == 'media') {
 233        $httpRequest->enableExpectedRaw();
 234      }
 235  
 236      if ($this->client->shouldDefer()) {
 237        // If we are in batch or upload mode, return the raw request.
 238        return $httpRequest;
 239      }
 240  
 241      return $this->client->execute($httpRequest);
 242    }
 243  
 244    protected function convertToArrayAndStripNulls($o)
 245    {
 246      $o = (array) $o;
 247      foreach ($o as $k => $v) {
 248        if ($v === null) {
 249          unset($o[$k]);
 250        } elseif (is_object($v) || is_array($v)) {
 251          $o[$k] = $this->convertToArrayAndStripNulls($o[$k]);
 252        }
 253      }
 254      return $o;
 255    }
 256  }