tripal_core.chado_general.api.inc 29 KB

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