TripalWebServiceResource.inc 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  1. <?php
  2. class TripalWebServiceResource {
  3. /**
  4. * The unique identifier for this resource.
  5. */
  6. protected $id;
  7. /**
  8. * The unique type of resource. The type must exists in the
  9. * context for the web service.
  10. */
  11. protected $type;
  12. /**
  13. * The JSON-LD compatible context for this resource.
  14. */
  15. protected $context;
  16. /**
  17. * Holds the data portion of the JSON-LD response for this resource.
  18. */
  19. protected $data;
  20. /**
  21. * The URL path that the service is providing to access this resource.
  22. * This path plus the $id are concatenated to form the IRI for this resource.
  23. */
  24. protected $service_path;
  25. /**
  26. * Implements the constructor.
  27. *
  28. * @param $service_path
  29. *
  30. */
  31. public function __construct($service_path) {
  32. $this->context = array();
  33. $this->data = array();
  34. $this->service_path = $service_path;
  35. // First, add the RDFS and Hydra vocabularies to the context. All Tripal
  36. // web services should use these.
  37. $this->addContextItem('rdf', "http://www.w3.org/1999/02/22-rdf-syntax-ns#");
  38. $this->addContextItem('rdfs', 'http://www.w3.org/2000/01/rdf-schema#');
  39. $this->addContextItem('hydra', "http://www.w3.org/ns/hydra/core#");
  40. $vocab = tripal_get_vocabulary_details('dc');
  41. $this->addContextItem('dc', $vocab['url']);
  42. $vocab = tripal_get_vocabulary_details('schema');
  43. $this->addContextItem('schema', $vocab['url']);
  44. $vocab = tripal_get_vocabulary_details('local');
  45. $this->addContextItem('local', url($vocab['url'], array('absolute' => TRUE)). '/');
  46. $this->data['@id'] = $service_path;
  47. $this->data['@type'] = '';
  48. }
  49. /**
  50. * Adds a term to the '@context' section for this resource.
  51. *
  52. * This function should not be called directory. Rather, the
  53. * addContextTerm() and addContextVocab() functions built
  54. * into the TripalWebService class should be used as these will help
  55. * ensure terms are added proper for the context of the web service.
  56. *
  57. * @param $name
  58. * The term name.
  59. * @param $iri
  60. * The Internationalized Resource Identifiers or it's shortcut.
  61. *
  62. */
  63. public function addContextItem($name, $iri) {
  64. if (array_key_exists($name, $this->context)) {
  65. return;
  66. }
  67. $this->context[$name] = $iri;
  68. }
  69. /**
  70. * Removes a term for the '@context' section for this resource.
  71. *
  72. * @param $name
  73. * The term name.
  74. * @param $iri
  75. * The Internationalized Resource Identifiers or it's shortcut.
  76. */
  77. public function removeContextItem($name, $iri) {
  78. // TODO: make sure that if a shortcut is used that the parent is present.
  79. unset($this->context[$name]);
  80. }
  81. /**
  82. * Sets the resource type.
  83. *
  84. * The type exist in the context of the web service.
  85. *
  86. * @param $type
  87. * The type
  88. */
  89. public function setType($type) {
  90. $this->checkKey($type);
  91. $this->type = $type;
  92. $this->data['@type'] = $type;
  93. }
  94. /**
  95. * Checks a key to ensure it is in the Context before being used.
  96. *
  97. * This function should be used before adding a property or type to this
  98. * resource. It ensures that the key for the property is already in the
  99. * context.
  100. *
  101. * @param $key
  102. * The key to check.
  103. * @throws Exception
  104. */
  105. private function checkKey($key) {
  106. // Make sure the key is already present in the context.
  107. $keys = array_keys($this->context);
  108. // Keys that are full HTML are acceptable
  109. if (preg_match('/^(http|https):\/\/.*/', $key)) {
  110. return;
  111. }
  112. // If the key has a colon separating the vocabulary and the term then we
  113. // just need to make sure that the vocabulary is present.
  114. $matches = array();
  115. if (preg_match('/^(.*?):(.*?)$/', $key, $matches)) {
  116. $vocab = $matches[1];
  117. $accession = $matches[2];
  118. // The underscore represents the blank node. So, these keys are okay.
  119. if ($vocab == '_') {
  120. return;
  121. }
  122. // If the vocabulary is not in the.
  123. if (!in_array($vocab, $keys)) {
  124. dpm(debug_backtrace());
  125. throw new Exception("The key, '$key', has a vocabulary that has not yet been added to the " .
  126. "context. Use the addContextItem() function to add the vocabulary prior to adding a value for it.");
  127. }
  128. }
  129. else {
  130. // If the key is not in the context then throw an error.
  131. if (!in_array($key, $keys)) {
  132. dpm(debug_backtrace());
  133. throw new Exception("The key, '$key', has not yet been added to the " .
  134. "context. Use the addContextItem() function to add this key prior to adding a value for it.");
  135. }
  136. }
  137. }
  138. /**
  139. * Set's the unique identifier for the resource.
  140. *
  141. * Every resource must have a unique Idientifer. In JSON-LD the '@id' element
  142. * identifies the IRI for the resource which will include the unique
  143. * identifier. The TraiplWebService to which a resource is added will
  144. * build the IRIs but it needs the unique ID of each resource.
  145. *
  146. * @param $id
  147. * The unique identifier for the resource.
  148. */
  149. public function setID($id) {
  150. $this->id = $id;
  151. $this->data['@id'] = $this->getURI($id);
  152. }
  153. /**
  154. * Retreives the IRI for an entity of a given ID in this web service.
  155. *
  156. * @param $id
  157. * The unique identifier for the resource.
  158. */
  159. public function getURI($id) {
  160. // If this is a key/value pair for an id and if the vocab portion is
  161. // an underscore then this represents a blank node and we don't want
  162. // to add the full path.
  163. $matches = array();
  164. if (preg_match('/^(.*?):(.*?)$/', $id, $matches)) {
  165. $vocab = $matches[1];
  166. if ($vocab == '_') {
  167. return $id;
  168. }
  169. return $id;
  170. }
  171. else {
  172. return $this->service_path . '/' . $id;
  173. }
  174. }
  175. /**
  176. * Retrieves the unique identifier for this resource.
  177. *
  178. * Every resource must have a unique Idientifer. In JSON-LD the '@id' element
  179. * identifies the IRI for the resource which will include the unique
  180. * identifier. The TraiplWebService to which a resource is added will
  181. * build the IRIs but it needs the unique ID of each resource.
  182. *
  183. * @return
  184. * The unique identifier for the resource.
  185. */
  186. public function getID() {
  187. return $this->id;
  188. }
  189. /**
  190. * Retreives the type of this resource.
  191. *
  192. * @return
  193. * The name of the resource.
  194. */
  195. public function getType() {
  196. return $this->type;
  197. }
  198. /**
  199. * Adds a new key/value pair to the web serivces response.
  200. *
  201. * The value must either be a scalar or another TripalWebServiceResource
  202. * object. If the same key is usesd multiple times then the resulting
  203. * resource will be presented as an array of elements.
  204. *
  205. * @param unknown $key
  206. * The name of the $key to add. This key must already be present in the
  207. * web service context by first adding it using the addContextItem()
  208. * member function.
  209. * @param unknown $value
  210. * The value of the key which must either be a scalar or a
  211. * TripalWebServiceResource instance.
  212. */
  213. public function addProperty($key, $value) {
  214. $this->checkKey($key);
  215. // If this is a numeric array then go through each element and add them.
  216. if (is_array($value) and count(array_filter(array_keys($value), 'is_int')) == count(array_keys($value))) {
  217. if (!array_key_exists($key, $this->data)) {
  218. $this->data[$key] = array();
  219. }
  220. foreach ($value as $item) {
  221. $this->addProperty($key, $item);
  222. }
  223. return;
  224. }
  225. // If this is a TripalWebServiceResource then get it's data and use that
  226. // as the new value.
  227. if (is_a($value, 'TripalWebServiceResource') or is_subclass_of($value, 'TripalWebServiceResource')) {
  228. // Add in the context items to this resource.
  229. $context = $value->getContext();
  230. foreach ($context as $k => $v) {
  231. $this->addContextItem($k, $v);
  232. }
  233. $value = $value->getData();
  234. }
  235. // If this key doesn't exist then add the value directly to the key.
  236. if (!array_key_exists($key, $this->data)) {
  237. $this->data[$key] = $value;
  238. }
  239. // Else if it does exist then we need to make sure that the element is
  240. // an array and add it.
  241. else {
  242. // If this is the second element, then convert it to an array. The
  243. // second test in the condition below is for for a numeric array.
  244. if (!is_array($this->data[$key]) or count(array_filter(array_keys($this->data[$key]), 'is_string')) > 0) {
  245. $element = $this->data[$key];
  246. $this->data[$key] = array();
  247. $this->data[$key][] = $element;
  248. }
  249. $this->data[$key][] = $value;
  250. }
  251. }
  252. /**
  253. * Retrieves the data section of the resource.
  254. *
  255. * The JSON-LD response constists of two sections the '@context' section
  256. * and the data section. This function only returns the data section
  257. * for this resource
  258. *
  259. * @return
  260. * An associative array containing the data section of the response.
  261. */
  262. public function getData() {
  263. return $this->data;
  264. }
  265. /**
  266. * Retrieves the data section of the resource.
  267. *
  268. * The JSON-LD response constists of two sections the '@context' section
  269. * and the data section. This function only returns the data section
  270. * for this resource
  271. *
  272. * @return
  273. * An associative array containing the data section of the response.
  274. */
  275. public function getContext() {
  276. return $this->context;
  277. }
  278. /**
  279. * Copies the context from a given TripalWebService resource to this
  280. * resource.
  281. *
  282. * @param $resource
  283. */
  284. public function setContext($resource) {
  285. if (!is_a($resource, 'TripalWebServiceResource')) {
  286. throw new Exception("The \$resource argument must be an instance of a TripalWebServiceResource.");
  287. }
  288. $this->context = $resource->getContext();
  289. }
  290. }