tripal_ws.rest.inc 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826
  1. <?php
  2. /**
  3. *_a
  4. */
  5. function tripal_ws_rest() {
  6. global $base_url;
  7. $ws_path = func_get_args();
  8. $params = $_GET;
  9. unset($params['q']);
  10. // The web services should never be cached.
  11. drupal_page_is_cacheable(FALSE);
  12. // Set some initial variables.
  13. $response = array();
  14. $status = 'success';
  15. $version = 'v0.1';
  16. $message = '';
  17. $api_url = $base_url . '/ws/' . $version;
  18. $page_limit = 25;
  19. $pager_id = 0;
  20. // Set some defaults for the response.
  21. $response['@context'] = array();
  22. // Lump everything ito a try block so that if there is a problem we can
  23. // throw an error and have that returned in the response.
  24. try {
  25. // The services is the first argument
  26. $service = (count($ws_path) > 0) ? $ws_path[0] : '';
  27. switch ($service) {
  28. case 'doc':
  29. tripal_ws_handle_doc_service($api_url, $response);
  30. break;
  31. case 'content':
  32. tripal_ws_handle_content_service($api_url, $response, $ws_path, $params);
  33. break;
  34. case 'vocab':
  35. tripal_ws_handle_vocab_service($api_url, $response, $ws_path);
  36. break;
  37. default:
  38. tripal_ws_handle_no_service($api_url, $response);
  39. }
  40. }
  41. catch (Exception $e) {
  42. watchdog('tripal_ws', $e->getMessage(), array(), WATCHDOG_ERROR);
  43. $message = $e->getMessage();
  44. $status = 'error';
  45. }
  46. // The responses follow a similar format as the AGAVE API with a
  47. // status, message, version and all data in the 'result' object.
  48. /* $response['status'] = $status;
  49. $response['message'] = $message;
  50. $response['api_version'] = $version;
  51. $response['source'] = array(
  52. 'site_name' => variable_get('site_name', 'Unspecified'),
  53. 'site_url' => $base_url,
  54. 'site_slogan' => variable_get('site_slogan', 'Unspecified'),
  55. 'site_email' => variable_get('site_mail', 'Unspecified'),
  56. ); */
  57. // Rather than use the drupal_json_output() funciton we manually specify
  58. // content type because we want it to be 'ld+json'.
  59. drupal_add_http_header('Content-Type', 'application/ld+json');
  60. print drupal_json_encode($response);
  61. }
  62. /**
  63. *
  64. * @param $api_url
  65. * @param $response
  66. * @param $ws_path
  67. */
  68. function tripal_ws_handle_content_service($api_url, &$response, $ws_path, $params) {
  69. // Get the content type.
  70. $ctype = (count($ws_path) > 1) ? $ws_path[1] : '';
  71. $entity_id = (count($ws_path) > 2) ? $ws_path[2] : '';
  72. // If we have no content type then list all of the available content types.
  73. if (!$ctype) {
  74. tripal_ws_get_content_types($api_url, $response);
  75. }
  76. // If we don't have an entity ID then show a paged list of entities with
  77. // the given type.
  78. else if ($ctype and !$entity_id) {
  79. tripal_ws_get_content_type($api_url, $response, $ws_path, $ctype, $params);
  80. }
  81. // If we have a content type and an entity ID then show the entity
  82. else {
  83. tripal_ws_get_content($api_url, $response, $ws_path, $ctype, $entity_id, $params);
  84. }
  85. }
  86. /**
  87. *
  88. * @param $api_url
  89. * @param $response
  90. * @param $ws_path
  91. */
  92. function tripal_ws_handle_vocab_service($api_url, &$response, $ws_path) {
  93. // Get the vocab name.
  94. $vocabulary = (count($ws_path) > 1) ? $ws_path[1] : '';
  95. $accession = (count($ws_path) > 2) ? $ws_path[2] : '';
  96. // If we have no $vocabulary type then list all of the available vocabs.
  97. if (!$vocabulary) {
  98. tripal_ws_get_vocabs($api_url, $response);
  99. }
  100. // If we don't have a $vocabulary then show a paged list of terms.
  101. else if ($vocabulary and !$accession) {
  102. tripal_ws_get_vocab($api_url, $response, $ws_path, $vocabulary);
  103. }
  104. // If we have a content type and an entity ID then show the entity
  105. else if ($vocabulary and $accession) {
  106. tripal_ws_get_term($api_url, $response, $ws_path, $vocabulary, $accession);
  107. }
  108. }
  109. /**
  110. *
  111. * @param $api_url
  112. * @param $response
  113. */
  114. function tripal_ws_get_vocabs($api_url, &$response) {
  115. // First, add the vocabularies used into the @context section.
  116. $response['@context']['rdfs'] = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
  117. $response['@context']['hydra'] = 'http://www.w3.org/ns/hydra/core#';
  118. // Next add in the ID for tihs resource.
  119. $response['@id'] = $api_url . '/vocab';
  120. // Start the list.
  121. $response['@type'] = 'Collection';
  122. $response['totalItems'] = 0;
  123. $response['label'] = 'Content Types';
  124. $response['member'] = array();
  125. $vocabs = db_select('tripal_vocab', 'tv')
  126. ->fields('tv')
  127. ->execute();
  128. // Iterate through the vocabularies and add an entry in the collection.
  129. $i = 0;
  130. while ($vocab = $vocabs->fetchObject()) {
  131. $term =
  132. // Add the bundle as a content type.
  133. $response['member'][] = array(
  134. '@id' => $api_url . '/vocab/' . urlencode($vocab->vocabulary),
  135. '@type' => 'vocabulary',
  136. 'vocabulary' => $vocab->vocabulary,
  137. );
  138. $i++;
  139. }
  140. $response['totalItems'] = $i;
  141. //$response['totalItems'] = $i;
  142. // Lastly, add in the terms used into the @context section.
  143. $response['@context']['Collection'] = 'hydra:Collection';
  144. $response['@context']['totalItems'] = 'hydra:totalItems';
  145. $response['@context']['member'] = 'hydra:member';
  146. $response['@context']['label'] = 'rdfs:label';
  147. $response['@context']['description'] = 'hydra:description';
  148. }
  149. /**
  150. *
  151. * @param $api_url
  152. * @param $response
  153. * @param $ws_path
  154. */
  155. function tripal_ws_get_vocab($api_url, &$response, $ws_path, $vocabulary) {
  156. // First, add the vocabularies used into the @context section.
  157. $response['@context']['rdfs'] = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
  158. $response['@context']['hydra'] = 'http://www.w3.org/ns/hydra/core#';
  159. $response['@context']['schema'] = 'https://schema.org/';
  160. // Next add in the ID for tihs resource.
  161. $response['@id'] = $api_url . '/vocab/' . $vocabulary;
  162. // Get the vocabulary
  163. $vocab = tripal_load_vocab_entity(array('vocabulary' => $vocabulary));
  164. // Start the list.
  165. $response['@type'] = 'Collection';
  166. $response['totalItems'] = 0;
  167. $response['label'] = vocabulary . " vocabulary collection";
  168. $response['comment'] = 'The following list of terms may not be the full ' .
  169. 'list for the vocabulary. The terms listed here are only those ' .
  170. 'that have associated content on this site.';
  171. // Get the list of terms for this vocab.
  172. $query = db_select('tripal_term', 'tt')
  173. ->fields('tt', array('id'))
  174. ->condition('vocab_id', $vocab->id)
  175. ->orderBy('accession', 'DESC');
  176. // Iterate through the entities and add them to the list.
  177. $terms = $query->execute();
  178. $i = 0;
  179. while($term = $terms->fetchObject()) {
  180. $term = tripal_load_term_entity(array('term_id' => $term->id));
  181. $response['member'][] = array(
  182. '@id' => $api_url . '/vocab/' . urlencode($vocabulary) . '/' . urlencode($term->accession),
  183. '@type' => 'vocabulary_term',
  184. 'vocabulary' => $vocab->vocabulary,
  185. 'accession' => $term->accession,
  186. 'name' => $term->name,
  187. 'definition' => $term->definition,
  188. );
  189. $i++;
  190. }
  191. $response['totalItems'] = $i;
  192. // Lastly, add in the terms used into the @context section.
  193. $response['@context']['Collection'] = 'hydra:Collection';
  194. $response['@context']['totalItems'] = 'hydra:totalItems';
  195. $response['@context']['member'] = 'hydra:member';
  196. $response['@context']['label'] = 'rdfs:label';
  197. $response['@context']['comment'] = 'rdfs:comment';
  198. $response['@context']['itemPage'] = 'schema:itemPage';
  199. }
  200. /**
  201. *
  202. * @param $api_url
  203. * @param $response
  204. * @param $ws_path
  205. */
  206. function tripal_ws_get_term($api_url, &$response, $ws_path, $vocabulary, $accession) {
  207. // First, add the vocabularies used into the @context section.
  208. $response['@context']['rdfs'] = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
  209. $response['@context']['hydra'] = 'http://www.w3.org/ns/hydra/core#';
  210. $response['@context']['schema'] = 'https://schema.org/';
  211. // Get the term.
  212. $term = tripal_load_term_entity(array('vocabulary' => $vocabulary, 'accession' => $accession));
  213. // Next add in the ID and Type for this resources.
  214. $response['@id'] = $api_url . '/vocab/' . urlencode($vocabulary) . '/' . urlencode($accession);
  215. $response['@type'] = 'vocabulary_term';
  216. $response['label'] = $term->name;
  217. $response['vocabulary'] = $vocabulary;
  218. $response['accession'] = $accession;
  219. $response['name'] = $term->name;
  220. $response['definition'] = $term->definition;
  221. if ($term->url) {
  222. $response['URL'] = $term->url;
  223. }
  224. // Lastly, add in the terms used into the @context section.
  225. $response['@context']['label'] = 'rdfs:label';
  226. $response['@context']['itemPage'] = 'schema:itemPage';
  227. }
  228. /**
  229. * Provides a collection (list) of all of the content types.
  230. *
  231. * @param $api_url
  232. * @param $response
  233. */
  234. function tripal_ws_get_content_types($api_url, &$response) {
  235. // First, add the vocabularies used into the @context section.
  236. $response['@context']['rdfs'] = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
  237. $response['@context']['hydra'] = 'http://www.w3.org/ns/hydra/core#';
  238. // Next add in the ID for tihs resource.
  239. $response['@id'] = $api_url . '/content';
  240. // Start the list.
  241. $response['@type'] = 'Collection';
  242. $response['totalItems'] = 0;
  243. $response['label'] = 'Content Types';
  244. $response['member'] = array();
  245. // Get the list of published terms (these are the bundle IDs)
  246. $bundles = db_select('tripal_bundle', 'tb')
  247. ->fields('tb')
  248. ->orderBy('tb.label', 'ASC')
  249. ->execute();
  250. $terms = array();
  251. // Iterate through the terms and add an entry in the collection.
  252. $i = 0;
  253. while ($bundle = $bundles->fetchObject()) {
  254. $entity = entity_load('TripalTerm', array('id' => $bundle->term_id));
  255. $term = reset($entity);
  256. $vocab = $term->vocab;
  257. if (!array_key_exists($vocab->vocabulary, $response['@context'])) {
  258. // If there is no URL prefix then use this API's vocabulary API
  259. if ($term->urlprefix) {
  260. $response['@context'][$vocab->vocabulary] = $term->urlprefix;
  261. }
  262. else {
  263. $response['@context'][$vocab->vocabulary] = $api_url . '/vocab/' . $vocab->vocabulary . '/';
  264. }
  265. }
  266. // Get the bundle description. If no description is provided then
  267. // use the term definition
  268. $description = tripal_get_bundle_variable('description', $bundle->id);
  269. if (!$description) {
  270. $description = $term->definition;
  271. }
  272. // Add the bundle as a content type.
  273. $response['member'][] = array(
  274. '@id' => $api_url . '/content/' . urlencode($bundle->label),
  275. '@type' => $vocab->vocabulary . ':' . $term->accession,
  276. 'label' => $bundle->label,
  277. 'description' => $description,
  278. );
  279. $i++;
  280. }
  281. $response['totalItems'] = $i;
  282. // Lastly, add in the terms used into the @context section.
  283. $response['@context']['Collection'] = 'hydra:Collection';
  284. $response['@context']['totalItems'] = 'hydra:totalItems';
  285. $response['@context']['member'] = 'hydra:member';
  286. $response['@context']['label'] = 'rdfs:label';
  287. $response['@context']['description'] = 'hydra:description';
  288. }
  289. /**
  290. *
  291. * @param $api_url
  292. * @param $response
  293. * @param $ws_path
  294. */
  295. function tripal_ws_get_content_type($api_url, &$response, $ws_path, $ctype, $params) {
  296. // First, add the vocabularies used into the @context section.
  297. $response['@context']['rdfs'] = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
  298. $response['@context']['hydra'] = 'http://www.w3.org/ns/hydra/core#';
  299. $response['@context']['schema'] = 'https://schema.org/';
  300. // Next add in the ID for tihs resource.
  301. $response['@id'] = $api_url . '/content/' . $ctype;
  302. // Get the TripalBundle, TripalTerm and TripalVocab type for this type.
  303. $bundle = tripal_load_bundle_entity(array('label' => $ctype));
  304. $term = entity_load('TripalTerm', array('id' => $bundle->term_id));
  305. $term = reset($term);
  306. $vocab = $term->vocab;
  307. if (!array_key_exists($vocab->vocabulary, $response['@context'])) {
  308. // If there is no URL prefix then use this API's vocabulary API
  309. if ($term->urlprefix) {
  310. $response['@context'][$vocab->vocabulary] = $term->urlprefix;
  311. }
  312. else {
  313. $response['@context'][$vocab->vocabulary] = $api_url . '/vocab/' . $vocab->vocabulary . '/';
  314. }
  315. }
  316. // Start the list.
  317. $response['@type'] = 'Collection';
  318. $response['totalItems'] = 0;
  319. $response['label'] = $bundle->label . " collection";
  320. // Organize the fields by their web service names.
  321. $fields = field_info_fields();
  322. $field_ws_names = array();
  323. foreach ($fields as $field_name => $details) {
  324. if (array_key_exists('settings', $details) and
  325. array_key_exists('semantic_web', $details['settings'])) {
  326. $sw_name = $details['settings']['semantic_web']['name'];
  327. $field_ws_names[$sw_name][] = $field_name;
  328. }
  329. }
  330. // Get the list of entities for this bundle.
  331. $query = new TripalFieldQuery();
  332. $query->fieldCondition('content_type', $term->id);
  333. foreach($params as $key => $value) {
  334. foreach ($field_ws_names[$key] as $field_name) {
  335. $query->fieldCondition($field_name, $value);
  336. }
  337. }
  338. $results = $query->execute();
  339. // Get the entities from the above search. We do a direct query of the
  340. // table because the load_entity() function is too slow.
  341. $query = db_select('tripal_entity', 'TE');
  342. $query->fields('TE');
  343. $query->condition('id', array_keys($results['TripalEntity']));
  344. $results = $query->execute();
  345. // Iterate through the entities and add them to the list.
  346. $i = 0;
  347. while($entity = $results->fetchObject()) {
  348. $response['member'][] = array(
  349. '@id' => $api_url . '/content/' . urlencode($ctype) . '/' . $entity->id,
  350. '@type' => $vocab->vocabulary . ':' . $term->accession,
  351. 'label' => $entity->title,
  352. 'itemPage' => url('/bio_data/' . $entity->id, array('absolute' => TRUE)),
  353. );
  354. $i++;
  355. }
  356. $response['totalItems'] = $i;
  357. // Lastly, add in the terms used into the @context section.
  358. $response['@context']['Collection'] = 'hydra:Collection';
  359. $response['@context']['totalItems'] = 'hydra:totalItems';
  360. $response['@context']['member'] = 'hydra:member';
  361. $response['@context']['label'] = 'rdfs:label';
  362. $response['@context']['itemPage'] = 'schema:itemPage';
  363. $response['operation'][] = array(
  364. '@type' => 'hydra:CreateResourceOperation',
  365. 'hydra:method' => 'PUT'
  366. );
  367. $response['query'] = array(
  368. '@id' => $response['@id'],
  369. '@type' => 'IriTemplate',
  370. "template" => $response['@id'] . "{?name,}",
  371. "mapping" => array(
  372. array(
  373. "hydra:variable" => 'name',
  374. "hydra:property" => 'name',
  375. )
  376. )
  377. );
  378. }
  379. /**
  380. *
  381. * @param unknown $response
  382. * @param unknown $ws_path
  383. * @param unknown $ctype
  384. * @param unknown $entity_id
  385. * @param unknown $params
  386. */
  387. function tripal_ws_get_content_add_fields($entity, $bundle, $api_url, &$response, $ws_path, $ctype, $entity_id, $params) {
  388. // Get information about the fields attached to this bundle and sort them
  389. // in the order they were set for the display.
  390. // TODO: should we allow for custom ordering of fields for web services
  391. // or use the default display ordering?
  392. $instances = field_info_instances('TripalEntity', $bundle->name);
  393. uasort($instances, function($a, $b) {
  394. $a_weight = (is_array($a) && isset($a['display']['default']['weight'])) ? $a['display']['default']['weight'] : 0;
  395. $b_weight = (is_array($b) && isset($b['display']['default']['weight'])) ? $b['display']['default']['weight'] : 0;
  396. if ($a_weight == $b_weight) {
  397. return 0;
  398. }
  399. return ($a_weight < $b_weight) ? -1 : 1;
  400. });
  401. // Iterate through the fields and add each value to the response.
  402. //$response['fields'] = $fields;
  403. foreach ($instances as $field_name => $instance) {
  404. // Ignore the content_type field provided by Tripal.
  405. if ($field_name == 'content_type') {
  406. continue;
  407. }
  408. // Skip hidden fields.
  409. if ($instance['display']['default']['type'] == 'hidden') {
  410. continue;
  411. }
  412. // Get the information about this field. It will have settings different
  413. // from the instance.
  414. $field = field_info_field($field_name);
  415. // By default, the label for the key in the output should be the
  416. // term from the vocabulary that the field is assigned. But in the
  417. // case that the field is not assigned a term, we must use the field name.
  418. $field_name = $instance['field_name'];
  419. $field_settings = $field['settings'];
  420. $key = $field_name;
  421. //$key = strtolower(preg_replace('/ /', '_', $key));
  422. if (array_key_exists('semantic_web', $field_settings) and $field_settings['semantic_web']) {
  423. list($vocabulary, $accession) = explode(':', $field_settings['semantic_web']);
  424. $term = tripal_get_term_details($vocabulary, $accession);
  425. if ($term) {
  426. $key = $term['name'];
  427. $response['@context'][$key] = array(
  428. '@id' => $term['url'],
  429. );
  430. }
  431. }
  432. // If this field should not be attached by default then just add a link
  433. // so that the caller can get the information separately.
  434. $instance_settings = $instance['settings'];
  435. if (array_key_exists('auto_attach', $instance_settings) and
  436. $instance_settings['auto_attach'] != TRUE) {
  437. $response['@context'][$key]['@type'] = '@id';
  438. $response[$key] = $api_url . '/content/' . $ctype . '/' . $entity->id . '/' . urlencode($key);
  439. continue;
  440. }
  441. // Get the details for this field for the JSON-LD response.
  442. tripal_ws_get_content_add_field($key, $entity, $field, $instance, $api_url, $response);
  443. }
  444. // Lastly, add in the terms used into the @context section.
  445. $response['@context']['label'] = 'rdfs:label';
  446. $response['@context']['itemPage'] = 'schema:itemPage';
  447. // $response['operation'][] = array(
  448. // '@type' => 'hydra:DeleteResourceOperation',
  449. // 'hydra:method' => 'DELETE'
  450. // );
  451. // $response['operation'][] = array(
  452. // '@type' => 'hydra:ReplaceResourceOperation',
  453. // 'hydra:method' => 'POST'
  454. // );
  455. }
  456. /**
  457. *
  458. * @param unknown $field_arg
  459. * @param unknown $api_url
  460. * @param unknown $response
  461. * @param unknown $ws_path
  462. * @param unknown $ctype
  463. * @param unknown $entity_id
  464. * @param unknown $params
  465. */
  466. function tripal_ws_get_content_find_field($field_arg, $ctype, $entity_id) {
  467. $bundle = tripal_load_bundle_entity(array('label' => $ctype));
  468. $entity = tripal_load_entity('TripalEntity', array('id' => $entity_id));
  469. $entity = reset($entity);
  470. $term = NULL;
  471. // Find the field whose term matches the one provied.
  472. $value = array();
  473. $instances = field_info_instances('TripalEntity', $bundle->name);
  474. foreach ($instances as $instance) {
  475. $field_name = $instance['field_name'];
  476. $field = field_info_field($field_name);
  477. $field_settings = $field['settings'];
  478. if (array_key_exists('semantic_web', $field_settings) and
  479. $field_settings['semantic_web']) {
  480. list($vocabulary, $accession) = explode(':', $field_settings['semantic_web']);
  481. $temp_term = tripal_get_term_details($vocabulary, $accession);
  482. if ($temp_term['name'] == $field_arg) {
  483. return array($entity, $bundle, $field, $instance, $temp_term);
  484. }
  485. }
  486. }
  487. }
  488. /**
  489. *
  490. * @param unknown $api_url
  491. * @param unknown $response
  492. * @param unknown $ws_path
  493. * @param unknown $ctype
  494. * @param unknown $entity_id
  495. * @param unknown $params
  496. * @return number
  497. */
  498. function tripal_ws_get_content($api_url, &$response, $ws_path, $ctype, $entity_id, $params) {
  499. // First, add the vocabularies used into the @context section.
  500. $response['@context']['rdfs'] = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
  501. $response['@context']['hydra'] = 'http://www.w3.org/ns/hydra/core#';
  502. // If we have an argument in the 4th element (3rd index) then the user
  503. // is requesting to epxand the details of a field that was not
  504. // initially attached to the enity.
  505. $field_arg = '';
  506. if (array_key_exists(3, $ws_path)) {
  507. $field_arg = $ws_path[3];
  508. list($entity, $bundle, $field, $instance, $term) = tripal_ws_get_content_find_field($field_arg, $ctype, $entity_id);
  509. // Next add in the ID and Type for this resources.
  510. $key = $term['name'];
  511. $response['@context'][$key] = $term['url'];
  512. $response['@id'] = $key;
  513. // Attach the field and then add it's values to the response.
  514. field_attach_load($entity->type, array($entity->id => $entity), FIELD_LOAD_CURRENT,
  515. array('field_id' => $field['id']));
  516. tripal_ws_get_content_add_field($key, $entity, $field, $instance, $api_url, $response, TRUE);
  517. return;
  518. }
  519. // If we don't have a 4th argument then we're loading the base record.
  520. // Get the TripalBundle, TripalTerm and TripalVocab type for this type.
  521. $bundle = tripal_load_bundle_entity(array('label' => $ctype));
  522. $term = entity_load('TripalTerm', array('id' => $bundle->term_id));
  523. $term = reset($term);
  524. $vocab = $term->vocab;
  525. // Add the vocabulary for this content type to the @context section.
  526. if (!array_key_exists($vocab->vocabulary, $response['@context'])) {
  527. // If there is no URL prefix then use this API's vocabulary API
  528. if (property_exists($term, 'urlprefix')) {
  529. $response['@context'][$vocab->vocabulary] = $term->urlprefix;
  530. }
  531. else {
  532. $response['@context'][$vocab->vocabulary] = $api_url . '/vocab/' . $vocab->vocabulary . '/';
  533. }
  534. }
  535. // Get the TripalEntity
  536. $entity = tripal_load_entity('TripalEntity', array('id' => $entity_id));
  537. $entity = reset($entity);
  538. // Next add in the ID and Type for this resources.
  539. $response['@id'] = $api_url . '/content/' . $ctype . '/' . $entity_id;
  540. $response['@type'] = $term->name;
  541. $response['@context'][$term->name] = $term->url;
  542. $response['label'] = $entity->title;
  543. $response['itemPage'] = url('/bio_data/' . $entity->id, array('absolute' => TRUE));
  544. tripal_ws_get_content_add_fields($entity, $bundle, $api_url, $response, $ws_path, $ctype, $entity_id, $params);
  545. }
  546. /**
  547. *
  548. */
  549. function tripal_ws_get_content_add_field($key, $entity, $field, $instance, $api_url, &$response, $is_field_page = NULL) {
  550. // Get the field settings.
  551. $field_name = $field['field_name'];
  552. $field_settings = $field['settings'];
  553. $items = field_get_items('TripalEntity', $entity, $field_name);
  554. $values = array();
  555. for ($i = 0; $i < count($items); $i++) {
  556. // See if the keys in the values array have been mapped to semantic
  557. // web terms.
  558. if (array_key_exists('semantic_web', $items[$i])) {
  559. foreach ($items[$i]['semantic_web'] as $k => $v) {
  560. list($vocabulary, $accession) = explode(':', $v);
  561. $term = tripal_get_term_details($vocabulary, $accession);
  562. if ($k == 'type') {
  563. $items[$i]['value']['@type'] = $items[$i]['value']['type'];
  564. unset($items[$i]['value']['type']);
  565. $response['@context'][$term['name']] = $term['url'];
  566. }
  567. else {
  568. $response['@context'][$k] = $term['url'];
  569. }
  570. }
  571. }
  572. // Recurse through the values array and set the entity elemtns
  573. // and add the fields to the context.
  574. tripal_ws_get_content_add_field_context($items[$i], $response, $api_url);
  575. // Add the remaining values to the $values array.
  576. $values[] = $items[$i]['value'];
  577. }
  578. // If we only have one value then set the response with just the value.
  579. if (count($values) == 1) {
  580. // If the value is an array and this is the field page then all of those
  581. // key/value pairs should be added directly to the response.
  582. if (is_array($values[0])) {
  583. if ($is_field_page) {
  584. foreach ($values[0] as $k => $v) {
  585. $response[$k] = $v;
  586. }
  587. }
  588. else {
  589. $response[$key] = $values[0];
  590. }
  591. }
  592. // If the value is not an array it's a scalar so add it as is to the
  593. // response.
  594. else {
  595. $response[$key] = $values[0];
  596. }
  597. }
  598. // If we have more than one value then set the response to be a collection.
  599. if (count($values) > 1) {
  600. // If this is the field page then the Collection is added directly to the
  601. // response, otherwise, it's added under the field $key.
  602. if ($is_field_page) {
  603. $response['@type'] = 'Collection';
  604. $response['totalItems'] = count($values);
  605. $response['label'] = $instance['label'];
  606. $response['member'] = $values;
  607. }
  608. else {
  609. $response[$key] = array(
  610. '@type' => 'Collection',
  611. 'totalItems' => count($values),
  612. 'label' => $instance['label'],
  613. 'member' => $values,
  614. );
  615. }
  616. }
  617. }
  618. /**
  619. *
  620. */
  621. function tripal_ws_get_content_add_field_context(&$items, &$response, $api_url) {
  622. foreach ($items as $key => $value) {
  623. if (is_array($value)) {
  624. tripal_ws_get_content_add_field_context($items[$key], $response, $api_url);
  625. continue;
  626. }
  627. if ($key == 'entity') {
  628. list($item_etype, $item_eid) = explode(':', $items['entity']);
  629. if ($item_eid) {
  630. $item_entity = tripal_load_entity($item_etype, array($item_eid));
  631. $item_entity = reset($item_entity);
  632. $item_term = tripal_load_term_entity(array('term_id' => $item_entity->term_id));
  633. $items['@id'] = $api_url . '/content/' . $item_term->name . '/' . $item_eid;
  634. }
  635. unset($items['entity']);
  636. }
  637. }
  638. }
  639. /**
  640. * Provides the Hydra compatible apiDocumentation page that describes this API.
  641. *
  642. * @param $api_url
  643. * @param $response
  644. */
  645. function tripal_ws_handle_doc_service($api_url, &$response) {
  646. // First, add the vocabularies used into the @context section.
  647. $response['@context']['rdfs'] = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
  648. $response['@context']['hydra'] = 'http://www.w3.org/ns/hydra/core#';
  649. // Next add in the ID for tihs resource.
  650. $site_name = variable_get('site_name', '');
  651. $response['@id'] = $api_url . '/doc/';
  652. $response['title'] = $site_name . ": RESTful Web Services API";
  653. $response['entrypoint'] = $api_url;
  654. $response['description'] = "A fully queryable REST API using JSON-LD and " .
  655. "discoverable using the WC3 Hydra specification.";
  656. // Lastly, add in the terms used into the @context section.
  657. $response['@context']['title'] = 'hydra:title';
  658. $response['@context']['entrypoint'] = array(
  659. "@id" => "hydra:entrypoint",
  660. "@type" => "@id",
  661. );
  662. $response['@context']['description'] = 'hydra:description';
  663. }
  664. /**
  665. * This function specifies the types of resources avaiable via the API.
  666. *
  667. * @param $api_url
  668. * @param $response
  669. * @param $ws_path
  670. */
  671. function tripal_ws_handle_no_service($api_url, &$response) {
  672. // First, add the vocabularies used into the @context section.
  673. $response['@context']['rdfs'] = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
  674. $response['@context']['hydra'] = 'http://www.w3.org/ns/hydra/core#';
  675. $response['@context']['dc'] = 'http://purl.org/dc/dcmitype/';
  676. $response['@context']['schema'] = 'https://schema.org/';
  677. // Next add in the ID for tihs resource.
  678. $response['@id'] = $api_url;
  679. // Start the list.
  680. $response['@type'] = 'Collection';
  681. $response['totalItems'] = 0;
  682. $response['label'] = 'Services';
  683. $response['member'] = array();
  684. // Start the list.
  685. $response['member'][] = array(
  686. '@id' => $api_url . '/content/',
  687. '@type' => 'Service',
  688. 'label' => 'Content Types',
  689. 'description' => 'Provides acesss to the biological and ' .
  690. 'ancilliary data available on this site. Each content type ' .
  691. 'represents biological data that is defined in a controlled vocabulary '.
  692. '(e.g. Sequence Ontology term: gene (SO:0000704)).',
  693. );
  694. $response['member'][] = array(
  695. '@id' => $api_url . '/doc/',
  696. '@type' => 'Service',
  697. 'label' => 'API Documentation',
  698. 'description' => 'The WC3 Hydra compatible documentation for this API.',
  699. );
  700. $response['member'][] = array(
  701. '@id' => $api_url . '/vocab/',
  702. '@type' => 'Service',
  703. 'label' => 'Vocabulary',
  704. 'description' => 'Defines in-house locally defined vocabulary terms that ' .
  705. 'have been added specifically for this site. These terms are typically ' .
  706. 'added because no other appropriate term exists in another community-vetted '.
  707. 'controlled vocabulary.',
  708. );
  709. $response['totalItems'] = count($response['member']);
  710. $response['@context']['Collection'] = 'hydra:Collection';
  711. $response['@context']['totalItems'] = 'hydra:totalItems';
  712. $response['@context']['member'] = 'hydra:member';
  713. $response['@context']['Service'] = 'dc:Service';
  714. $response['@context']['label'] = 'rdfs:label';
  715. $response['@context']['description'] = 'hydra:description';
  716. }