TripalWebServiceResource.inc 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  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. * @param $name
  53. * The term name.
  54. * @param $iri
  55. * The Internationalized Resource Identifiers or it's shortcut.
  56. */
  57. public function addContextItem($name, $iri) {
  58. // TODO: make sure that if a shortcut is used that the parent is present.
  59. $this->context[$name] = $iri;
  60. }
  61. /**
  62. * Removes a term for the '@context' section for this resource.
  63. *
  64. * @param $name
  65. * The term name.
  66. * @param $iri
  67. * The Internationalized Resource Identifiers or it's shortcut.
  68. */
  69. public function removeContextItem($name, $iri) {
  70. // TODO: make sure that if a shortcut is used that the parent is present.
  71. unset($this->context[$name]);
  72. }
  73. /**
  74. * Sets the resource type.
  75. *
  76. * The type exist in the context of the web service.
  77. *
  78. * @param $type
  79. * The type
  80. */
  81. public function setType($type) {
  82. $this->checkKey($type);
  83. $this->type = $type;
  84. $this->data['@type'] = $type;
  85. }
  86. /**
  87. * Checks a key to ensure it is in the Context before being used.
  88. *
  89. * This function should be used before adding a property or type to this
  90. * resource. It ensures that the key for the property is already in the
  91. * context.
  92. *
  93. * @param $key
  94. * The key to check.
  95. * @throws Exception
  96. */
  97. private function checkKey($key) {
  98. // Make sure the key is already present in the context.
  99. $keys = array_keys($this->context);
  100. // Keys that are full HTML are acceptable
  101. if (preg_match('/^(http|https):\/\/.*/', $key)) {
  102. return;
  103. }
  104. // If the key has a colon separating the vocabulary and the term then we
  105. // just need to make sure that the vocabulary is present.
  106. $matches = array();
  107. if (preg_match('/^(.*?):(.*?)$/', $key, $matches)) {
  108. $vocab = $matches[1];
  109. $accession = $matches[2];
  110. // The underscore represents the blank node. So, these keys are okay.
  111. if ($vocab == '_') {
  112. return;
  113. }
  114. // If the vocabulary is not in the.
  115. if (!in_array($vocab, $keys)) {
  116. throw new Exception("The key, '$key', has a vocabulary that has not yet been added to the " .
  117. "context. Use the addContextItem() function to add the vocabulary prior to adding a value for it.");
  118. }
  119. }
  120. else {
  121. // If the key is not in the context then throw an error.
  122. if (!in_array($key, $keys)) {
  123. throw new Exception("The key, '$key', has not yet been added to the " .
  124. "context. Use the addContextItem() function to add this key prior to adding a value for it.");
  125. }
  126. }
  127. }
  128. /**
  129. * Set's the unique identifier for the resource.
  130. *
  131. * Every resource must have a unique Idientifer. In JSON-LD the '@id' element
  132. * identifies the IRI for the resource which will include the unique
  133. * identifier. The TraiplWebService to which a resource is added will
  134. * build the IRIs but it needs the unique ID of each resource.
  135. *
  136. * @param $id
  137. * The unique identifier for the resource.
  138. */
  139. public function setID($id) {
  140. $this->id = $id;
  141. $this->data['@id'] = $this->getURI($id);
  142. }
  143. /**
  144. * Retreives the IRI for an entity of a given ID in this web service.
  145. *
  146. * @param $id
  147. * The unique identifier for the resource.
  148. */
  149. public function getURI($id) {
  150. // If this is a key/value pair for an id and if the vocab portion is
  151. // an underscore then this represents a blank node and we don't want
  152. // to add the full path.
  153. $matches = array();
  154. if (preg_match('/^(.*?):(.*?)$/', $id, $matches)) {
  155. $vocab = $matches[1];
  156. if ($vocab == '_') {
  157. return $id;
  158. }
  159. return $id;
  160. }
  161. else {
  162. return $this->service_path . '/' . $id;
  163. }
  164. }
  165. /**
  166. * Retrieves the unique identifier for this resource.
  167. *
  168. * Every resource must have a unique Idientifer. In JSON-LD the '@id' element
  169. * identifies the IRI for the resource which will include the unique
  170. * identifier. The TraiplWebService to which a resource is added will
  171. * build the IRIs but it needs the unique ID of each resource.
  172. *
  173. * @return
  174. * The unique identifier for the resource.
  175. */
  176. public function getID() {
  177. return $this->id;
  178. }
  179. /**
  180. * Retreives the type of this resource.
  181. *
  182. * @return
  183. * The name of the resource.
  184. */
  185. public function getType() {
  186. return $this->type;
  187. }
  188. /**
  189. * Adds a new key/value pair to the web serivces response.
  190. *
  191. * The value must either be a scalar or another TripalWebServiceResource
  192. * object. If the same key is usesd multiple times then the resulting
  193. * resource will be presented as an array of elements.
  194. *
  195. * @param unknown $key
  196. * The name of the $key to add. This key must already be present in the
  197. * web service context by first adding it using the addContextItem()
  198. * member function.
  199. * @param unknown $value
  200. * The value of the key which must either be a scalar or a
  201. * TripalWebServiceResource instance.
  202. */
  203. public function addProperty($key, $value) {
  204. $this->checkKey($key);
  205. // If this is a numeric array then go through each element and add them.
  206. if (is_array($value) and count(array_filter(array_keys($value), 'is_int')) == count(array_keys($value))) {
  207. if (!array_key_exists($key, $this->data)) {
  208. $this->data[$key] = array();
  209. }
  210. foreach ($value as $item) {
  211. $this->addProperty($key, $item);
  212. }
  213. return;
  214. }
  215. // If this is a TripalWebServiceResource then get it's data and use that
  216. // as the new value.
  217. if (is_a($value, 'TripalWebServiceResource') or is_subclass_of($value, 'TripalWebServiceResource')) {
  218. // Add in the context items to this resource.
  219. $context = $value->getContext();
  220. foreach ($context as $k => $v) {
  221. $this->addContextItem($k, $v);
  222. }
  223. $value = $value->getData();
  224. }
  225. // If this key doesn't exist then add the value directly to the key.
  226. if (!array_key_exists($key, $this->data)) {
  227. $this->data[$key] = $value;
  228. }
  229. // Else if it does exist then we need to make sure that the element is
  230. // an array and add it.
  231. else {
  232. // If this is the second element, then convert it to an array. The
  233. // second test in the condition below is for for a numeric array.
  234. if (!is_array($this->data[$key]) or count(array_filter(array_keys($this->data[$key]), 'is_string')) > 0) {
  235. $element = $this->data[$key];
  236. $this->data[$key] = array();
  237. $this->data[$key][] = $element;
  238. }
  239. $this->data[$key][] = $value;
  240. }
  241. }
  242. /**
  243. * Retrieves the data section of the resource.
  244. *
  245. * The JSON-LD response constists of two sections the '@context' section
  246. * and the data section. This function only returns the data section
  247. * for this resource
  248. *
  249. * @return
  250. * An associative array containing the data section of the response.
  251. */
  252. public function getData() {
  253. return $this->data;
  254. }
  255. /**
  256. * Retrieves the data section of the resource.
  257. *
  258. * The JSON-LD response constists of two sections the '@context' section
  259. * and the data section. This function only returns the data section
  260. * for this resource
  261. *
  262. * @return
  263. * An associative array containing the data section of the response.
  264. */
  265. public function getContext() {
  266. return $this->context;
  267. }
  268. /**
  269. * Copies the context from a given TripalWebService resource to this
  270. * resource.
  271. *
  272. * @param $resource
  273. */
  274. public function setContext($resource) {
  275. if (!is_a($resource, 'TripalWebServiceResource')) {
  276. throw new Exception("The \$resource argument must be an instance of a TripalWebServiceResource.");
  277. }
  278. $this->context = $resource->getContext();
  279. }
  280. }