tripal_core.chado_general.api.inc

Provides an application programming interface (API) to manage data withing the Chado database.

File

tripal_core/api/tripal_core.chado_general.api.inc
View source
  1. <?php
  2. /**
  3. * @file
  4. * Provides an application programming interface (API) to manage data withing the Chado database.
  5. */
  6. require_once 'tripal_core.schema_v1.2.api.inc';
  7. require_once 'tripal_core.schema_v1.11.api.inc';
  8. /**
  9. * @defgroup tripal_chado_api Chado API
  10. * @ingroup tripal_core_api
  11. * @{
  12. * Provides an application programming interface (API) to manage data withing the Chado database.
  13. *
  14. * This includes functions for selecting, inserting, updating and deleting records
  15. * in Chado tables. The functions will ensure proper integrity contraints are met
  16. * for inserts and updates.
  17. *
  18. * Also, a set of functions is provided for creating template variables. First,
  19. * is the chado_generate_var which is used to select one ore more
  20. * records from a table and return an array with foreign key relationships fully
  21. * populated. For example, if selecting a feature, the organism_id and type_id
  22. * would be present in the returned array as a nested array with their respective
  23. * foreign keys also nested. The only fields that are not included are text
  24. * fields (which may be very large) or many-to-many foreign key relationships.
  25. * However, these fields and relationships can be expanded using the
  26. * chado_expand_var.
  27. *
  28. * When a row from a chado table is selected using these two functions, it provides
  29. * a way for users who want to cutomize Drupal template files to access all data
  30. * associate with a specific record.
  31. *
  32. * Finally, the property tables in Chado generally follow the same format. Therefore
  33. * there is a set of functions for inserting, updating and deleting properties for
  34. * any table. This provides quick lookup of properties (provided the CV term is
  35. * known).
  36. *
  37. * @}
  38. *
  39. */
  40. /**
  41. * Set the Tripal Database
  42. *
  43. * The chado_set_active function is used to prevent namespace collisions
  44. * when Chado and Drupal are installed in the same database but in different
  45. * schemas. It is also used when using Drupal functions such as
  46. * db_table_exists().
  47. *
  48. * The connection settings can be altered through the hook
  49. * hook_chado_connection_alter.
  50. *
  51. * Current active connection name is stored in the global variable
  52. * $GLOBALS['chado_active_db'].
  53. *
  54. * @see hook_chado_connection_alter()
  55. *
  56. * @ingroup tripal_chado_api
  57. */
  58. function chado_set_active($dbname = 'default') {
  59. // Check if the chado_active_db has been set yet.
  60. if (!array_key_exists('chado_active_db', $GLOBALS)) {
  61. $GLOBALS['chado_active_db'] = 'default';
  62. }
  63. $previous_db = $active_db = $GLOBALS['chado_active_db'];
  64. $search_path = tripal_get_schema_name('drupal');
  65. // Change only if 'chado' has been specified.
  66. // Notice that we leave the active_db set as chado but use the possibly user-altered
  67. // schema name for the actual search path. This is to keep outward facing mentions of
  68. // chado as "chado" while still allowing the user to alter the schema name used.
  69. if ($dbname == 'chado') {
  70. $active_db = 'chado';
  71. $search_path = tripal_get_schema_name('chado') . ',' . tripal_get_schema_name('drupal');
  72. }
  73. else {
  74. $active_db = $dbname;
  75. }
  76. $settings = array(
  77. 'dbname' => $dbname,
  78. 'new_active_db' => &$active_db,
  79. 'new_search_path' => &$search_path,
  80. );
  81. // Will call all modules implementing hook_chado_search_path_alter
  82. // note: hooks can alter $active_db and $search_path.
  83. drupal_alter('chado_connection', $settings);
  84. // set chado_active_db to remember active db
  85. $GLOBALS['chado_active_db'] = $active_db;
  86. // set PostgreSQL search_path
  87. db_query('SET search_path TO ' . $search_path);
  88. return $previous_db;
  89. }
  90. /**
  91. * Alter Chado connection settings.
  92. *
  93. * This hook is useful for multi-chado instances. Tripal core functions
  94. * call the chado_set_active() function (e.g. chado_query) but there is no
  95. * opportunity elsewhere to set the active database. This is useful in two
  96. * cases: 1) Users are managed at the database level as in the case of
  97. * SouthGreen Bioinformatics Platform tools (e.g. Banana Genone Hub).
  98. * This allows custom modules to change the database connections on a per-user
  99. * basis, and each user permissions is managed at the database level. Users
  100. * are managed at the database level to provid the same access restrictions
  101. * across various tools that use Chado (e,g, Artemis) 2) When there are
  102. * simply two Chado instances housed in different Chado databases and the
  103. * module needs to control which one is being used at any given time.
  104. *
  105. * @param $settings
  106. * An array containing
  107. *
  108. * @see chado_set_active()
  109. *
  110. * @ingroup tripal_chado_api
  111. */
  112. function hook_chado_connection_alter(&$settings) {
  113. // This example shows how we could make sure no table of the 'public' schema
  114. // would be allowed in the coming queries: to do so, the caller will call
  115. // "chado_set_active('chado_only');" and the hook will remove 'public' from
  116. // the search path.
  117. if ('chado_only' == $settings['dbname']) {
  118. $settings['new_active_db'] = 'chado';
  119. // We don't include 'public' in search path.
  120. $settings['new_search_path'] = 'chado';
  121. }
  122. }
  123. /**
  124. * Get max rank for a given set of criteria
  125. * This function was developed with the many property tables in chado in mind but will
  126. * work for any table with a rank
  127. *
  128. * @params tablename: the name of the chado table you want to select the max rank from
  129. * this table must contain a rank column of type integer
  130. * @params where_options: array(
  131. * <column_name> => array(
  132. * 'type' => <type of column: INT/STRING>,
  133. * 'value' => <the value you want to filter on>,
  134. * 'exact' => <if TRUE use =; if FALSE use ~>,
  135. * )
  136. * )
  137. * where options should include the id and type for that table to correctly
  138. * group a set of records together where the only difference are the value and rank
  139. * @return the maximum rank
  140. *
  141. * @ingroup tripal_chado_api
  142. */
  143. function chado_get_table_max_rank($tablename, $where_options) {
  144. $where_clauses = array();
  145. $where_args = array();
  146. //generate the where clause from supplied options
  147. // the key is the column name
  148. $i = 0;
  149. $sql = "
  150. SELECT max(rank) as max_rank, count(rank) as count
  151. FROM {".$tablename."}
  152. WHERE
  153. ";
  154. foreach ($where_options as $key => $value) {
  155. $where_clauses[] = "$key = :$key";
  156. $where_args[":$key"] = $value;
  157. }
  158. $sql .= implode($where_clauses, ' AND ');
  159. $result = chado_query($sql, $where_args)->fetchObject();
  160. if ($result->count > 0) {
  161. return $result->max_rank;
  162. }
  163. else {
  164. return -1;
  165. }
  166. }
  167. /**
  168. * Retrieve a property for a given base table record.
  169. *
  170. * @param $record
  171. * An array used to identify the record to which the property is associated.
  172. * The following keys must be used:
  173. * -table: The base table for which the property should be updated.
  174. * Thus to update a property for a feature the base_table=feature.
  175. * -id: The primary key value of the base table. The property will be
  176. * associated with the record that matches this id.
  177. * -prop_id: The primary key in the [table]prop table. If this value
  178. * is supplied then the 'table' and 'id' keys are not needed.
  179. * @param $property
  180. * An associative array used to specify the property to be selected. It can
  181. * contain the following keys. The keys must be specified to uniquely identify
  182. * the term to be applied. If the options identify more than one CV term
  183. * then an error will occur.
  184. * -type_name: The cvterm name to be selected.
  185. * -type_id: The cvterm_id of the term to be selected.
  186. * -cv_id: The cv_id of the CV that contains the term.
  187. * -cv_name: The name of the CV that contains the term.
  188. * -value: The specific value for the property.
  189. * -rank: The specific rank for the property.
  190. * @return
  191. * An array in the same format as that generated by the function
  192. * chado_generate_var(). If only one record is returned it
  193. * is a single object. If more than one record is returned then it is an array
  194. * of objects
  195. *
  196. * @ingroup tripal_chado_api
  197. */
  198. function chado_get_property($record, $property) {
  199. $base_table = array_key_exists('table', $record) ? $record['table'] : '';
  200. $base_id = array_key_exists('id', $record) ? $record['id'] : '';
  201. $prop_id = array_key_exists('prop_id', $record) ? $record['prop_id'] : '';
  202. $type_name = array_key_exists('type_name', $property) ? $property['type_name'] : '';
  203. $type_id = array_key_exists('type_id', $property) ? $property['type_id'] : '';
  204. $cv_name = array_key_exists('cv_name', $property) ? $property['cv_name'] : '';
  205. $cv_id = array_key_exists('cv_id', $property) ? $property['cv_id'] : '';
  206. $value = array_key_exists('value', $property) ? $property['value'] : '';
  207. $rank = array_key_exists('rank', $property) ? $property['rank'] : 0;
  208. // Build the values array for checking if the CVterm exists and for
  209. // retrieving the term as a property.
  210. $type = array();
  211. if ($cv_id) {
  212. $type['cv_id'] = $cv_id;
  213. }
  214. if ($cv_name) {
  215. $type['cv_id'] = array(
  216. 'name' => $cv_name,
  217. );
  218. }
  219. if ($type_name) {
  220. $type['name'] = $type_name;
  221. }
  222. if ($type_id) {
  223. $type['cvterm_id'] = $type_id;
  224. }
  225. // Make sure the CV term exists;
  226. $options = array();
  227. $term = chado_select_record('cvterm', array('cvterm_id'), $type, $options);
  228. if (!$term or count($term) == 0) {
  229. tripal_report_error('tripal_core', TRIPAL_ERROR, "chado_get_property: " .
  230. "Cannot find the term described by: %property.",
  231. array('%property' => print_r($property, TRUE)));
  232. return FALSE;
  233. }
  234. if (count($term) > 1) {
  235. tripal_report_error('tripal_core', TRIPAL_ERROR, "chado_get_property: " .
  236. "Multiple terms found. Cannot add the property. Property was described " .
  237. "by: %property.",
  238. array('%property' => print_r($property, TRUE))); return FALSE;
  239. }
  240. // get the foreign key for this property table
  241. $table_desc = chado_get_schema($base_table . 'prop');
  242. $fkcol = key($table_desc['foreign keys'][$base_table]['columns']);
  243. // construct the array of values to be selected
  244. $values = array(
  245. $fkcol => $base_id,
  246. 'type_id' => $type,
  247. );
  248. // if we have the unique property_id make sure to add that to the values
  249. if ($prop_id) {
  250. $property_pkey = $table_desc['primary key'][0];
  251. $values[$property_pkey] = $prop_id;
  252. }
  253. $results = chado_generate_var($base_table . 'prop', $values);
  254. if ($results) {
  255. $results = chado_expand_var($results, 'field', $base_table . 'prop.value');
  256. }
  257. return $results;
  258. }
  259. /**
  260. * Insert a property for a given base table.
  261. *
  262. * By default if the property already exists a new property is added with the
  263. * next available rank. If the option 'update_if_present' is specified then
  264. * the record will be updated if it exists rather than adding a new property.
  265. *
  266. * @param $record
  267. * An associative array used to identify the record to which the property
  268. * should be assigned. The following keys must be used:
  269. * -table: The base table for which the property should be inserted.
  270. * Thus to insert a property for a feature the base_table=feature and
  271. * property is inserted into featureprop
  272. * -id: The primary key value of the base table. The property will be
  273. * associated with the record that matches this id.
  274. * @param $property
  275. * An associative array used to specify the property to be added. It can
  276. * contain the following keys. The keys must be specified to uniquely identify
  277. * the term to be applied. If the options identify more than one CV term
  278. * then an error will occur.
  279. * -type_name: The cvterm name to be selected.
  280. * -type_id: The cvterm_id of the term to be selected.
  281. * -cv_id: The cv_id of the CV that contains the term.
  282. * -cv_name: The name of the CV that contains the term.
  283. * -value: The specific value for the property.
  284. * -rank: The specific rank for the property.
  285. * @param $options
  286. * An associative array containing the following keys:
  287. * -update_if_present: A boolean indicating whether an existing record
  288. * should be updated. If the property already exists and this value is
  289. * not specified or is zero then a new property will be added with the
  290. * next largest rank.
  291. * -force_rank: If the specified rank is already used by another property
  292. * recrod for the same base_id, then set force_rank to TRUE to require
  293. * that only the specified rank can be used. Otherwise, the next
  294. * available rank will be used. If 'update_if_present' is FALSE and
  295. * 'force_rank' is set then an error will occur.
  296. *
  297. * @return
  298. * Return TRUE if successful and FALSE otherwise
  299. *
  300. * @ingroup tripal_chado_api
  301. */
  302. function chado_insert_property($record, $property, $options = array()) {
  303. $base_table = array_key_exists('table', $record) ? $record['table'] : '';
  304. $base_id = array_key_exists('id', $record) ? $record['id'] : '';
  305. $type_name = array_key_exists('type_name', $property) ? $property['type_name'] : '';
  306. $type_id = array_key_exists('type_id', $property) ? $property['type_id'] : '';
  307. $cv_name = array_key_exists('cv_name', $property) ? $property['cv_name'] : '';
  308. $cv_id = array_key_exists('cv_id', $property) ? $property['cv_id'] : '';
  309. $value = array_key_exists('value', $property) ? $property['value'] : '';
  310. $rank = array_key_exists('rank', $property) ? $property['rank'] : 0;
  311. $update_if_present = array_key_exists('update_if_present', $options) ? $options['update_if_present'] : FALSE;
  312. $force_rank = array_key_exists('force_rank', $options) ? $options['force_rank'] : FALSE;
  313. // First see if the property is already assigned to the record. I
  314. $props = chado_get_property($record, $property);
  315. if (!is_array($props)) {
  316. if ($props) {
  317. $props = array($props);
  318. }
  319. else {
  320. $props = array();
  321. }
  322. }
  323. if (count($props) > 0) {
  324. // The property is already assigned, so, see if we should update it.
  325. if ($update_if_present) {
  326. return chado_update_property($record, $property);
  327. }
  328. else {
  329. if (!$force_rank) {
  330. // iterate through the properties returned and check to see if the
  331. // property with this value already exists if not, get the largest rank
  332. // and insert the same property but with this new value
  333. foreach ($props as $prop) {
  334. if ($prop->rank > $rank) {
  335. $rank = $prop->rank;
  336. }
  337. if (strcmp($prop->value, $value) == 0) {
  338. return TRUE;
  339. }
  340. }
  341. // now add 1 to the rank
  342. $rank++;
  343. }
  344. else {
  345. tripal_report_error('tripal_core', TRIPAL_ERROR, "chado_insert_property: " .
  346. "The property is already assigned to the record with the following " .
  347. "rank. And, because the 'force_rank' option is used, the property " .
  348. "cannot be added: %property.",
  349. array('%property' => print_r($property, true)));
  350. return FALSE;
  351. }
  352. }
  353. }
  354. // Build the values array for checking if the CVterm exists and for
  355. // inserting the term as a property.
  356. $values = array();
  357. if ($cv_id) {
  358. $values['cv_id'] = $cv_id;
  359. }
  360. if ($cv_name) {
  361. $values['cv_id'] = array(
  362. 'name' => $cv_name,
  363. );
  364. }
  365. if ($type_name) {
  366. $values['name'] = $type_name;
  367. }
  368. if ($type_id) {
  369. $values['cvterm_id'] = $type_id;
  370. }
  371. // Make sure the CV term exists;
  372. $options = array();
  373. $term = chado_select_record('cvterm', array('cvterm_id'), $values, $options);
  374. if (!$term or count($term) == 0) {
  375. tripal_report_error('tripal_core', TRIPAL_ERROR, "chado_insert_property: " .
  376. "Cannot find the term described by: %property.",
  377. array('%property' => print_r($property, TRUE)));
  378. return FALSE;
  379. }
  380. if (count($term) > 1) {
  381. tripal_report_error('tripal_core', TRIPAL_ERROR, "chado_insert_property: " .
  382. "Multiple terms found. Cannot add the property. Property was described " .
  383. "by: %property.",
  384. array('%property' => print_r($property, TRUE))); return FALSE;
  385. }
  386. // Get the foreign key for this property table
  387. $table_desc = chado_get_schema($base_table . 'prop');
  388. $fkcol = key($table_desc['foreign keys'][$base_table]['columns']);
  389. // Add the property to the record.
  390. $values = array(
  391. $fkcol => $base_id,
  392. 'type_id' => $values,
  393. 'value' => $value,
  394. 'rank' => $rank,
  395. );
  396. $result = chado_insert_record($base_table . 'prop', $values);
  397. return $result;
  398. }
  399. /**
  400. * Update a property for a given base table record and property name.
  401. *
  402. * @param $record
  403. * An associative array used to identify the record to which the property
  404. * should be updated. The following keys must be used:
  405. * -table: The base table for which the property should be updated.
  406. * Thus to update a property for a feature the base_table=feature.
  407. * -id: The primary key value of the base table. The property will be
  408. * associated with the record that matches this id.
  409. * -prop_id: The primary key in the [table]prop table. If this value
  410. * is supplied then the 'table' and 'id' keys are not needed.
  411. * @param $property
  412. * An associative array used to specify the property to be updated. It can
  413. * contain the following keys. The keys must be specified to uniquely identify
  414. * the term to be applied. If the options identify more than one CV term
  415. * then an error will occur.
  416. * -type_name: The cvterm name to be selected.
  417. * -type_id: The cvterm_id of the term to be selected.
  418. * -cv_id: The cv_id of the CV that contains the term.
  419. * -cv_name: The name of the CV that contains the term.
  420. * -value: The specific value for the property.
  421. * -rank: The specific rank for the property.
  422. * @param $options
  423. * An associative array containing the following keys:
  424. * -insert_if_missing: A boolean indicating whether a record should be
  425. * inserted if one doesn't exist to update.
  426. *
  427. *
  428. * @return
  429. * Return TRUE on Update/Insert and FALSE otherwise
  430. *
  431. * @ingroup tripal_chado_api
  432. */
  433. function chado_update_property($record, $property, $options = array()) {
  434. $base_table = array_key_exists('table', $record) ? $record['table'] : '';
  435. $base_id = array_key_exists('id', $record) ? $record['id'] : '';
  436. $prop_id = array_key_exists('prop_id', $record) ? $record['prop_id'] : '';
  437. $type_name = array_key_exists('type_name', $property) ? $property['type_name'] : '';
  438. $type_id = array_key_exists('type_id', $property) ? $property['type_id'] : '';
  439. $cv_name = array_key_exists('cv_name', $property) ? $property['cv_name'] : '';
  440. $cv_id = array_key_exists('cv_id', $property) ? $property['cv_id'] : '';
  441. $value = array_key_exists('value', $property) ? $property['value'] : '';
  442. $rank = array_key_exists('rank', $property) ? $property['rank'] : 0;
  443. $insert_if_missing = array_key_exists('insert_if_missing', $options) ? $options['insert_if_missing'] : FALSE;
  444. // first see if the property is missing (we can't update a missing property
  445. $prop = chado_get_property($record, $property);
  446. if (count($prop) == 0) {
  447. if ($insert_if_missing) {
  448. return chado_insert_property($record, $property);
  449. }
  450. else {
  451. return FALSE;
  452. }
  453. }
  454. // Build the values array for checking if the CVterm exists.
  455. $type = array();
  456. if ($cv_id) {
  457. $type['cv_id'] = $cv_id;
  458. }
  459. if ($cv_name) {
  460. $type['cv_id'] = array(
  461. 'name' => $cv_name,
  462. );
  463. }
  464. if ($type_name) {
  465. $type['name'] = $type_name;
  466. }
  467. if ($type_id) {
  468. $type['cvterm_id'] = $type_id;
  469. }
  470. // Make sure the CV term exists;
  471. $options = array();
  472. $term = chado_select_record('cvterm', array('cvterm_id'), $type, $options);
  473. if (!$term or count($term) == 0) {
  474. tripal_report_error('tripal_core', TRIPAL_ERROR, "chado_update_property: " .
  475. "Cannot find the term described by: %property.",
  476. array('%property' => print_r($property, TRUE)));
  477. return FALSE;
  478. }
  479. if (count($term) > 1) {
  480. tripal_report_error('tripal_core', TRIPAL_ERROR, "chado_update_property: " .
  481. "Multiple terms found. Cannot add the property. Property was described " .
  482. "by: %property.",
  483. array('%property' => print_r($property, TRUE)));
  484. return FALSE;
  485. }
  486. // Get the foreign key for this property table
  487. $table_desc = chado_get_schema($base_table . 'prop');
  488. $fkcol = key($table_desc['foreign keys'][$base_table]['columns']);
  489. // construct the array that will match the exact record to update
  490. $match = array(
  491. $fkcol => $base_id,
  492. 'type_id' => $type,
  493. );
  494. // If we have the unique property_id, make sure to use it in the match to
  495. // ensure we get the exact record. Doesn't rely on there only being one
  496. // property of that type.
  497. if ($prop_id) {
  498. $property_pkey = $table_desc['primary key'][0];
  499. $match = array(
  500. $property_pkey => $prop_id,
  501. );
  502. }
  503. // Construct the array of values to be updated.
  504. $values = array();
  505. $values['value'] = $value;
  506. if ($rank) {
  507. $values['rank'] = $rank;
  508. }
  509. // If we have the unique property_id then we can also update the type
  510. // thus add it to the values to be updated
  511. if ($prop_id) {
  512. $values['type_id'] = $type;
  513. }
  514. return chado_update_record($base_table . 'prop', $match, $values);
  515. }
  516. /**
  517. * Deletes a property for a given base table record using the property name
  518. *
  519. * @param $record
  520. * An associative array used to identify the record to which the property
  521. * should be deleted. The following keys must be used:
  522. * -table: The base table for which the property should be deleted.
  523. * Thus to update a property for a feature the base_table=feature.
  524. * -id: The primary key value of the base table. The property will be
  525. * deleted from the record that matches this id.
  526. * -prop_id: The primary key in the [table]prop table to be deleted. If
  527. * this value is supplied then the 'table' and 'id' keys are not needed.
  528. * @param $property
  529. * An associative array used to specify the property to be updated. It can
  530. * contain the following keys. The keys must be specified to uniquely identify
  531. * the term to be applied. If the options identify more than one CV term
  532. * then an error will occur.
  533. * -type_name: The cvterm name to be selected.
  534. * -type_id: The cvterm_id of the term to be selected.
  535. * -cv_id: The cv_id of the CV that contains the term.
  536. * -cv_name: The name of the CV that contains the term.
  537. * -value: The specific value for the property.
  538. * -rank: The specific rank for the property.
  539. *
  540. * @return
  541. * Return TRUE on successful deletion and FALSE otherwise
  542. *
  543. * @ingroup tripal_chado_api
  544. */
  545. function chado_delete_property($record, $property) {
  546. $base_table = array_key_exists('table', $record) ? $record['table'] : '';
  547. $base_id = array_key_exists('id', $record) ? $record['id'] : '';
  548. $prop_id = array_key_exists('prop_id', $record) ? $record['prop_id'] : '';
  549. $type_name = array_key_exists('type_name', $property) ? $property['type_name'] : '';
  550. $type_id = array_key_exists('type_id', $property) ? $property['type_id'] : '';
  551. $cv_name = array_key_exists('cv_name', $property) ? $property['cv_name'] : '';
  552. $cv_id = array_key_exists('cv_id', $property) ? $property['cv_id'] : '';
  553. $value = array_key_exists('value', $property) ? $property['value'] : '';
  554. $rank = array_key_exists('rank', $property) ? $property['rank'] : 0;
  555. // Build the values array for checking if the CVterm exists
  556. $type = array();
  557. if ($cv_id) {
  558. $type['cv_id'] = $cv_id;
  559. }
  560. if ($cv_name) {
  561. $type['cv_id'] = array(
  562. 'name' => $cv_name,
  563. );
  564. }
  565. if ($type_name) {
  566. $type['name'] = $type_name;
  567. }
  568. if ($type_id) {
  569. $type['cvterm_id'] = $type_id;
  570. }
  571. // Make sure the CV term exists;
  572. $options = array();
  573. $term = chado_select_record('cvterm', array('cvterm_id'), $type, $options);
  574. if (!$term or count($term) == 0) {
  575. tripal_report_error('tripal_core', TRIPAL_ERROR, "chado_delete_property: " .
  576. "Cannot find the term described by: %property.",
  577. array('%property' => print_r($property, TRUE)));
  578. return FALSE;
  579. }
  580. if (count($term) > 1) {
  581. tripal_report_error('tripal_core', TRIPAL_ERROR, "chado_delete_property: " .
  582. "Multiple terms found. Cannot add the property. Property was described " .
  583. "by: %property.",
  584. array('%property' => print_r($property, TRUE))); return FALSE;
  585. }
  586. // get the foreign key for this property table
  587. $table_desc = chado_get_schema($base_table . 'prop');
  588. $fkcol = key($table_desc['foreign keys'][$base_table]['columns']);
  589. // If we have the unique property_id, make sure to use it in the match to ensure
  590. // we get the exact record. Doesn't rely on there only being one property of that type
  591. if ($prop_id) {
  592. $property_pkey = $table_desc['primary key'][0];
  593. $match = array(
  594. $property_pkey => $prop_id
  595. );
  596. }
  597. // construct the array that will match the exact record to update
  598. else {
  599. $match = array(
  600. $fkcol => $record_id,
  601. 'type_id' => $type,
  602. );
  603. }
  604. return chado_delete_record($base_table . 'prop', $match);
  605. }
  606. /**
  607. * Get all records in the base table assigned one or more properties.
  608. *
  609. * The property or properties of interest are specified using the $property
  610. * argument.
  611. *
  612. * @param $record
  613. * An associative array used to identify the table and subset of records to
  614. * to be searched:
  615. * -table: The base table for which the property should be updated.
  616. * Thus to update a property for a feature the base_table=feature.
  617. * -base_records: An array in the format accepted by the chado_select_record
  618. * for specifying a subset of records in the base table.
  619. * @param $property
  620. * An associative array used to specify the property to be selected for. It
  621. * can contain the following keys. The keys must be specified to uniquely
  622. * identify the term to be searched. If the options identify more than one
  623. * CV term then an error will occur.
  624. * -type_name: The cvterm name to be selected.
  625. * -type_id: The cvterm_id of the term to be selected.
  626. * -cv_id: The cv_id of the CV that contains the term.
  627. * -cv_name: The name of the CV that contains the term.
  628. * -value: The specific value for the property.
  629. * -rank: The specific rank for the property.
  630. * @param $options
  631. * An array of options supported by chado_generate_var(). These keys
  632. * are used for generating the cvterm objects returned by this function.
  633. *
  634. * @return
  635. * An array of chado variables with the given property
  636. *
  637. * @ingroup tripal_chado_api
  638. */
  639. function chado_get_record_with_property($record, $property, $options = array()) {
  640. $base_table = array_key_exists('table', $record) ? $record['table'] : '';
  641. $base_records= array_key_exists('base_records', $record) ? $record['base_records'] : array();
  642. $type_name = array_key_exists('type_name', $property) ? $property['type_name'] : '';
  643. $type_id = array_key_exists('type_id', $property) ? $property['type_id'] : '';
  644. $cv_name = array_key_exists('cv_name', $property) ? $property['cv_name'] : '';
  645. $cv_id = array_key_exists('cv_id', $property) ? $property['cv_id'] : '';
  646. $value = array_key_exists('value', $property) ? $property['value'] : '';
  647. $rank = array_key_exists('rank', $property) ? $property['rank'] : '';
  648. $property_table = $base_table . 'prop';
  649. $foreignkey_name = $base_table . '_id';
  650. // Build the values array for checking if the CVterm exists and for
  651. // inserting the term as a property.
  652. $type = array();
  653. if ($cv_id) {
  654. $type['cv_id'] = $cv_id;
  655. }
  656. if ($cv_name) {
  657. $type['cv_id'] = array(
  658. 'name' => $cv_name,
  659. );
  660. }
  661. if ($type_name) {
  662. $type['name'] = $type_name;
  663. }
  664. if ($type_id) {
  665. $type['cvterm_id'] = $type_id;
  666. }
  667. // Make sure the CV term exists;
  668. $term = chado_select_record('cvterm', array('cvterm_id'), $type);
  669. if (!$term or count($term) == 0) {
  670. tripal_report_error('tripal_core', TRIPAL_ERROR, "chado_update_property: " .
  671. "Cannot find the term described by: %property.",
  672. array('%property' => print_r($property, TRUE)));
  673. return FALSE;
  674. }
  675. if (count($term) > 1) {
  676. tripal_report_error('tripal_core', TRIPAL_ERROR, "chado_update_property: " .
  677. "Multiple terms found. Cannot add the property. Property was described " .
  678. "by: %property.",
  679. array('%property' => print_r($property, TRUE))); return FALSE;
  680. }
  681. // Build the array for identifying the property.
  682. $values = array();
  683. $values['type_id'] = $type;
  684. if ($rank) {
  685. $values['rank'] = $rank;
  686. }
  687. if ($value) {
  688. $values['value'] = $value;
  689. }
  690. // Add the base records details to the values array.
  691. if (!empty($base_records)) {
  692. $values[$foreignkey_name] = $base_records;
  693. }
  694. // Now select the ids of the base table that have the properties we want that match.
  695. $select = chado_select_record($property_table, array($foreignkey_name), $values);
  696. // For each of these ids, pull out the full base records
  697. $records = array();
  698. foreach ($select as $s) {
  699. $id = $s->{$foreignkey_name};
  700. $values = array($foreignkey_name => $id);
  701. $records[$id] = chado_generate_var($base_table, $values, $options);
  702. }
  703. return $records;
  704. }