tripal_feature.api.inc 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981
  1. <?php
  2. /**
  3. * @file
  4. * Provides an application programming interface (API) for working with features
  5. */
  6. /**
  7. * @defgroup tripal_feature_api Feature API
  8. * @ingroup tripal_api
  9. * @{
  10. * Provides an application programming interface (API) for working with features
  11. * @}
  12. */
  13. /**
  14. * Retrieve properties from the analysisfeatureprop table for a feature.
  15. *
  16. * @param $analysis_id
  17. * The analysis ID for the analysis feature. This argument is optional but
  18. * if specified it must also be accompanied with a feature ID.
  19. * @param $feature_id
  20. * The feature ID for the analysis feature. This argument is optional but
  21. * if specified it must also be accompanied with an analysis ID.
  22. * @param $analysisfeature_id
  23. * The analysis feature ID for the analysis feature. This argument is
  24. * optional and can be used rather than specifying the $analysis_id and
  25. * $feature_id arguments. If all three arguments are specified (e.g.
  26. * an $analysis_id, $feature_id and $analysisfeature_id, then the
  27. * $analysisfeature_id is used and the other two arguments are ignored.
  28. * @param $property
  29. * The cvterm name of the properties to retrieve
  30. * @param $cv_name
  31. * Optional. The name of the cv to which the property belongs. By
  32. * default this is the 'tripal' cv.
  33. *
  34. * @return
  35. * An analysisfeature chado variable with the specified properties expanded
  36. *
  37. * @ingroup tripal_feature_api
  38. */
  39. function tripal_feature_analysis_get_property($analysis_id = NULL, $feature_id = NUll,
  40. $analysisfeature_id = NULL, $property, $cv_name = 'tripal') {
  41. // check that the incoming arguments are correct
  42. if (($analysis_id and !$feature_id) or
  43. (!$analysis_id and $feature_id)) {
  44. tripal_report_error('tripal_feature', TRIPAL_WARNING,
  45. 'tripal_feature_analysis_get_property: Both an analysis ID and feature ID should be specified',
  46. array());
  47. }
  48. // get the analysisfeature_id if one is not provided
  49. if (!$analysisfeature_id) {
  50. $columns = array('analysisfeature_id');
  51. $values = array('analysis_id' => $analysis_id, 'feature_id' => $feature_id);
  52. $result = chado_select_record('analysisfeature', $columns, $values);
  53. $analysisfeature_id = $result[0]->analysisfeature_id;
  54. }
  55. // get the property.
  56. return chado_get_property('analysisfeature', $analysisfeature_id, $property, $cv_name);
  57. }
  58. /**
  59. * Insert a property for an analysis feature
  60. *
  61. * @param $analysis_id
  62. * The analysis ID for the analysis feature. This argument is optional but
  63. * if specified it must also be accompanied with a feature ID.
  64. * @param $feature_id
  65. * The feature ID for the analysis feature. This argument is optional but
  66. * if specified it must also be accompanied with an analysis ID.
  67. * @param $analysisfeature_id
  68. * The analysis feature ID for the analysis feature. This argument is
  69. * optional and can be used rather than specifying the $analysis_id and
  70. * $feature_id arguments. If all three arguments are specified (e.g.
  71. * an $analysis_id, $feature_id and $analysisfeature_id, then the
  72. * $analysisfeature_id is used and the other two arguments are ignored.
  73. * @param $property
  74. * The cvterm name of the property to insert
  75. * @param $value
  76. * The value of the property to insert
  77. * @param $update_if_present
  78. * A boolean indicated whether to update the record if it's already present
  79. * @param $cv_name
  80. * Optional. The name of the cv to which the property belongs. By
  81. * default this is the 'tripal' cv.
  82. *
  83. * @return
  84. * True of success, False otherwise
  85. *
  86. * @ingroup tripal_feature_api
  87. */
  88. function tripal_feature_analysis_insert_property($analysis_id = NULL, $feature_id = NUll,
  89. $analysisfeature_id = NULL, $property, $value, $update_if_present = 0, $cv_name = 'tripal') {
  90. // check that the incoming arguments are correct
  91. if (($analysis_id and !$feature_id) or
  92. (!$analysis_id and $feature_id)) {
  93. tripal_report_error('tripal_feature', TRIPAL_WARNING,
  94. 'tripal_feature_analysis_insert_property: Both an analysis ID and feature ID should be specified',
  95. array());
  96. }
  97. // get the analysisfeature_id if one is not provided
  98. if (!$analysisfeature_id) {
  99. $columns = array('analysisfeature_id');
  100. $values = array('analysis_id' => $analysis_id, 'feature_id' => $feature_id);
  101. $result = chado_select_record('analysisfeature', $columns, $values);
  102. $analysisfeature_id = $result[0]->analysisfeature_id;
  103. }
  104. // insert the property.
  105. $success = chado_insert_property('analysisfeature', $analysisfeature_id,
  106. $property, $cv_name, $value, $update_if_present);
  107. if (!$success) {
  108. tripal_report_error('tripal_feature', TRIPAL_WARNING,
  109. 'tripal_feature_analysis_insert_property: Failed to insert analysis feature property',
  110. array());
  111. return FALSE;
  112. }
  113. return $success;
  114. }
  115. /**
  116. * Update an analysis feature property using the property name. Use this
  117. * when a property only exists once for a given analysis feature. When more
  118. * than one value can exist for the same property use the
  119. * tripal_feature_analysis_update_property_by_id() function.
  120. *
  121. * @param $analysis_id
  122. * The analysis ID for the analysis feature. This argument is optional but
  123. * if specified it must also be accompanied with a feature ID.
  124. * @param $feature_id
  125. * The feature ID for the analysis feature. This argument is optional but
  126. * if specified it must also be accompanied with an analysis ID.
  127. * @param $analysisfeature_id
  128. * The analysis feature ID for the analysis feature. This argument is
  129. * optional and can be used rather than specifying the $analysis_id and
  130. * $feature_id arguments. If all three arguments are specified (e.g.
  131. * an $analysis_id, $feature_id and $analysisfeature_id, then the
  132. * $analysisfeature_id is used and the other two arguments are ignored.
  133. * @param $property
  134. * The cvterm name of the property to update
  135. * @param $value
  136. * The value of the property to update
  137. * @param $insert_if_missing
  138. * A boolean indicated whether to insert the record if it's absent
  139. * @param $cv_name
  140. * Optional. The name of the cv to which the property belongs. By
  141. * default this is the 'tripal' cv.
  142. *
  143. * Note: The property will be identified using the unique combination of the $analysis_id and $property
  144. * and then it will be updated with the supplied value
  145. *
  146. * @return
  147. * True of success, False otherwise
  148. *
  149. * @ingroup tripal_feature_api
  150. */
  151. function tripal_feature_analysis_update_property($analysis_id = NULL, $feature_id = NUll,
  152. $analysisfeature_id = NULL, $property, $value, $insert_if_missing = 0,
  153. $cv_name = 'tripal') {
  154. // check that the incoming arguments are correct
  155. if (($analysis_id and !$feature_id) or
  156. (!$analysis_id and $feature_id)) {
  157. tripal_report_error('tripal_feature', TRIPAL_WARNING,
  158. 'tripal_feature_analysis_update_property: Both an analysis ID and feature ID should be specified',
  159. array());
  160. }
  161. // get the analysisfeature_id if one is not provided
  162. if (!$analysisfeature_id) {
  163. $columns = array('analysisfeature_id');
  164. $values = array('analysis_id' => $analysis_id, 'feature_id' => $feature_id);
  165. $result = chado_select_record('analysisfeature', $columns, $values);
  166. $analysisfeature_id = $result[0]->analysisfeature_id;
  167. }
  168. // update the property.
  169. return chado_update_property('analysisfeature', $analysisfeature_id, $property, $cv_name, $value, $insert_if_missing);
  170. }
  171. /**
  172. * Update a property for an analysis feature using the analysisfeatureprop_id.
  173. *
  174. * @param $analysisfeatureprop_id
  175. * The analysis feature property ID for the analysis feature.
  176. * @param $property
  177. * The cvterm name of the property
  178. * @param $value
  179. * The value of the property
  180. * @param $cv_name
  181. * Optional. The name of the cv to which the property belongs. By
  182. * default this is the 'tripal' cv.
  183. * *
  184. * @return
  185. * True of success, False otherwise
  186. *
  187. * @ingroup tripal_feature_api
  188. */
  189. function tripal_feature_analysis_update_property_by_id($analysisfeatureprop_id,
  190. $property, $value, $cv_name = 'tripal') {
  191. // update the property.
  192. return chado_update_propertyID('analysisfeature',
  193. $analysisfeatureprop_id, $property, $cv_name, $value);
  194. }
  195. /**
  196. * Delete an analysis feature property using the property name. Use this
  197. * when a property only exists once for a given analysis feature. When more
  198. * than one value can exist for the same property use the
  199. * tripal_feature_analysis_delete_property_by_id() function.
  200. *
  201. * @param $analysis_id
  202. * The analysis ID for the analysis feature. This argument is optional but
  203. * if specified it must also be accompanied with a feature ID.
  204. * @param $feature_id
  205. * The feature ID for the analysis feature. This argument is optional but
  206. * if specified it must also be accompanied with an analysis ID.
  207. * @param $analysisfeature_id
  208. * The analysis feature ID for the analysis feature. This argument is
  209. * optional and can be used rather than specifying the $analysis_id and
  210. * $feature_id arguments. If all three arguments are specified (e.g.
  211. * an $analysis_id, $feature_id and $analysisfeature_id, then the
  212. * $analysisfeature_id is used and the other two arguments are ignored.
  213. * @param $property
  214. * The cvterm name of the property to delete
  215. * @param $cv_name
  216. * Optional. The name of the cv to which the property belongs. By
  217. * default this is the 'tripal' cv.
  218. *
  219. * Note: The property will be identified using the unique combination of the $analysis_id and $property
  220. * and then it will be deleted
  221. *
  222. * @return
  223. * True of success, False otherwise
  224. *
  225. * @ingroup tripal_feature_api
  226. */
  227. function tripal_feature_analysis_delete_property($analysis_id = NULL, $feature_id = NUll,
  228. $analysisfeature_id = NULL, $property, $cv_name = 'tripal') {
  229. // check that the incoming arguments are correct
  230. if (($analysis_id and !$feature_id) or
  231. (!$analysis_id and $feature_id)) {
  232. tripal_report_error('tripal_feature', TRIPAL_WARNING,
  233. 'tripal_feature_analysis_delete_property: Both an analysis ID and feature ID should be specified',
  234. array());
  235. }
  236. // get the analysisfeature_id if one is not provided
  237. if (!$analysisfeature_id) {
  238. $columns = array('analysisfeature_id');
  239. $values = array('analysis_id' => $analysis_id, 'feature_id' => $feature_id);
  240. $result = chado_select_record('analysisfeature', $columns, $values);
  241. $analysisfeature_id = $result[0]->analysisfeature_id;
  242. }
  243. // get the property.
  244. return chado_delete_property('analysisfeature', $analysisfeature_id, $property, $cv_name);
  245. }
  246. /**
  247. * Delete a property using the analysisfeatureprop_id
  248. *
  249. * @param $analysisfeatureprop_id
  250. * The analysis feature property ID for the analysis feature.
  251. *
  252. * @return
  253. * True of success, False otherwise
  254. *
  255. * @ingroup tripal_feature_api
  256. */
  257. function tripal_feature_analysis_delete_property_by_id($analysisfeatureprop_id) {
  258. // get the property.
  259. return chado_delete_propertyID('analysisfeature', $analysisfeatureprop_id);
  260. }
  261. /**
  262. * Retrieve properties of a given type for a given feature
  263. *
  264. * @param $feature_id
  265. * The feature_id of the properties you would like to retrieve
  266. * @param $property
  267. * The cvterm name of the properties to retrieve
  268. * @param $cv_name
  269. * Optional. The name of the cv to which the property belongs. By
  270. * default this is the 'tripal' cv.
  271. *
  272. * @return
  273. * A feature chado variable with the specified properties expanded
  274. *
  275. * @ingroup tripal_feature_api
  276. */
  277. function tripal_feature_get_property($feature_id, $property, $cv_name='tripal') {
  278. return chado_get_property('feature', $feature_id, $property, $cv_name);
  279. }
  280. /**
  281. * Insert a given property
  282. *
  283. * @param $feature_id
  284. * The feature_id of the property to insert
  285. * @param $property
  286. * The cvterm name of the property to insert
  287. * @param $value
  288. * The value of the property to insert
  289. * @param $update_if_present
  290. * A boolean indicated whether to update the record if it's already present
  291. * @param $cv_name
  292. * Optional. The name of the cv to which the property belongs. By
  293. * default this is the 'tripal' cv.
  294. *
  295. * @return
  296. * True of success, False otherwise
  297. *
  298. * @ingroup tripal_feature_api
  299. */
  300. function tripal_feature_insert_property($feature_id, $property, $value,
  301. $update_if_present = 0, $cv_name = 'tripal') {
  302. return chado_insert_property('feature', $feature_id, $property,
  303. $cv_name, $value, $update_if_present);
  304. }
  305. /**
  306. * Update a feature property using the property name. Only use this
  307. * if the property is unique and only exist once for the feature.
  308. *
  309. * @param $feature_id
  310. * The feature_id of the property to update
  311. * @param $property
  312. * The cvterm name of the property to update
  313. * @param $value
  314. * The value of the property to update
  315. * @param $insert_if_missing
  316. * A boolean indicated whether to insert the record if it's absent
  317. * @param $cv_name
  318. * Optional. The name of the cv to which the property belongs. By
  319. * default this is the 'tripal' cv.
  320. *
  321. * Note: The property will be identified using the unique combination of the $feature_id and $property
  322. * and then it will be updated with the supplied value
  323. *
  324. * @return
  325. * True of success, False otherwise
  326. *
  327. * @ingroup tripal_feature_api
  328. */
  329. function tripal_feature_update_property($feature_id, $property,
  330. $value, $insert_if_missing = 0, $cv_name = 'tripal') {
  331. return chado_update_property('feature', $feature_id, $property, $cv_name, $value, $insert_if_missing);
  332. }
  333. /**
  334. * Update a given feature property using the featureprop_id
  335. *
  336. * @param $featureprop_id
  337. * The featureprop_id of the property to update
  338. * @param $property
  339. * The cvterm name of the property
  340. * @param $value
  341. * The value of the property
  342. * @param $cv_name
  343. * Optional. The name of the cv to which the property belongs. By
  344. * default this is the 'tripal' cv.
  345. *
  346. * @return
  347. * True of success, False otherwise
  348. *
  349. * @ingroup tripal_feature_api
  350. */
  351. function tripal_feature_update_property_by_id($featureprop_id, $property,
  352. $value, $cv_name = 'tripal') {
  353. return chado_update_propertyID('feature', $featureprop_id, $property, $cv_name, $value);
  354. }
  355. /**
  356. * Delete a given feature property using the property name. Only use this
  357. * if the property is unique and only exists once for the feature.
  358. *
  359. * @param $feature_id
  360. * The feature_id of the property to delete
  361. * @param $property
  362. * The cvterm name of the property to delete
  363. * @param $cv_name
  364. * Optional. The name of the cv to which the property belongs. By
  365. * default this is the 'tripal' cv.
  366. *
  367. * Note: The property will be identified using the unique combination of the $feature_id and $property
  368. * and then it will be deleted
  369. *
  370. * @return
  371. * True of success, False otherwise
  372. *
  373. * @ingroup tripal_feature_api
  374. */
  375. function tripal_feature_delete_property($feature_id, $property, $cv_name='tripal') {
  376. return chado_delete_property('feature', $feature_id, $property, $cv_name);
  377. }
  378. /**
  379. * Delete a given feature property using the featureprop_id
  380. *
  381. * @param $featureprop_id
  382. * The feature_id of the property to delete
  383. *
  384. * @return
  385. * True of success, False otherwise
  386. *
  387. * @ingroup tripal_feature_api
  388. */
  389. function tripal_feature_delete_property_by_id($featureprop_id) {
  390. return chado_delete_propertyID('feature', $featureprop_id);
  391. }
  392. /**
  393. * Performs a reverse compliment of a nucleotide sequence
  394. *
  395. * @param $sequence
  396. * The nucelotide sequence
  397. *
  398. * @return
  399. * an upper-case reverse complemented sequence
  400. *
  401. * @ingroup tripal_feature_api
  402. */
  403. function tripal_feature_reverse_complement($sequence) {
  404. $seq = strtoupper($sequence);
  405. $seq = strrev($seq);
  406. $seq = str_replace("A", "t", $seq);
  407. $seq = str_replace("T", "a", $seq);
  408. $seq = str_replace("G", "c", $seq);
  409. $seq = str_replace("C", "g", $seq);
  410. $seq = str_replace("Y", "r", $seq);
  411. $seq = str_replace("R", "y", $seq);
  412. $seq = str_replace("W", "w", $seq);
  413. $seq = str_replace("S", "s", $seq);
  414. $seq = str_replace("K", "m", $seq);
  415. $seq = str_replace("M", "k", $seq);
  416. $seq = str_replace("D", "h", $seq);
  417. $seq = str_replace("V", "b", $seq);
  418. $seq = str_replace("H", "d", $seq);
  419. $seq = str_replace("B", "v", $seq);
  420. return strtoupper($seq);
  421. }
  422. /**
  423. * Retrieves the sequence for a feature.
  424. *
  425. * @param $feature_id
  426. * The feature_id of the feature for which the sequence will be retrieved
  427. * @param $feature_name
  428. * The feature name. This will appear on the FASTA definition line
  429. * @param $num_bases_per_line
  430. * Indicate the number of bases to use per line. A new line will be added
  431. * after the specified number of bases on each line.
  432. * @param $derive_from_parent
  433. * Set to '1' if the sequence should be obtained from the parent to which
  434. * this feature is aligned.
  435. * @param $aggregate
  436. * Set to '1' if the sequence should only contain sub features, excluding
  437. * intra sub feature sequence. For example, set this option to obtain just
  438. * the coding sequence of an mRNA.
  439. * @param $output_format
  440. * The type of format. Valid formats include 'fasta_html', 'fasta_txt' and
  441. * 'raw'. The format 'fasta_txt' outputs line
  442. * breaks as <br> tags and the entire return value is in a <span> tag
  443. * with a fixed-width font definition. 'fasta_txt' outputs line breaks with
  444. * windows format carriage returns (e.g. \r\n) with no other formatting. The
  445. * raw format is simply the sequence with now FASTA formatting and no
  446. * line breaks.
  447. * @param $upstream
  448. * An integer specifing the number of upstream bases to include in the output
  449. * @param $downstream
  450. * An integer specifying the number of downstream bases to include in the
  451. * output.
  452. * @param $sub_features
  453. * Only include sub features (or child features) of the types provided in the array
  454. * @param $relationship
  455. * If a relationship name is provided (e.g. sequence_of) then any sequences that
  456. * are in relationships of this type with matched sequences are also included
  457. * @param $rel_part
  458. * If a relationship is provided in the preceeding argument then the rel_part
  459. * must be either 'object' or 'subject' to indicate which side of the
  460. * relationship the matched features belong
  461. *
  462. * @return
  463. * The DNA/protein sequence formated as requested.
  464. *
  465. * @ingroup tripal_feature_api
  466. */
  467. function tripal_feature_get_formatted_sequence($feature_id, $feature_name,
  468. $num_bases_per_line, $derive_from_parent, $aggregate, $output_format,
  469. $upstream, $downstream, $sub_features = array(), $relationship = '', $rel_part = '') {
  470. // to speed things up we need to make sure we have a persistent connection
  471. $connection = tripal_db_persistent_chado();
  472. if (!$upstream) {
  473. $upstream = 0;
  474. }
  475. if (!$downstream) {
  476. $downstream = 0;
  477. }
  478. if ($rel_part == "object" or $rel_part == "subject") {
  479. if ($rel_part == "subject") {
  480. $psql = '
  481. PREPARE feature_rel_get_object (int, text) AS
  482. SELECT FO.feature_id, FO.name, FO.uniquename, CVTO.name as feature_type, O.genus, O.species
  483. FROM feature FS
  484. INNER JOIN feature_relationship FR ON FR.subject_id = FS.feature_id
  485. INNER JOIN cvterm CVTFR ON CVTFR.cvterm_id = FR.type_id
  486. INNER JOIN feature FO ON FO.feature_id = FR.object_id
  487. INNER JOIN cvterm CVTO ON CVTO.cvterm_id = FO.type_id
  488. INNER JOIN organism O ON O.organism_id = FO.organism_id
  489. WHERE
  490. FS.feature_id = $1 AND
  491. CVTFR.name = $2
  492. ';
  493. $status = tripal_core_chado_prepare('feature_rel_get_object', $psql, array('int', 'text'));
  494. if (!$status) {
  495. tripal_report_error('tripal_feature', TRIPAL_ERROR, "init: not able to prepare SQL statement '%name'",
  496. array('%name' => 'feature_by_subject'));
  497. }
  498. $sql = "EXECUTE feature_rel_get_object(:feature_id, :relationship)";
  499. $features = chado_query($sql, array(':feature_id' => $feature_id, ':relationship' => $relationship));
  500. }
  501. if ($rel_part == "object") {
  502. $psql = '
  503. PREPARE feature_rel_get_subject (int, text) AS
  504. SELECT FS.feature_id, FS.name, FS.uniquename, CVTO.name as feature_type, O.genus, O.species
  505. FROM feature FO
  506. INNER JOIN feature_relationship FR ON FR.object_id = FO.feature_id
  507. INNER JOIN cvterm CVTFR ON CVTFR.cvterm_id = FR.type_id
  508. INNER JOIN feature FS ON FS.feature_id = FR.subject_id
  509. INNER JOIN cvterm CVTO ON CVTO.cvterm_id = FS.type_id
  510. INNER JOIN organism O ON O.organism_id = FS.organism_id
  511. WHERE
  512. FO.feature_id = $1 AND
  513. CVTFR.name = $2
  514. ';
  515. $status = tripal_core_chado_prepare('feature_rel_get_subject', $psql, array('int', 'text'));
  516. if (!$status) {
  517. tripal_report_error('tripal_feature', TRIPAL_ERROR, "init: not able to prepare SQL statement '%name'",
  518. array('%name' => 'feature_by_object'));
  519. }
  520. $sql = "EXECUTE feature_rel_get_subject(:feature_id, :relationship)";
  521. $features = chado_query($sql, array(':feature_id' => $feature_id, ':relationship' => $relationship));
  522. }
  523. $sequences = '';
  524. while ($feature = $features->fetchObject()) {
  525. // recurse and get the sequences for these in the relationship
  526. if ($rel_part == "subject") {
  527. $defline = "$feature_name, $relationship, $feature->uniquename $feature->feature_type ($feature->genus $feature->species)";
  528. }
  529. if ($rel_part == "object") {
  530. $defline = "$feature->uniquename $feature->feature_type ($feature->genus $feature->species), $relationship, $feature_name";
  531. }
  532. $sequences .= tripal_feature_get_formatted_sequence($feature->feature_id, $defline,
  533. $num_bases_per_line, $derive_from_parent, $aggregate, $output_format,
  534. $upstream, $downstream, $sub_features, '', '');
  535. }
  536. return $sequences;
  537. }
  538. // prepare statements we'll need to use later
  539. if (!tripal_core_is_sql_prepared('sequence_by_parent')) {
  540. // prepare the queries we're going to use later during the render phase
  541. // This SQL statement uses conditionals in the select clause to handle
  542. // cases cases where the alignment is in the reverse direction and when
  543. // the upstream and downstream extensions go beyond the lenght of the
  544. // parent sequence.
  545. $psql ='
  546. PREPARE sequence_by_parent (int, int, int) AS
  547. SELECT srcname, srcfeature_id, strand, srctypename, typename,
  548. fmin, fmax, upstream, downstream, adjfmin, adjfmax,
  549. substring(residues from (adjfmin + 1) for (upstream + (fmax - fmin) + downstream)) as residues,
  550. genus, species
  551. FROM (
  552. SELECT
  553. OF.name srcname, FL.srcfeature_id, FL.strand,
  554. OCVT.name as srctypename, SCVT.name as typename,
  555. FL.fmin, FL.fmax, OO.genus, OO.species,
  556. CASE
  557. WHEN FL.strand >= 0 THEN
  558. CASE
  559. WHEN FL.fmin - $1 <= 0 THEN 0
  560. ELSE FL.fmin - $1
  561. END
  562. WHEN FL.strand < 0 THEN
  563. CASE
  564. WHEN FL.fmin - $2 <= 0 THEN 0
  565. ELSE FL.fmin - $2
  566. END
  567. END as adjfmin,
  568. CASE
  569. WHEN FL.strand >= 0 THEN
  570. CASE
  571. WHEN FL.fmax + $2 > OF.seqlen THEN OF.seqlen
  572. ELSE FL.fmax + $2
  573. END
  574. WHEN FL.strand < 0 THEN
  575. CASE
  576. WHEN FL.fmax + $1 > OF.seqlen THEN OF.seqlen
  577. ELSE FL.fmax + $1
  578. END
  579. END as adjfmax,
  580. CASE
  581. WHEN FL.strand >= 0 THEN
  582. CASE
  583. WHEN FL.fmin - $1 <= 0 THEN FL.fmin
  584. ELSE $1
  585. END
  586. ELSE
  587. CASE
  588. WHEN FL.fmax + $1 > OF.seqlen THEN OF.seqlen - FL.fmax
  589. ELSE $1
  590. END
  591. END as upstream,
  592. CASE
  593. WHEN FL.strand >= 0 THEN
  594. CASE
  595. WHEN FL.fmax + $2 > OF.seqlen THEN OF.seqlen - FL.fmax
  596. ELSE $2
  597. END
  598. ELSE
  599. CASE
  600. WHEN FL.fmin - $2 <= 0 THEN FL.fmin
  601. ELSE $2
  602. END
  603. END as downstream,
  604. OF.residues
  605. FROM {featureloc} FL
  606. INNER JOIN {feature} SF on FL.feature_id = SF.feature_id
  607. INNER JOIN {cvterm} SCVT on SF.type_id = SCVT.cvterm_id
  608. INNER JOIN {feature} OF on FL.srcfeature_id = OF.feature_id
  609. INNER JOIN {cvterm} OCVT on OF.type_id = OCVT.cvterm_id
  610. INNER JOIN {organism} OO on OF.organism_id = OO.organism_id
  611. WHERE SF.feature_id = $3 and NOT (OF.residues = \'\' or OF.residues IS NULL)) as tbl1
  612. ';
  613. $status = tripal_core_chado_prepare('sequence_by_parent', $psql, array('int', 'int', 'int'));
  614. if (!$status) {
  615. tripal_report_error('tripal_feature', TRIPAL_ERROR,
  616. "init: not able to prepare SQL statement '%name'",
  617. array('%name' => 'sequence_by_parent'));
  618. }
  619. // this query is meant to get all of the sub features of any given
  620. // feature (arg #1) and order them as they appear on the reference
  621. // feature (arg #2).
  622. $psql ='PREPARE sub_features (int, int) AS
  623. SELECT SF.feature_id, CVT.name as type_name, SF.type_id
  624. FROM {feature_relationship} FR
  625. INNER JOIN {feature} SF on SF.feature_id = FR.subject_id
  626. INNER JOIN {cvterm} CVT on CVT.cvterm_id = SF.type_id
  627. INNER JOIN {featureloc} FL on FL.feature_id = FR.subject_id
  628. INNER JOIN {feature} PF on PF.feature_id = FL.srcfeature_id
  629. WHERE FR.object_id = $1 and PF.feature_id = $2
  630. ORDER BY FL.fmin ASC';
  631. $status = tripal_core_chado_prepare('sub_features', $psql, array('int', 'int'));
  632. if (!$status) {
  633. tripal_report_error('tripal_feature', TRIPAL_ERROR,
  634. "init: not able to prepare SQL statement '%name'",
  635. array('%name' => 'ssub_features'));
  636. }
  637. $psql ='PREPARE count_sub_features (int, int) AS
  638. SELECT count(*) as num_children
  639. FROM {feature_relationship} FR
  640. INNER JOIN {feature} SF on SF.feature_id = FR.subject_id
  641. INNER JOIN {cvterm} CVT on CVT.cvterm_id = SF.type_id
  642. INNER JOIN {featureloc} FL on FL.feature_id = FR.subject_id
  643. INNER JOIN {feature} PF on PF.feature_id = FL.srcfeature_id
  644. WHERE FR.object_id = $1 and PF.feature_id = $2';
  645. $status = tripal_core_chado_prepare('count_sub_features', $psql, array('int', 'int'));
  646. if (!$status) {
  647. tripal_report_error('tripal_feature', TRIPAL_ERROR,
  648. "init: not able to prepare SQL statement '%name'",
  649. array('%name' => 'count_sub_features'));
  650. }
  651. }
  652. // if we need to get the sequence from the parent then do so now.
  653. if ($derive_from_parent) {
  654. // execute the query to get the sequence from the parent
  655. $sql = "EXECUTE sequence_by_parent (:upstream, :downstream, :feature_id)";
  656. $parents = chado_query($sql, array(':uptream' => $upstream, ':downstream' => $downstream, ':feature_id' => $feature_id));
  657. while ($parent = $parents->fetchObject()) {
  658. $seq = ''; // initialize the sequence for each parent
  659. // if we are to aggregate then we will ignore the feature returned
  660. // by the query above and rebuild it using the sub features
  661. if ($aggregate) {
  662. // now get the sub features that are located on the parent.
  663. $sql = "EXECUTE sub_features (:feature_id, :srcfeature_id)";
  664. $children = chado_query($sql, array(':feature_id' => $feature_id, ':srcfeature_id' => $parent->srcfeature_id));
  665. $sql = "EXECUTE count_sub_features (:feature_id, :srcfeature_id)";
  666. $sub_features = chado_query($sql, array(':feature_id' => $feature_id, ':srcfeature_id' => $parent->srcfeature_id));
  667. $num_children = $sub_features->fetchObject();
  668. // iterate through the sub features and concat their sequences. They
  669. // should already be in order.
  670. $types = array();
  671. $i = 0;
  672. while ($child = $children->fetchObject()) {
  673. // if the callee has specified that only certain sub features should be
  674. // included then continue if this child is not one of those allowed
  675. // subfeatures
  676. if (count($sub_features) > 0 and !in_array($child->type_name, $sub_features)) {
  677. continue;
  678. }
  679. // keep up with the types
  680. if (!in_array($child->type_name, $types)) {
  681. $types[] = $child->type_name;
  682. }
  683. $sql = "EXECUTE sequence_by_parent (:upstream, %d, :feature_id)";
  684. // if the first sub feature we need to include the upstream bases. first check if
  685. // the feature is in the foward direction or the reverse.
  686. if ($i == 0 and $parent->strand >= 0) { // forward direction
  687. // -------------------------- ref
  688. // ....----> ---->
  689. // up 1 2
  690. $q = chado_query($sql, array(':upstream' => $upstream, ':downstream' => 0, ':feature_id' => $child->feature_id));
  691. }
  692. elseif ($i == 0 and $parent->strand < 0) { // reverse direction
  693. // -------------------------- ref
  694. // ....<---- <----
  695. // down 1 2
  696. $q = chado_query($sql, array(':upstream' => 0, ':downstream' => $downstream, ':feature_id' => $child->feature_id));
  697. }
  698. // Next, if the last sub feature we need to include the downstream bases. first check if
  699. // the feature is in teh forward direction or the reverse
  700. if ($i == $num_children->num_children - 1 and $parent->strand >= 0) { // forward direction
  701. // -------------------------- ref
  702. // ----> ---->....
  703. // 1 2 down
  704. $q = chado_query($sql, array(':upstream' => 0, ':downstream' => $downstream, ':feature_id' => $child->feature_id));
  705. }
  706. elseif ($i == $num_children->num_children - 1 and $parent->strand < 0) { // reverse direction
  707. // -------------------------- ref
  708. // <---- <----....
  709. // 1 2 up
  710. $q = chado_query($sql, array(':upstream' => $upstream, ':downstream' => 0, ':feature_id' => $child->feature_id));
  711. }
  712. // for internal sub features we don't want upstream or downstream bases
  713. else {
  714. $sql = "EXECUTE sequence_by_parent (%d, %d, %d)";
  715. $q = chado_query($sql, array(':upstream' => 0, ':downstream' => 0, ':feature_id' => $child->feature_id));
  716. }
  717. while ($subseq = $q->fetchObject()) {
  718. // concatenate the sequences of all the sub features
  719. if ($subseq->srcfeature_id == $parent->srcfeature_id) {
  720. $seq .= $subseq->residues;
  721. }
  722. }
  723. $i++;
  724. }
  725. }
  726. // if this isn't an aggregate then use the parent residues
  727. else {
  728. $seq = $parent->residues;
  729. }
  730. // get the reverse compliment if feature is on the reverse strand
  731. $dir = 'forward';
  732. if ($parent->strand < 0) {
  733. $seq = tripal_feature_reverse_complement($seq);
  734. $dir = 'reverse';
  735. }
  736. // now format for display
  737. if ($output_format == 'fasta_html') {
  738. $seq = wordwrap($seq, $num_bases_per_line, "<br>", TRUE);
  739. }
  740. elseif ($output_format == 'fasta_txt') {
  741. $seq = wordwrap($seq, $num_bases_per_line, "\r\n", TRUE);
  742. }
  743. $residues .= ">$feature_name. Sequence derived from feature of type, '$parent->srctypename', of $parent->genus $parent->species: $parent->srcname:" . ($parent->adjfmin + 1) . ".." . $parent->adjfmax . " ($dir). ";
  744. if (count($types) > 0) {
  745. $residues .= "Excludes all bases but those of type(s): " . implode(', ', $types) . ". " ;
  746. }
  747. if ($parent->upstream > 0) {
  748. $residues .= "Includes " . $parent->upstream . " bases upstream. ";
  749. }
  750. if ($parent->downstream > 0) {
  751. $residues .= "Includes " . $parent->downstream . " bases downstream. ";
  752. }
  753. if (!$seq) {
  754. if ($output_format == 'fasta_html') {
  755. $residues .= "No sequence available.</br>";
  756. }
  757. else {
  758. $residues .= "No sequence available.\r\n";
  759. }
  760. }
  761. else {
  762. if ($output_format == 'fasta_html') {
  763. $residues .= "<br>";
  764. }
  765. $residues .= "\r\n" . $seq . "\r\n";
  766. if ($output_format == 'fasta_html') {
  767. $residues .= "<br>";
  768. }
  769. }
  770. }
  771. }
  772. // if we are not getting the sequence from the parent sequence then
  773. // use what comes through from the feature record
  774. else {
  775. $sql = "SELECT * FROM {feature} F WHERE feature_id = :feature_id";
  776. $values = chado_query($sql, array(':feature_id' => $feature_id))->fetchObject();
  777. $residues = $values->residues;
  778. if ($output_format == 'fasta_html') {
  779. $residues = wordwrap($residues, $num_bases_per_line, "<br>", TRUE);
  780. }
  781. elseif ($output_format == 'fasta_txt') {
  782. $residues = wordwrap($residues, $num_bases_per_line, "\r\n", TRUE);
  783. }
  784. $residues = ">$feature_name\r\n$residues\r\n";
  785. }
  786. // format the residues for display
  787. if ($residues and $num_bases_per_line) {
  788. if ($output_format == 'fasta_html') {
  789. $residues = '<span style="font-family: monospace;">' . $residues . '</span>';
  790. }
  791. }
  792. return $residues;
  793. }
  794. /**
  795. * This function adds an entry to the feature_dbxref table.
  796. *
  797. * @param $feature_id
  798. * The numeric feature_if of the feature
  799. * @param $dbname
  800. * The name of the database to which the term belongs
  801. * @param accession
  802. * The accession of the term
  803. *
  804. * @return
  805. * TRUE on success. FALSE on failure.
  806. *
  807. * @ingroup tripal_feature_api
  808. */
  809. function tripal_feature_add_dbxref($feature_id, $dbname, $accession) {
  810. // make sure the db exists. If it doesn't, then add it
  811. $values = array('name' => $dbname);
  812. $options = array('statement_name' => 'sel_db_na');
  813. $db = chado_select_record('db', array('db_id'), $values, $options);
  814. if (!$db or count($db) == 0) {
  815. $options = array('statement_name' => 'ins_db_na');
  816. $success = chado_insert_record('db', $values, $options);
  817. if (!$success) {
  818. tripal_report_error('tripal_feature', TRIPAL_WARNING, 'tripal_feature_add_dbxref: The feature dbxref entry for feature, %feature_id, " .
  819. "could not be added because the database, %dbname, does not exist and cannot be added.',
  820. array('%feature_id' => $feature_id, '%dbname' => $dbname));
  821. return FALSE;
  822. }
  823. }
  824. // first make sure that the record doesn't already exist
  825. $values = array(
  826. 'dbxref_id' => array(
  827. 'accession' => $accession,
  828. 'db_id' => array(
  829. 'name' => $dbname
  830. ),
  831. ),
  832. 'feature_id' => $feature_id,
  833. );
  834. $options = array('statement_name' => 'sel_featuredbxref_dbfe');
  835. $xref = chado_select_record('feature_dbxref', array('feature_dbxref_id'), $values, $options);
  836. if (count($xref) == 0) {
  837. // if the record doesn't exist then add it.
  838. $options = array('statement_name' => 'ins_featuredbxref_dbfe');
  839. $success = chado_insert_record('feature_dbxref', $values, $options);
  840. if (!$success) {
  841. tripal_report_error('tripal_feature', TRIPAL_WARNING, 'tripal_feature_add_dbxref: The feature dbxref entry for feature, %feature_id, ' .
  842. 'could not be added: %db:%accession.', array('%feature_id' => $feature_id, '%db' => $dbname,
  843. '%accession' => $accession));
  844. return FALSE;
  845. }
  846. }
  847. return TRUE;
  848. }
  849. /**
  850. * This function adds an entry to the feature_cvterm table.
  851. *
  852. * @param $feature_id
  853. * The numeric feature_if of the feature
  854. * @param $cvname
  855. * The name of the controlled vocabulary to which the term belongs
  856. * @param cvterm
  857. * The name of the cvterm
  858. *
  859. * @return
  860. * TRUE on success. FALSE on failure.
  861. *
  862. * @ingroup tripal_feature_api
  863. */
  864. function tripal_feature_add_cvterm($feature_id, $cvname, $cvterm) {
  865. // make sure the cv exists. If it doesn't, then add it
  866. $values = array('name' => $cvname);
  867. $options = array('statement_name' => 'sel_cv_na');
  868. $cv = chado_select_record('cv', array('cv_id'), $values, $options);
  869. if (!$cv or count($cv) == 0) {
  870. $options = array('statement_name' => 'ins_cv_na');
  871. $success = chado_insert_record('cv', $values, $options);
  872. if (!$success) {
  873. tripal_report_error('tripal_feature', TRIPAL_WARNING, 'tripal_feature_add_cvterm: The feature cvterm entry for feature, %feature_id, " .
  874. "could not be added because the CV, %cvname, does not exist and cannot be added.',
  875. array('%feature_id' => $feature_id, '%cvname' => $cvname));
  876. return FALSE;
  877. }
  878. }
  879. // first make sure that the record doesn't already exist
  880. $values = array(
  881. 'cvterm_id' => array(
  882. 'name' => $cvterm,
  883. 'cv_id' => array(
  884. 'name' => $cvname
  885. ),
  886. ),
  887. 'feature_id' => $feature_id,
  888. 'pub_id' => 1,
  889. );
  890. $options = array('statement_name' => 'sel_featuredcvterm_cvfepu');
  891. $xref = chado_select_record('feature_cvterm', array('feature_cvterm_id'), $values, $options);
  892. if (count($xref) == 0) {
  893. // if the record doesn't exist then add it.
  894. $options = array('statement_name' => 'ins_featurecvterm_cvfepu');
  895. $success = chado_insert_record('feature_cvterm', $values, $options);
  896. if (!$success) {
  897. tripal_report_error('tripal_feature', TRIPAL_WARNING, 'tripal_feature_add_cvterm: The feature cvterm entry for feature, %feature_id, ' .
  898. 'could not be added: %cvterm.', array('%feature_id' => $feature_id, '%cvterm' => $cvterm));
  899. return FALSE;
  900. }
  901. }
  902. return TRUE;
  903. }
  904. /**
  905. * Returns a fasta record for the passed in feature
  906. *
  907. * @param $feature
  908. * A single feature object containing all the fields from the chado.feature table
  909. * @param $desc
  910. * A string containing any additional details you want added to the definition line of
  911. * the fasta record.
  912. *
  913. * Note: the feature accession and name separated by a | will be added
  914. * before the description but on the same line
  915. *
  916. * @ingroup tripal_feature_api
  917. */
  918. function tripal_feature_return_fasta($feature, $desc) {
  919. $fasta = ">" . variable_get('chado_feature_accession_prefix', 'FID') . "$feature->feature_id|$feature->name";
  920. $fasta .= " $desc\n";
  921. $fasta .= wordwrap($feature->residues, 50, "\n", TRUE);
  922. $fasta .= "\n\n";
  923. return $fasta;
  924. }