PageRenderTime 160ms CodeModel.GetById 85ms RepoModel.GetById 1ms app.codeStats 0ms

/RuaApp/libraries/opensocial/osapi/io/osapiRestIO.php

https://github.com/webvpro/RUA-CORE
PHP | 235 lines | 151 code | 22 blank | 62 comment | 43 complexity | 9b190436142bd548d03cad0b632a75b1 MD5 | raw file
  1. <?php
  2. /*
  3. * Copyright 2008 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. * The REST based implementation of the IO layer. This class
  19. * sends the batched requests one by one to the REST endpoint
  20. *
  21. * @author Chris Chabot
  22. */
  23. class osapiRestIO extends osapiIO {
  24. // URL templates used to construct the REST requests
  25. private static $urlTemplates = array(
  26. 'people' => 'people/{userId}/{groupId}/{personId}',
  27. 'activities' => 'activities/{userId}/{groupId}/{appId}/{activityId}',
  28. 'appdata' => 'appdata/{userId}/{groupId}/{appId}',
  29. 'messages' => 'messages/{userId}/outbox/{msgId}',
  30. 'albums'=>'albums/{userId}/{groupId}/{albumId}',
  31. 'mediaItems'=>'mediaItems/{userId}/{groupId}/{albumId}/{mediaItemId}',
  32. 'groups'=>'groups/{userId}',
  33. // MySpace Specific
  34. 'statusmood'=>'statusmood/{userId}/{groupId}/{friendId}/{moodId}/{history}',
  35. 'notifications'=>'notifications/{userId}/{groupId}',
  36. 'profilecomments'=>'profilecomments/{userId}/{groupId}'
  37. );
  38. // Array used to resolve the method to the correct HTTP operation
  39. private static $methodAliases = array(
  40. 'get' => 'GET',
  41. 'create' => 'POST',
  42. 'delete' => 'DELETE',
  43. 'update' => 'PUT',
  44. 'upload'=>'POST',
  45. 'getSupportedFields'=>'GET',
  46. 'getSupportedMood'=>'GET'
  47. );
  48. // Array used to define which field in the params array is supposed to be the post body
  49. private static $postAliases = array(
  50. 'people' => 'person',
  51. 'activities' => 'activity',
  52. 'appdata' => 'data',
  53. 'messages' => 'message',
  54. 'albums'=>'album',
  55. 'mediaItems'=>'mediaItem',
  56. 'statusmood'=>'statusMood',
  57. 'notifications'=>'notification'
  58. );
  59. /**
  60. * Sends the batched requests to the REST endpoint, the actual sending
  61. * is done in self::executeRestRequest()
  62. *
  63. * @param array $requests
  64. * @param osapiProvider $provider
  65. * @param osapiAuth $signer
  66. * @return array results
  67. */
  68. public static function sendBatch(Array $requests, osapiProvider $provider, osapiAuth $signer, $strictMode = false) {
  69. $ret = array();
  70. foreach ($requests as $request) {
  71. $entry = self::executeRestRequest($request, $provider, $signer);
  72. // flip 'entry' to 'list' so the result structure processing can be the same between the RPC and REST implementations
  73. if (!$entry instanceof osapiError) {
  74. if (isset($entry['data']['entry'])) {
  75. $entry['data']['list'] = $entry['data']['entry'];
  76. unset($entry['data']['entry']);
  77. }
  78. if (isset($entry['data']['list']) && count($entry['data']) != 1) {
  79. foreach ($entry['data']['list'] as $key => $val) {
  80. $entry['data']['list'][$key] = self::convertArray($request, $val, $strictMode);
  81. }
  82. $entry['data'] = self::listToCollection($entry['data'], $strictMode);
  83. } else {
  84. if (isset($entry['data']['list'])) {
  85. $entry['data'] = self::convertArray($request, $entry['data']['list'], $strictMode);
  86. }else{
  87. $entry['data'] = self::convertArray($request, $entry['data'], $strictMode);
  88. }
  89. }
  90. }
  91. if (isset($request->id)) {
  92. $ret[$request->id] = is_array($entry) && isset($entry['data']) ? $entry['data'] : $entry;
  93. } else {
  94. $ret[] = $entry;
  95. }
  96. }
  97. if (method_exists($provider, 'postParseResponseProcess')) {
  98. $provider->postParseResponseProcess($request, $ret);
  99. }
  100. return $ret;
  101. }
  102. /**
  103. * Performs the actual REST request by rewriting
  104. * the method (people.get) to the proper REST endpoint
  105. * and converting the params into a properly formed
  106. * REST url
  107. *
  108. * @param osapiRequest $request
  109. * @return array decoded response body
  110. */
  111. private static function executeRestRequest(osapiRequest $request, osapiProvider $provider, osapiAuth $signer) {
  112. $service = $request->getService($request->method);
  113. $operation = $request->getOperation($request->method);
  114. if (! isset(self::$urlTemplates[$service])) {
  115. throw new osapiException("Invalid service: $service");
  116. }
  117. $urlTemplate = self::$urlTemplates[$service];
  118. if (! isset(self::$methodAliases[$operation])) {
  119. throw new osapiException("Invalid method: ($service) $operation");
  120. }
  121. $method = self::$methodAliases[$operation];
  122. $postBody = false;
  123. $headers = false;
  124. $hasPostBody = false;
  125. if ($method != 'GET') {
  126. if (isset(self::$postAliases[$service]) && isset($request->params[self::$postAliases[$service]])) {
  127. $hasPostBody = true;
  128. $headers = array("Content-Type: application/json");
  129. if($request->method == 'mediaItems.upload'){
  130. $postBody = $request->params[self::$postAliases[$service]];
  131. $headers = array("Content-Type: " . $request->params['contentType'], 'Expect:');
  132. unset($request->params['contentType']);
  133. }
  134. }
  135. }
  136. $baseUrl = $provider->restEndpoint;
  137. if (substr($baseUrl, strlen($baseUrl) - 1, 1) == '/') {
  138. // Prevent double //'s in the url when concatinating
  139. $baseUrl = substr($baseUrl, 0, strlen($baseUrl) - 1);
  140. }
  141. if (method_exists($provider, 'preRequestProcess')) {
  142. // Note that we're passing baseUrl, not the complete service URL.
  143. // It should be easier to change service parameters by changing
  144. // the params array than modifying a string url.
  145. $provider->preRequestProcess($request, $method, $baseUrl, $headers, $signer);
  146. }
  147. if ($hasPostBody) {
  148. if($request->method == 'mediaItems.upload') {
  149. // If we are uploading a mediaItem don't try to json_encode it.
  150. $postBody = $request->params[self::$postAliases[$service]];
  151. }else {
  152. // Pull out the (possibly) modified post body parameter and
  153. // unset it from the request, so that it doesn't get signed.
  154. $postBody = json_encode($request->params[self::$postAliases[$service]]);
  155. }
  156. unset($request->params[self::$postAliases[$service]]);
  157. }
  158. $url = $baseUrl . self::constructUrl($urlTemplate, $request->params);
  159. if (! $provider->isOpenSocial) {
  160. // PortableContacts end points don't require the /people bit added
  161. $url = str_replace('/people', '', $url);
  162. }
  163. $signedUrl = $signer->sign($method, $url, $request->params, $postBody, $headers);
  164. $response = self::send($signedUrl, $method, $provider->httpProvider, $headers, $postBody);
  165. if (method_exists($provider, 'postRequestProcess')) {
  166. $provider->postRequestProcess($request, $response);
  167. }
  168. $ret = array();
  169. // Added 201 for create requests
  170. if (($response['http_code'] == '200' || $response['http_code'] == '201') && !empty($response['data'])) {
  171. $ret['data'] = json_decode($response['data'], true);
  172. if ($ret['data'] == $response['data']) {
  173. // signals a failure in decoding the json
  174. throw new osapiException("Error decoding server response: '" . $response['data'] . "'");
  175. }
  176. } else {
  177. $ret = new osapiError($response['http_code'], isset($response['data']) ? $response['data'] : '');
  178. }
  179. return $ret;
  180. }
  181. /**
  182. * Fill in the URL based on the service template, anything that's not part of the URL is posted as query param
  183. * The url components are removed from the params so they are passed by reference
  184. * @param string $template the url template
  185. * @param $params Array parameters
  186. * @return string url
  187. */
  188. private static function constructUrl($urlTemplate, &$params) {
  189. $url = '';
  190. $urlParts = explode('/', $urlTemplate);
  191. foreach ($urlParts as $part) {
  192. if (substr($part, 0, 1) == '{' && substr($part, strlen($part) - 1, 1) == '}') {
  193. $tag = substr($part, 1, strlen($part) - 2);
  194. if (isset($params[$tag])) {
  195. $url .= '/' . (is_array($params[$tag]) ? implode(',', $params[$tag]) : $params[$tag]);
  196. unset($params[$tag]);
  197. }
  198. } else {
  199. $url .= '/' . $part;
  200. }
  201. }
  202. // Everything that was a part of the url template has been removed from the array, so what's left are the query params
  203. if (count($params)) {
  204. foreach ($params as $key => $val) {
  205. if (is_array($val)) {
  206. $val = implode(',', $val);
  207. }
  208. $url .= ((strpos($url, '?') === false) ? '?' : '&') . urlencode($key) . '=' . urlencode($val);
  209. }
  210. }
  211. return $url;
  212. }
  213. }