tripal_chado.db.api.inc 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588
  1. <?php
  2. /**
  3. * @file
  4. * Provides an application programming interface (API) to manage references to
  5. * external databases
  6. */
  7. /**
  8. * @defgroup tripal_chado_database_api Chado DB
  9. * @ingroup tripal_chado_api
  10. * @{
  11. * @}
  12. */
  13. /**
  14. * Retrieves a chado db variable
  15. *
  16. * Example Usage:
  17. * @code
  18. $select_values = array(
  19. 'name' => 'SOFP'
  20. );
  21. $db_object = tripal_get_db($select_values);
  22. * @endcode
  23. * The above code selects the SOFP db and returns the following object:
  24. * @code
  25. $db_object = stdClass Object (
  26. [db_id] => 49
  27. [name] => SOFP
  28. [description] =>
  29. [urlprefix] =>
  30. [url] =>
  31. );
  32. * @endcode
  33. *
  34. * @param $identifier
  35. * An array with the key stating what the identifier is. Supported keys (only on of the
  36. * following unique keys is required):
  37. * - db_id: the chado db.db_id primary key
  38. * - name: the chado db.name field (assume unique)
  39. * @param $options
  40. * An array of options. Supported keys include:
  41. * - Any keys supported by chado_generate_var(). See that function definition for
  42. * additional details.
  43. *
  44. * NOTE: the $identifier parameter can really be any array similar to $values passed into
  45. * chado_select_record(). It should fully specify the db record to be returned.
  46. *
  47. * @return
  48. * If unique values were passed in as an identifier then an object describing the cv
  49. * will be returned (will be a chado variable from chado_generate_var()). Otherwise,
  50. * an array of objects will be returned.
  51. *
  52. * @ingroup tripal_chado_database_api
  53. */
  54. function tripal_get_db($identifiers, $options = array()) {
  55. // Set Defaults
  56. if (!isset($options['include_fk'])) {
  57. // Tells chado_generate_var not to follow any foreign keys
  58. $options['include_fk'] = array();
  59. }
  60. // Error Checking of parameters
  61. if (!is_array($identifiers)) {
  62. tripal_report_error(
  63. 'tripal_chado_database_api',
  64. TRIPAL_ERROR,
  65. "tripal_get_db: The identifier passed in is expected to be an array with the key
  66. matching a column name in the db table (ie: db_id or name). You passed in %identifier.",
  67. array(
  68. '%identifier'=> print_r($identifiers, TRUE)
  69. )
  70. );
  71. }
  72. elseif (empty($identifiers)) {
  73. tripal_report_error(
  74. 'tripal_chado_database_api',
  75. TRIPAL_ERROR,
  76. "tripal_get_db: You did not pass in anything to identify the db you want. The identifier
  77. is expected to be an array with the key matching a column name in the db table
  78. (ie: db_id or name). You passed in %identifier.",
  79. array(
  80. '%identifier'=> print_r($identifiers, TRUE)
  81. )
  82. );
  83. }
  84. // Try to get the db
  85. $db = chado_generate_var(
  86. 'db',
  87. $identifiers,
  88. $options
  89. );
  90. // Ensure the db is singular. If it's an array then it is not singular
  91. if (is_array($db)) {
  92. tripal_report_error(
  93. 'tripal_chado_database_api',
  94. TRIPAL_ERROR,
  95. "tripal_get_db: The identifiers you passed in were not unique. You passed in %identifier.",
  96. array(
  97. '%identifier'=> print_r($identifiers, TRUE)
  98. )
  99. );
  100. }
  101. // Report an error if $db is FALSE since then chado_generate_var has failed
  102. elseif ($db === FALSE) {
  103. tripal_report_error(
  104. 'tripal_chado_database_api',
  105. TRIPAL_ERROR,
  106. "tripal_get_db: chado_generate_var() failed to return a db based on the identifiers
  107. you passed in. You should check that your identifiers are correct, as well as, look
  108. for a chado_generate_var error for additional clues. You passed in %identifier.",
  109. array(
  110. '%identifier'=> print_r($identifiers, TRUE)
  111. )
  112. );
  113. }
  114. // Else, as far we know, everything is fine so give them their db :)
  115. else {
  116. return $db;
  117. }
  118. }
  119. /**
  120. * Create an options array to be used in a form element
  121. * which provides a list of all chado dbs
  122. *
  123. * @return
  124. * An array(db_id => name) for each db in the chado db table
  125. *
  126. * @ingroup tripal_chado_database_api
  127. */
  128. function tripal_get_db_select_options() {
  129. $dbs = chado_query("SELECT db_id, name FROM {db} ORDER BY name");
  130. $options = array();
  131. $options[] = 'Select a Database';
  132. foreach ($dbs as $db) {
  133. $options[$db->db_id] = $db->name;
  134. }
  135. return $options;
  136. }
  137. /**
  138. * Retrieves a chado database reference variable
  139. *
  140. * Example Usage:
  141. * @code
  142. $identifiers = array(
  143. 'accession' => 'synonym',
  144. 'db_id' => array(
  145. 'name' => 'SOFP'
  146. )
  147. );
  148. $dbxref_object = tripal_get_dbxref($identifiers);
  149. * @endcode
  150. * The above code selects the synonym database reference and returns the following object:
  151. * @code
  152. $dbxref_object = stdClass Object (
  153. [dbxref_id] => 2581
  154. [accession] => synonym
  155. [description] =>
  156. [version] =>
  157. [db_db_id] => 49
  158. [db_name] => SOFP
  159. [db_description] =>
  160. [db_urlprefix] =>
  161. [db_url] =>
  162. );
  163. * @endcode
  164. *
  165. * @param $identifier
  166. * An array apropriate for use with the chado_generate_var for uniquely
  167. * identifying a dbxref record. Alternatively, there are also some specially
  168. * handled keys. They are:
  169. * - property: An array/object describing the property to select records for. It
  170. * should at least have either a type_name (if unique across cvs) or type_id. Other
  171. * supported keys include: cv_id/cv_name (of the type), value and rank
  172. * @param $options
  173. * An array of options. Supported keys include:
  174. * - Any keys supported by chado_generate_var(). See that function definition for
  175. * additional details.
  176. *
  177. * NOTE: the $identifier parameter can really be any array similar to $values passed into
  178. * chado_select_record(). It should fully specify the dbxref record to be returned.
  179. *
  180. * @return
  181. * If unique values were passed in as an identifier then an object describing the dbxref
  182. * will be returned (will be a chado variable from chado_generate_var()). Otherwise,
  183. * FALSE will be returned.
  184. *
  185. * @ingroup tripal_db_api
  186. */
  187. function tripal_get_dbxref($identifiers, $options = array()) {
  188. // Set Defaults
  189. if (!isset($options['include_fk'])) {
  190. // Tells chado_generate_var not only expand the db
  191. $options['include_fk'] = array('db_id' => TRUE);
  192. }
  193. // Error Checking of parameters
  194. if (!is_array($identifiers)) {
  195. tripal_report_error('tripal_db_api', TRIPAL_ERROR,
  196. "tripal_get_dbxref: The identifier passed in is expected to be an array with the key
  197. matching a column name in the dbxref table (ie: dbxref_id or name). You passed in %identifier.",
  198. array('%identifier'=> print_r($identifiers, TRUE))
  199. );
  200. }
  201. elseif (empty($identifiers)) {
  202. tripal_report_error('tripal_db_api', TRIPAL_ERROR,
  203. "tripal_get_dbxref: You did not pass in anything to identify the dbxref you want. The identifier
  204. is expected to be an array with the key matching a column name in the dbxref table
  205. (ie: dbxref_id or name). You passed in %identifier.",
  206. array('%identifier'=> print_r($identifiers, TRUE))
  207. );
  208. }
  209. // If one of the identifiers is property then use chado_get_record_with_property()
  210. if (isset($identifiers['property'])) {
  211. $property = $identifiers['property'];
  212. unset($identifiers['property']);
  213. $dbxref = chado_get_record_with_property(
  214. array('table' => 'dbxref', 'base_records' => $identifiers),
  215. array('type_name' => $property),
  216. $options
  217. );
  218. }
  219. // Else we have a simple case and we can just use chado_generate_var to get the analysis
  220. else {
  221. $dbxref = chado_generate_var('dbxref', $identifiers, $options);
  222. }
  223. // Ensure the dbxref is singular. If it's an array then it is not singular
  224. if (is_array($dbxref)) {
  225. tripal_report_error('tripal_db_api', TRIPAL_ERROR,
  226. "tripal_get_dbxref: The identifiers you passed in were not unique. You passed in %identifier.",
  227. array('%identifier'=> print_r($identifiers, TRUE))
  228. );
  229. }
  230. // Report an error if $dbxref is FALSE since then chado_generate_var has failed
  231. elseif ($dbxref === FALSE) {
  232. tripal_report_error(
  233. 'tripal_db_api',
  234. TRIPAL_ERROR,
  235. "tripal_get_dbxref: chado_generate_var() failed to return a dbxref based on the identifiers
  236. you passed in. You should check that your identifiers are correct, as well as, look
  237. for a chado_generate_var error for additional clues. You passed in %identifier.",
  238. array(
  239. '%identifier'=> print_r($identifiers, TRUE)
  240. )
  241. );
  242. }
  243. // Else, as far we know, everything is fine so give them their dbxref :)
  244. else {
  245. return $dbxref;
  246. }
  247. }
  248. /**
  249. * Generates a URL for the controlled vocabulary term.
  250. *
  251. * If the URL and URL prefix are provided for the database record of a cvterm
  252. * then a URL can be created for the term. By default, the db.name and
  253. * dbxref.accession are concatenated and appended to the end of the db.urlprefix.
  254. * But Tripal supports the use of {db} and {accession} tokens when if present
  255. * in the db.urlprefix string will be replaced with the db.name and
  256. * dbxref.accession respectively.
  257. *
  258. * @param $dbxref
  259. * A dbxref object as created by the chado_generate_var() function.
  260. *
  261. * @return
  262. * A string containing the URL.
  263. */
  264. function tripal_get_dbxref_url($dbxref) {
  265. $final_url = '';
  266. // Create the URL for the term.
  267. if ($dbxref->db_id->urlprefix) {
  268. $db_count = 0;
  269. $acc_count = 0;
  270. $url = $dbxref->db_id->urlprefix;
  271. // If the URL prefix has replacement tokens then use those.
  272. $url = preg_replace('/\{db\}/', $dbxref->db_id->name, $url, -1, $db_count);
  273. $url = preg_replace('/\{accession\}/', $dbxref->accession, $url, -1, $acc_count);
  274. $final_url = $url;
  275. // If no replacements were made above then tokens weren't used and we can
  276. // default to just appending the db name and accession to the end.
  277. if (!$db_count and !$acc_count) {
  278. $final_url = $dbxref->db_id->urlprefix . $dbxref->db_id->name . ':' . $dbxref->accession;
  279. }
  280. // If the URL prefix is relative then convert it to a full URL.
  281. if (!preg_match('/^(http|https)/', $final_url)) {
  282. $final_url = url($final_url, array('absolute' => TRUE));
  283. }
  284. }
  285. return $final_url;
  286. }
  287. /**
  288. * Adds a new database to the Chado DB table and returns the DB object.
  289. *
  290. * @param $values
  291. * An associative array of the values of the db (those to be inserted)
  292. * - name: The name of the database. This name is usually used as the prefix for
  293. * CV term accessions
  294. * - description: (Optional) A description of the database. By default no description is required.
  295. * - url: (Optional) The URL for the database
  296. * - urlprefix: (Optional) The URL that is to be used as a prefix when constructing a
  297. * link to a database term
  298. * @param $options
  299. * Optional. An associative array of options that can include:
  300. * - update_existing: Set this to '1' to force an update of the database if it
  301. * already exists. The default is to not update. If the database exists
  302. * then nothing is added.
  303. *
  304. * @return
  305. * An object populated with fields from the newly added database. If the
  306. * database already exists it returns the values in the current entry.
  307. *
  308. * @ingroup tripal_chado_database_api
  309. */
  310. function tripal_insert_db($values, $options = array()) {
  311. // Default Values
  312. $dbname = $values['name'];
  313. $description = (isset($values['description'])) ? $values['description'] : '';
  314. $url = (isset($values['url'])) ? $values['url'] : '';
  315. $urlprefix = (isset($values['urlprefix'])) ? $values['urlprefix'] : '';
  316. $update = (isset($options['update_existing'])) ? $options['update_existing'] : TRUE;
  317. // build the values array for inserting/updating
  318. $ins_values = array(
  319. 'name' => $dbname,
  320. 'description' => $description,
  321. 'url' => $url,
  322. 'urlprefix' => $urlprefix
  323. );
  324. // get the database record if it already exists
  325. $sel_values = array('name' => $dbname);
  326. $result = chado_select_record('db', array('*'), $sel_values);
  327. // if it does not exists then add it
  328. if (count($result) == 0) {
  329. $ins_options = array('statement_name' => 'ins_db_nadeurur');
  330. $success = chado_insert_record('db', $ins_values, $ins_options);
  331. if (!$success) {
  332. tripal_report_error('tripal_chado', TRIPAL_WARNING, "Cannot create db '$dbname'.", NULL);
  333. return 0;
  334. }
  335. $result = chado_select_record('db', array('*'), $sel_values);
  336. }
  337. // if it exists and update is enabled the do the update
  338. elseif ($update) {
  339. $upd_options = array('statement_name' => 'upd_db_nadeurur');
  340. $success = chado_update_record('db', $sel_values, $ins_values, $upd_options);
  341. if (!$success) {
  342. tripal_report_error('tripal_chado', TRIPAL_WARNING, "Cannot update db '$dbname'.", NULL);
  343. return 0;
  344. }
  345. $result = chado_select_record('db', array('*'), $sel_values);
  346. }
  347. // return the database object
  348. return $result[0];
  349. }
  350. /**
  351. * Add a database reference
  352. *
  353. * @param $values
  354. * An associative array of the values to be inserted including:
  355. * - db_id: the database_id of the database the reference is from
  356. * - accession: the accession
  357. * - version: (Optional) The version of the database reference
  358. * - description: (Optional) A description of the database reference
  359. *
  360. * @return
  361. * The newly inserted dbxref as an object, similar to that returned by
  362. * the chado_select_record() function.
  363. *
  364. * @ingroup tripal_chado_database_api
  365. */
  366. function tripal_insert_dbxref($values) {
  367. $db_id = $values['db_id'];
  368. $accession = $values['accession'];
  369. $version = (isset($values['version'])) ? $values['version'] : '';
  370. $description = (isset($values['description'])) ? $values['description'] : '';
  371. $ins_values = array(
  372. 'db_id' => $db_id,
  373. 'accession' => $accession,
  374. 'version' => $version,
  375. 'description' => $description
  376. );
  377. // check to see if the dbxref exists
  378. $sel_values = array(
  379. 'db_id' => $db_id,
  380. 'accession' => $accession,
  381. 'version' => $version
  382. );
  383. $result = chado_select_record('dbxref', array('*'), $sel_values);
  384. // if it doesn't already exist then add it
  385. if (!$result) {
  386. $success = chado_insert_record('dbxref', $ins_values);
  387. if (!$success) {
  388. tripal_report_error('tripal_chado', TRIPAL_WARNING, "Failed to insert the dbxref record $accession", NULL);
  389. return 0;
  390. }
  391. $result = chado_select_record('dbxref', array('*'), $sel_values);
  392. }
  393. if (isset($result[0])) {
  394. return $result[0];
  395. }
  396. else {
  397. return FALSE;
  398. }
  399. }
  400. /**
  401. * Add a record to a database reference linking table (ie: feature_dbxref)
  402. *
  403. * @param $basetable
  404. * The base table for which the dbxref should be associated. Thus to associate a dbxref
  405. * with a feature the basetable=feature and dbxref_id is added to the feature_dbxref table
  406. * @param $record_id
  407. * The primary key of the basetable to associate the dbxref with. This should be in integer.
  408. * @param $dbxref
  409. * An associative array describing the dbxref. Valid keys include: 'accession' => the
  410. * accession for the dbxref, 'db_name' => the name of the database the dbxref belongs to;
  411. * 'db_id' => the primary key of the database the dbxref belongs to.
  412. * @param $options
  413. * An associative array of options. Valid keys include:
  414. * - insert_dbxref: Insert the dbxref if it doesn't already exist. TRUE is the default
  415. *
  416. * @ingroup tripal_chado_database_api
  417. */
  418. function tripal_associate_dbxref($basetable, $record_id, $dbxref, $options = array()) {
  419. $linking_table = $basetable . '_dbxref';
  420. $foreignkey_name = $basetable . '_id';
  421. // Default Values
  422. $options['insert_dbxref'] = (isset($options['insert_dbxref'])) ? $options['insert_dbxref'] : TRUE;
  423. // If the dbxref_id is set then we know it already exists
  424. // Otherwise, select to check
  425. if (!isset($dbxref['dbxref_id'])) {
  426. $values = array(
  427. 'accession' => $dbxref['accession'],
  428. );
  429. if (isset($dbxref['db_id'])) {
  430. $values['db_id'] = $dbxref['db_id'];
  431. } elseif (isset($dbxref['db_name'])) {
  432. $values['db_id'] = array(
  433. 'name' => $dbxref['db_name']
  434. );
  435. }
  436. else {
  437. tripal_report_error(
  438. 'tripal_chado_database_api',
  439. TRIPAL_WARNING,
  440. "tripal_associate_dbxref: The dbxref needs to have either the db_name or db_id
  441. supplied. You were trying to associate a dbxref with the %base %record_id
  442. and supplied the dbxref values: %dbxref.",
  443. array('%base' => $basetable, '%record_id' => $record_id, '%dbxref' => print_r($dbxref,TRUE))
  444. );
  445. return FALSE;
  446. }
  447. $select = chado_select_record('dbxref',array('*'), $values);
  448. if ($select) {
  449. $dbxref['dbxref_id'] = $select[0]->dbxref_id;
  450. }
  451. elseif ($options['insert_dbxref']) {
  452. // Insert the dbxref
  453. $insert = tripal_insert_dbxref($values);
  454. if (isset($insert->dbxref_id)) {
  455. $dbxref['dbxref_id'] = $insert->dbxref_id;
  456. }
  457. else {
  458. tripal_report_error(
  459. 'tripal_chado_database_api',
  460. TRIPAL_WARNING,
  461. "tripal_associate_dbxref: Unable to insert the dbxref using the dbxref values: %dbxref.",
  462. array('%dbxref' => print_r($dbxref,TRUE))
  463. );
  464. return FALSE;
  465. }
  466. }
  467. else {
  468. tripal_report_error(
  469. 'tripal_api',
  470. TRIPAL_WARNING,
  471. "tripal_associate_dbxref: The dbxref doesn't already exist. You supplied the dbxref values: %dbxref.",
  472. array('%dbxref' => print_r($dbxref,TRUE))
  473. );
  474. return FALSE;
  475. }
  476. }
  477. // Now add the link between the record & dbxref
  478. if ($dbxref['dbxref_id'] > 0) {
  479. $values = array(
  480. 'dbxref_id' => $dbxref['dbxref_id'],
  481. $foreignkey_name => $record_id
  482. );
  483. $result = chado_select_record($linking_table, array('*'), $values);
  484. // if it doesn't already exist then add it
  485. if (!$result) {
  486. $success = chado_insert_record($linking_table, $values);
  487. if (!$success) {
  488. tripal_report_error(
  489. 'tripal_api',
  490. TRIPAL_WARNING,
  491. "Failed to insert the %base record %accession",
  492. array('%base' => $linking_table, '%accession' => $dbxref['accession'])
  493. );
  494. return FALSE;
  495. }
  496. $result = chado_select_record($linking_table, array('*'), $values);
  497. }
  498. if (isset($result[0])) {
  499. return $result[0];
  500. }
  501. else {
  502. return FALSE;
  503. }
  504. }
  505. return FALSE;
  506. }
  507. /**
  508. * This function is intended to be used in autocomplete forms
  509. * for searching for accession that begin with the provided string
  510. *
  511. * @param $db_id
  512. * The DB ID in which to search for the term
  513. * @param $string
  514. * The string to search for
  515. *
  516. * @return
  517. * A json array of terms that begin with the provided string
  518. *
  519. * @ingroup tripal_db_api
  520. */
  521. function tripal_autocomplete_dbxref($db_id, $string = '') {
  522. if (!$db_id) {
  523. return drupal_json_output(array());
  524. }
  525. $sql = "
  526. SELECT dbxref_id, accession
  527. FROM {dbxref}
  528. WHERE db_id = :db_id and lower(accession) like lower(:accession)
  529. ORDER by accession
  530. LIMIT 25 OFFSET 0
  531. ";
  532. $results = chado_query($sql, array(':db_id' => $db_id, ':accession' => $string . '%'));
  533. $items = array();
  534. foreach ($results as $ref) {
  535. $items[$ref->accession] = $ref->accession;
  536. }
  537. drupal_json_output($items);
  538. }