restservices.class.inc.php 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. <?php
  2. // Copyright (C) 2013 Combodo SARL
  3. //
  4. // This file is part of iTop.
  5. //
  6. // iTop is free software; you can redistribute it and/or modify
  7. // it under the terms of the GNU Affero General Public License as published by
  8. // the Free Software Foundation, either version 3 of the License, or
  9. // (at your option) any later version.
  10. //
  11. // iTop is distributed in the hope that it will be useful,
  12. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. // GNU Affero General Public License for more details.
  15. //
  16. // You should have received a copy of the GNU Affero General Public License
  17. // along with iTop. If not, see <http://www.gnu.org/licenses/>
  18. /**
  19. * REST/json services
  20. *
  21. * Definition of common structures + the very minimum service provider (manage objects)
  22. *
  23. * @package REST Services
  24. * @copyright Copyright (C) 2013 Combodo SARL
  25. * @license http://opensource.org/licenses/AGPL-3.0
  26. * @api
  27. */
  28. /**
  29. * Element of the response formed by RestResultWithObjects
  30. *
  31. * @package REST Services
  32. */
  33. class ObjectResult
  34. {
  35. public $code;
  36. public $message;
  37. public $fields;
  38. /**
  39. * Default constructor
  40. */
  41. public function __construct()
  42. {
  43. $this->code = RestResult::OK;
  44. $this->message = '';
  45. $this->fields = array();
  46. }
  47. /**
  48. * Helper to make an output value for a given attribute
  49. *
  50. * @param DBObject $oObject The object being reported
  51. * @param string $sAttCode The attribute code (must be valid)
  52. * @return string A scalar representation of the value
  53. */
  54. protected function MakeResultValue(DBObject $oObject, $sAttCode)
  55. {
  56. if ($sAttCode == 'id')
  57. {
  58. $value = $oObject->GetKey();
  59. }
  60. else
  61. {
  62. $sClass = get_class($oObject);
  63. $oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
  64. if ($oAttDef instanceof AttributeLinkedSet)
  65. {
  66. $value = array();
  67. // Make the list of required attributes
  68. // - Skip attributes pointing to the current object (redundant data)
  69. // - Skip link sets refering to the current data (infinite recursion!)
  70. $aRelevantAttributes = array();
  71. $sLnkClass = $oAttDef->GetLinkedClass();
  72. foreach (MetaModel::ListAttributeDefs($sLnkClass) as $sLnkAttCode => $oLnkAttDef)
  73. {
  74. // Skip any attribute of the link that points to the current object
  75. //
  76. if ($sLnkAttCode == $oAttDef->GetExtKeyToMe()) continue;
  77. if (method_exists($oLnkAttDef, 'GetKeyAttCode'))
  78. {
  79. if ($oLnkAttDef->GetKeyAttCode() ==$oAttDef->GetExtKeyToMe()) continue;
  80. }
  81. $aRelevantAttributes[] = $sLnkAttCode;
  82. }
  83. // Iterate on the set and build an array of array of attcode=>value
  84. $oSet = $oObject->Get($sAttCode);
  85. while ($oLnk = $oSet->Fetch())
  86. {
  87. $aLnkValues = array();
  88. foreach ($aRelevantAttributes as $sLnkAttCode)
  89. {
  90. $aLnkValues[$sLnkAttCode] = $this->MakeResultValue($oLnk, $sLnkAttCode);
  91. }
  92. $value[] = $aLnkValues;
  93. }
  94. }
  95. elseif ($oAttDef->IsExternalKey())
  96. {
  97. $value = $oObject->Get($sAttCode);
  98. }
  99. else
  100. {
  101. // Still to be refined...
  102. $value = $oObject->GetEditValue($sAttCode);
  103. }
  104. }
  105. return $value;
  106. }
  107. /**
  108. * Report the value for the given object attribute
  109. *
  110. * @param DBObject $oObject The object being reported
  111. * @param string $sAttCode The attribute code (must be valid)
  112. * @return void
  113. */
  114. public function AddField(DBObject $oObject, $sAttCode)
  115. {
  116. $this->fields[$sAttCode] = $this->MakeResultValue($oObject, $sAttCode);
  117. }
  118. }
  119. /**
  120. * REST response for services managing objects. Derive this structure to add information and/or constants
  121. *
  122. * @package Extensibility
  123. * @package REST Services
  124. * @api
  125. */
  126. class RestResultWithObjects extends RestResult
  127. {
  128. public $objects;
  129. /**
  130. * Report the given object
  131. *
  132. * @param int An error code (RestResult::OK is no issue has been found)
  133. * @param string $sMessage Description of the error if any, an empty string otherwise
  134. * @param DBObject $oObject The object being reported
  135. * @param array $aFields An array of attribute codes. List of the attributes to be reported.
  136. * @return void
  137. */
  138. public function AddObject($iCode, $sMessage, $oObject = null, $aFields = null)
  139. {
  140. $oObjRes = new ObjectResult();
  141. $oObjRes->code = $iCode;
  142. $oObjRes->message = $sMessage;
  143. if ($oObject)
  144. {
  145. foreach ($aFields as $sAttCode)
  146. {
  147. $oObjRes->AddField($oObject, $sAttCode);
  148. }
  149. }
  150. $this->objects[] = $oObjRes;
  151. }
  152. }
  153. /**
  154. * Implementation of core REST services (create/get/update... objects)
  155. *
  156. * @package Core
  157. */
  158. class CoreServices implements iRestServiceProvider
  159. {
  160. /**
  161. * Enumerate services delivered by this class
  162. *
  163. * @param string $sVersion The version (e.g. 1.0) supported by the services
  164. * @return array An array of hash 'verb' => verb, 'description' => description
  165. */
  166. public function ListOperations($sVersion)
  167. {
  168. $aOps = array();
  169. if ($sVersion == '1.0')
  170. {
  171. $aOps[] = array(
  172. 'verb' => 'core/create',
  173. 'description' => 'Create an object'
  174. );
  175. $aOps[] = array(
  176. 'verb' => 'core/update',
  177. 'description' => 'Update an object'
  178. );
  179. $aOps[] = array(
  180. 'verb' => 'core/get',
  181. 'description' => 'Search for objects'
  182. );
  183. }
  184. return $aOps;
  185. }
  186. /**
  187. * Enumerate services delivered by this class
  188. * @param string $sVersion The version (e.g. 1.0) supported by the services
  189. * @return RestResult The standardized result structure (at least a message)
  190. * @throws Exception in case of internal failure.
  191. */
  192. public function ExecOperation($sVersion, $sVerb, $aParams)
  193. {
  194. $oResult = new RestResultWithObjects();
  195. switch ($sVerb)
  196. {
  197. case 'core/create':
  198. RestUtils::InitTrackingComment($aParams);
  199. $sClass = RestUtils::GetClass($aParams, 'class');
  200. $aFields = RestUtils::GetMandatoryParam($aParams, 'fields');
  201. $aShowFields = RestUtils::GetFieldList($sClass, $aParams, 'output_fields');
  202. $oObject = RestUtils::MakeObjectFromFields($sClass, $aFields);
  203. $oObject->DBInsert();
  204. $oResult->AddObject(0, 'created', $oObject, $aShowFields);
  205. break;
  206. case 'core/update':
  207. RestUtils::InitTrackingComment($aParams);
  208. $sClass = RestUtils::GetClass($aParams, 'class');
  209. $key = RestUtils::GetMandatoryParam($aParams, 'key');
  210. $aFields = RestUtils::GetMandatoryParam($aParams, 'fields');
  211. $aShowFields = RestUtils::GetFieldList($sClass, $aParams, 'output_fields');
  212. $oObject = RestUtils::FindObjectFromKey($sClass, $key);
  213. RestUtils::UpdateObjectFromFields($oObject, $aFields);
  214. $oObject->DBUpdate();
  215. $oResult->AddObject(0, 'updated', $oObject, $aShowFields);
  216. break;
  217. case 'core/get':
  218. $sClass = RestUtils::GetClass($aParams, 'class');
  219. $key = RestUtils::GetMandatoryParam($aParams, 'key');
  220. $aShowFields = RestUtils::GetFieldList($sClass, $aParams, 'output_fields');
  221. $oObjectSet = RestUtils::GetObjectSetFromKey($sClass, $key);
  222. while ($oObject = $oObjectSet->Fetch())
  223. {
  224. $oResult->AddObject(0, '', $oObject, $aShowFields);
  225. }
  226. $oResult->message = "Found: ".$oObjectSet->Count();
  227. break;
  228. default:
  229. // unknown operation: handled at a higher level
  230. }
  231. return $oResult;
  232. }
  233. }