tripal_feature.api.inc 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994
  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_property('analysisfeature',
  193. NULL, $property, $cv_name, $value, FALSE, $analysisfeatureprop_id);
  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. // construct the array that will match the exact record to update
  259. $match = array(
  260. 'analysisfeatureprop_id' => $analysisfeatureprop_id,
  261. );
  262. return chado_delete_record('analysisfeatureprop', $match);
  263. }
  264. /**
  265. * Retrieve properties of a given type for a given feature
  266. *
  267. * @param $feature_id
  268. * The feature_id of the properties you would like to retrieve
  269. * @param $property
  270. * The cvterm name of the properties to retrieve
  271. * @param $cv_name
  272. * Optional. The name of the cv to which the property belongs. By
  273. * default this is the 'tripal' cv.
  274. *
  275. * @return
  276. * A feature chado variable with the specified properties expanded
  277. *
  278. * @ingroup tripal_feature_api
  279. */
  280. function tripal_feature_get_property($feature_id, $property, $cv_name='tripal') {
  281. return chado_get_property('feature', $feature_id, $property, $cv_name);
  282. }
  283. /**
  284. * Insert a given property
  285. *
  286. * @param $feature_id
  287. * The feature_id of the property to insert
  288. * @param $property
  289. * The cvterm name of the property to insert
  290. * @param $value
  291. * The value of the property to insert
  292. * @param $update_if_present
  293. * A boolean indicated whether to update the record if it's already present
  294. * @param $cv_name
  295. * Optional. The name of the cv to which the property belongs. By
  296. * default this is the 'tripal' cv.
  297. *
  298. * @return
  299. * True of success, False otherwise
  300. *
  301. * @ingroup tripal_feature_api
  302. */
  303. function tripal_feature_insert_property($feature_id, $property, $value,
  304. $update_if_present = 0, $cv_name = 'tripal') {
  305. return chado_insert_property('feature', $feature_id, $property,
  306. $cv_name, $value, $update_if_present);
  307. }
  308. /**
  309. * Update a feature property using the property name. Only use this
  310. * if the property is unique and only exist once for the feature.
  311. *
  312. * @param $feature_id
  313. * The feature_id of the property to update
  314. * @param $property
  315. * The cvterm name of the property to update
  316. * @param $value
  317. * The value of the property to update
  318. * @param $insert_if_missing
  319. * A boolean indicated whether to insert the record if it's absent
  320. * @param $cv_name
  321. * Optional. The name of the cv to which the property belongs. By
  322. * default this is the 'tripal' cv.
  323. *
  324. * Note: The property will be identified using the unique combination of the $feature_id and $property
  325. * and then it will be updated with the supplied value
  326. *
  327. * @return
  328. * True of success, False otherwise
  329. *
  330. * @ingroup tripal_feature_api
  331. */
  332. function tripal_feature_update_property($feature_id, $property,
  333. $value, $insert_if_missing = 0, $cv_name = 'tripal') {
  334. return chado_update_property('feature', $feature_id, $property, $cv_name, $value, $insert_if_missing);
  335. }
  336. /**
  337. * Update a given feature property using the featureprop_id
  338. *
  339. * @param $featureprop_id
  340. * The featureprop_id of the property to update
  341. * @param $property
  342. * The cvterm name of the property
  343. * @param $value
  344. * The value of the property
  345. * @param $cv_name
  346. * Optional. The name of the cv to which the property belongs. By
  347. * default this is the 'tripal' cv.
  348. *
  349. * @return
  350. * True of success, False otherwise
  351. *
  352. * @ingroup tripal_feature_api
  353. */
  354. function tripal_feature_update_property_by_id($featureprop_id, $property,
  355. $value, $cv_name = 'tripal') {
  356. return chado_update_property('feature', NULL, $property, $cv_name, $value, FALSE, $featureprop_id);
  357. }
  358. /**
  359. * Delete a given feature property using the property name. Only use this
  360. * if the property is unique and only exists once for the feature.
  361. *
  362. * @param $feature_id
  363. * The feature_id of the property to delete
  364. * @param $property
  365. * The cvterm name of the property to delete
  366. * @param $cv_name
  367. * Optional. The name of the cv to which the property belongs. By
  368. * default this is the 'tripal' cv.
  369. *
  370. * Note: The property will be identified using the unique combination of the $feature_id and $property
  371. * and then it will be deleted
  372. *
  373. * @return
  374. * True of success, False otherwise
  375. *
  376. * @ingroup tripal_feature_api
  377. */
  378. function tripal_feature_delete_property($feature_id, $property, $cv_name='tripal') {
  379. return chado_delete_property('feature', $feature_id, $property, $cv_name);
  380. }
  381. /**
  382. * Delete a given feature property using the featureprop_id
  383. *
  384. * @param $featureprop_id
  385. * The feature_id of the property to delete
  386. *
  387. * @return
  388. * True of success, False otherwise
  389. *
  390. * @ingroup tripal_feature_api
  391. */
  392. function tripal_feature_delete_property_by_id($featureprop_id) {
  393. // construct the array that will match the exact record to update
  394. $match = array(
  395. 'featureprop_id' => $featureprop_id,
  396. );
  397. return chado_delete_record('featureprop', $match);
  398. }
  399. /**
  400. * Performs a reverse compliment of a nucleotide sequence
  401. *
  402. * @param $sequence
  403. * The nucelotide sequence
  404. *
  405. * @return
  406. * an upper-case reverse complemented sequence
  407. *
  408. * @ingroup tripal_feature_api
  409. */
  410. function tripal_feature_reverse_complement($sequence) {
  411. $seq = strtoupper($sequence);
  412. $seq = strrev($seq);
  413. $seq = str_replace("A", "t", $seq);
  414. $seq = str_replace("T", "a", $seq);
  415. $seq = str_replace("G", "c", $seq);
  416. $seq = str_replace("C", "g", $seq);
  417. $seq = str_replace("Y", "r", $seq);
  418. $seq = str_replace("R", "y", $seq);
  419. $seq = str_replace("W", "w", $seq);
  420. $seq = str_replace("S", "s", $seq);
  421. $seq = str_replace("K", "m", $seq);
  422. $seq = str_replace("M", "k", $seq);
  423. $seq = str_replace("D", "h", $seq);
  424. $seq = str_replace("V", "b", $seq);
  425. $seq = str_replace("H", "d", $seq);
  426. $seq = str_replace("B", "v", $seq);
  427. return strtoupper($seq);
  428. }
  429. /**
  430. * Retrieves the sequence for a feature.
  431. *
  432. * @param $feature_id
  433. * The feature_id of the feature for which the sequence will be retrieved
  434. * @param $feature_name
  435. * The feature name. This will appear on the FASTA definition line
  436. * @param $num_bases_per_line
  437. * Indicate the number of bases to use per line. A new line will be added
  438. * after the specified number of bases on each line.
  439. * @param $derive_from_parent
  440. * Set to '1' if the sequence should be obtained from the parent to which
  441. * this feature is aligned.
  442. * @param $aggregate
  443. * Set to '1' if the sequence should only contain sub features, excluding
  444. * intra sub feature sequence. For example, set this option to obtain just
  445. * the coding sequence of an mRNA.
  446. * @param $output_format
  447. * The type of format. Valid formats include 'fasta_html', 'fasta_txt' and
  448. * 'raw'. The format 'fasta_txt' outputs line
  449. * breaks as <br> tags and the entire return value is in a <span> tag
  450. * with a fixed-width font definition. 'fasta_txt' outputs line breaks with
  451. * windows format carriage returns (e.g. \r\n) with no other formatting. The
  452. * raw format is simply the sequence with now FASTA formatting and no
  453. * line breaks.
  454. * @param $upstream
  455. * An integer specifing the number of upstream bases to include in the output
  456. * @param $downstream
  457. * An integer specifying the number of downstream bases to include in the
  458. * output.
  459. * @param $sub_features
  460. * Only include sub features (or child features) of the types provided in the array
  461. * @param $relationship
  462. * If a relationship name is provided (e.g. sequence_of) then any sequences that
  463. * are in relationships of this type with matched sequences are also included
  464. * @param $rel_part
  465. * If a relationship is provided in the preceeding argument then the rel_part
  466. * must be either 'object' or 'subject' to indicate which side of the
  467. * relationship the matched features belong
  468. *
  469. * @return
  470. * The DNA/protein sequence formated as requested.
  471. *
  472. * @ingroup tripal_feature_api
  473. */
  474. function tripal_feature_get_formatted_sequence($feature_id, $feature_name,
  475. $num_bases_per_line, $derive_from_parent, $aggregate, $output_format,
  476. $upstream, $downstream, $sub_features = array(), $relationship = '', $rel_part = '') {
  477. // to speed things up we need to make sure we have a persistent connection
  478. $connection = tripal_db_persistent_chado();
  479. if (!$upstream) {
  480. $upstream = 0;
  481. }
  482. if (!$downstream) {
  483. $downstream = 0;
  484. }
  485. if ($rel_part == "object" or $rel_part == "subject") {
  486. if ($rel_part == "subject") {
  487. $psql = '
  488. PREPARE feature_rel_get_object (int, text) AS
  489. SELECT FO.feature_id, FO.name, FO.uniquename, CVTO.name as feature_type, O.genus, O.species
  490. FROM feature FS
  491. INNER JOIN feature_relationship FR ON FR.subject_id = FS.feature_id
  492. INNER JOIN cvterm CVTFR ON CVTFR.cvterm_id = FR.type_id
  493. INNER JOIN feature FO ON FO.feature_id = FR.object_id
  494. INNER JOIN cvterm CVTO ON CVTO.cvterm_id = FO.type_id
  495. INNER JOIN organism O ON O.organism_id = FO.organism_id
  496. WHERE
  497. FS.feature_id = $1 AND
  498. CVTFR.name = $2
  499. ';
  500. $status = tripal_core_chado_prepare('feature_rel_get_object', $psql, array('int', 'text'));
  501. if (!$status) {
  502. tripal_report_error('tripal_feature', TRIPAL_ERROR, "init: not able to prepare SQL statement '%name'",
  503. array('%name' => 'feature_by_subject'));
  504. }
  505. $sql = "EXECUTE feature_rel_get_object(:feature_id, :relationship)";
  506. $features = chado_query($sql, array(':feature_id' => $feature_id, ':relationship' => $relationship));
  507. }
  508. if ($rel_part == "object") {
  509. $psql = '
  510. PREPARE feature_rel_get_subject (int, text) AS
  511. SELECT FS.feature_id, FS.name, FS.uniquename, CVTO.name as feature_type, O.genus, O.species
  512. FROM feature FO
  513. INNER JOIN feature_relationship FR ON FR.object_id = FO.feature_id
  514. INNER JOIN cvterm CVTFR ON CVTFR.cvterm_id = FR.type_id
  515. INNER JOIN feature FS ON FS.feature_id = FR.subject_id
  516. INNER JOIN cvterm CVTO ON CVTO.cvterm_id = FS.type_id
  517. INNER JOIN organism O ON O.organism_id = FS.organism_id
  518. WHERE
  519. FO.feature_id = $1 AND
  520. CVTFR.name = $2
  521. ';
  522. $status = tripal_core_chado_prepare('feature_rel_get_subject', $psql, array('int', 'text'));
  523. if (!$status) {
  524. tripal_report_error('tripal_feature', TRIPAL_ERROR, "init: not able to prepare SQL statement '%name'",
  525. array('%name' => 'feature_by_object'));
  526. }
  527. $sql = "EXECUTE feature_rel_get_subject(:feature_id, :relationship)";
  528. $features = chado_query($sql, array(':feature_id' => $feature_id, ':relationship' => $relationship));
  529. }
  530. $sequences = '';
  531. while ($feature = $features->fetchObject()) {
  532. // recurse and get the sequences for these in the relationship
  533. if ($rel_part == "subject") {
  534. $defline = "$feature_name, $relationship, $feature->uniquename $feature->feature_type ($feature->genus $feature->species)";
  535. }
  536. if ($rel_part == "object") {
  537. $defline = "$feature->uniquename $feature->feature_type ($feature->genus $feature->species), $relationship, $feature_name";
  538. }
  539. $sequences .= tripal_feature_get_formatted_sequence($feature->feature_id, $defline,
  540. $num_bases_per_line, $derive_from_parent, $aggregate, $output_format,
  541. $upstream, $downstream, $sub_features, '', '');
  542. }
  543. return $sequences;
  544. }
  545. // prepare statements we'll need to use later
  546. if (!tripal_core_is_sql_prepared('sequence_by_parent')) {
  547. // prepare the queries we're going to use later during the render phase
  548. // This SQL statement uses conditionals in the select clause to handle
  549. // cases cases where the alignment is in the reverse direction and when
  550. // the upstream and downstream extensions go beyond the lenght of the
  551. // parent sequence.
  552. $psql ='
  553. PREPARE sequence_by_parent (int, int, int) AS
  554. SELECT srcname, srcfeature_id, strand, srctypename, typename,
  555. fmin, fmax, upstream, downstream, adjfmin, adjfmax,
  556. substring(residues from (adjfmin + 1) for (upstream + (fmax - fmin) + downstream)) as residues,
  557. genus, species
  558. FROM (
  559. SELECT
  560. OF.name srcname, FL.srcfeature_id, FL.strand,
  561. OCVT.name as srctypename, SCVT.name as typename,
  562. FL.fmin, FL.fmax, OO.genus, OO.species,
  563. CASE
  564. WHEN FL.strand >= 0 THEN
  565. CASE
  566. WHEN FL.fmin - $1 <= 0 THEN 0
  567. ELSE FL.fmin - $1
  568. END
  569. WHEN FL.strand < 0 THEN
  570. CASE
  571. WHEN FL.fmin - $2 <= 0 THEN 0
  572. ELSE FL.fmin - $2
  573. END
  574. END as adjfmin,
  575. CASE
  576. WHEN FL.strand >= 0 THEN
  577. CASE
  578. WHEN FL.fmax + $2 > OF.seqlen THEN OF.seqlen
  579. ELSE FL.fmax + $2
  580. END
  581. WHEN FL.strand < 0 THEN
  582. CASE
  583. WHEN FL.fmax + $1 > OF.seqlen THEN OF.seqlen
  584. ELSE FL.fmax + $1
  585. END
  586. END as adjfmax,
  587. CASE
  588. WHEN FL.strand >= 0 THEN
  589. CASE
  590. WHEN FL.fmin - $1 <= 0 THEN FL.fmin
  591. ELSE $1
  592. END
  593. ELSE
  594. CASE
  595. WHEN FL.fmax + $1 > OF.seqlen THEN OF.seqlen - FL.fmax
  596. ELSE $1
  597. END
  598. END as upstream,
  599. CASE
  600. WHEN FL.strand >= 0 THEN
  601. CASE
  602. WHEN FL.fmax + $2 > OF.seqlen THEN OF.seqlen - FL.fmax
  603. ELSE $2
  604. END
  605. ELSE
  606. CASE
  607. WHEN FL.fmin - $2 <= 0 THEN FL.fmin
  608. ELSE $2
  609. END
  610. END as downstream,
  611. OF.residues
  612. FROM {featureloc} FL
  613. INNER JOIN {feature} SF on FL.feature_id = SF.feature_id
  614. INNER JOIN {cvterm} SCVT on SF.type_id = SCVT.cvterm_id
  615. INNER JOIN {feature} OF on FL.srcfeature_id = OF.feature_id
  616. INNER JOIN {cvterm} OCVT on OF.type_id = OCVT.cvterm_id
  617. INNER JOIN {organism} OO on OF.organism_id = OO.organism_id
  618. WHERE SF.feature_id = $3 and NOT (OF.residues = \'\' or OF.residues IS NULL)) as tbl1
  619. ';
  620. $status = tripal_core_chado_prepare('sequence_by_parent', $psql, array('int', 'int', 'int'));
  621. if (!$status) {
  622. tripal_report_error('tripal_feature', TRIPAL_ERROR,
  623. "init: not able to prepare SQL statement '%name'",
  624. array('%name' => 'sequence_by_parent'));
  625. }
  626. // this query is meant to get all of the sub features of any given
  627. // feature (arg #1) and order them as they appear on the reference
  628. // feature (arg #2).
  629. $psql ='PREPARE sub_features (int, int) AS
  630. SELECT SF.feature_id, CVT.name as type_name, SF.type_id
  631. FROM {feature_relationship} FR
  632. INNER JOIN {feature} SF on SF.feature_id = FR.subject_id
  633. INNER JOIN {cvterm} CVT on CVT.cvterm_id = SF.type_id
  634. INNER JOIN {featureloc} FL on FL.feature_id = FR.subject_id
  635. INNER JOIN {feature} PF on PF.feature_id = FL.srcfeature_id
  636. WHERE FR.object_id = $1 and PF.feature_id = $2
  637. ORDER BY FL.fmin ASC';
  638. $status = tripal_core_chado_prepare('sub_features', $psql, array('int', 'int'));
  639. if (!$status) {
  640. tripal_report_error('tripal_feature', TRIPAL_ERROR,
  641. "init: not able to prepare SQL statement '%name'",
  642. array('%name' => 'ssub_features'));
  643. }
  644. $psql ='PREPARE count_sub_features (int, int) AS
  645. SELECT count(*) as num_children
  646. FROM {feature_relationship} FR
  647. INNER JOIN {feature} SF on SF.feature_id = FR.subject_id
  648. INNER JOIN {cvterm} CVT on CVT.cvterm_id = SF.type_id
  649. INNER JOIN {featureloc} FL on FL.feature_id = FR.subject_id
  650. INNER JOIN {feature} PF on PF.feature_id = FL.srcfeature_id
  651. WHERE FR.object_id = $1 and PF.feature_id = $2';
  652. $status = tripal_core_chado_prepare('count_sub_features', $psql, array('int', 'int'));
  653. if (!$status) {
  654. tripal_report_error('tripal_feature', TRIPAL_ERROR,
  655. "init: not able to prepare SQL statement '%name'",
  656. array('%name' => 'count_sub_features'));
  657. }
  658. }
  659. // if we need to get the sequence from the parent then do so now.
  660. if ($derive_from_parent) {
  661. // execute the query to get the sequence from the parent
  662. $sql = "EXECUTE sequence_by_parent (:upstream, :downstream, :feature_id)";
  663. $parents = chado_query($sql, array(':uptream' => $upstream, ':downstream' => $downstream, ':feature_id' => $feature_id));
  664. while ($parent = $parents->fetchObject()) {
  665. $seq = ''; // initialize the sequence for each parent
  666. // if we are to aggregate then we will ignore the feature returned
  667. // by the query above and rebuild it using the sub features
  668. if ($aggregate) {
  669. // now get the sub features that are located on the parent.
  670. $sql = "EXECUTE sub_features (:feature_id, :srcfeature_id)";
  671. $children = chado_query($sql, array(':feature_id' => $feature_id, ':srcfeature_id' => $parent->srcfeature_id));
  672. $sql = "EXECUTE count_sub_features (:feature_id, :srcfeature_id)";
  673. $sub_features = chado_query($sql, array(':feature_id' => $feature_id, ':srcfeature_id' => $parent->srcfeature_id));
  674. $num_children = $sub_features->fetchObject();
  675. // iterate through the sub features and concat their sequences. They
  676. // should already be in order.
  677. $types = array();
  678. $i = 0;
  679. while ($child = $children->fetchObject()) {
  680. // if the callee has specified that only certain sub features should be
  681. // included then continue if this child is not one of those allowed
  682. // subfeatures
  683. if (count($sub_features) > 0 and !in_array($child->type_name, $sub_features)) {
  684. continue;
  685. }
  686. // keep up with the types
  687. if (!in_array($child->type_name, $types)) {
  688. $types[] = $child->type_name;
  689. }
  690. $sql = "EXECUTE sequence_by_parent (:upstream, %d, :feature_id)";
  691. // if the first sub feature we need to include the upstream bases. first check if
  692. // the feature is in the foward direction or the reverse.
  693. if ($i == 0 and $parent->strand >= 0) { // forward direction
  694. // -------------------------- ref
  695. // ....----> ---->
  696. // up 1 2
  697. $q = chado_query($sql, array(':upstream' => $upstream, ':downstream' => 0, ':feature_id' => $child->feature_id));
  698. }
  699. elseif ($i == 0 and $parent->strand < 0) { // reverse direction
  700. // -------------------------- ref
  701. // ....<---- <----
  702. // down 1 2
  703. $q = chado_query($sql, array(':upstream' => 0, ':downstream' => $downstream, ':feature_id' => $child->feature_id));
  704. }
  705. // Next, if the last sub feature we need to include the downstream bases. first check if
  706. // the feature is in teh forward direction or the reverse
  707. if ($i == $num_children->num_children - 1 and $parent->strand >= 0) { // forward direction
  708. // -------------------------- ref
  709. // ----> ---->....
  710. // 1 2 down
  711. $q = chado_query($sql, array(':upstream' => 0, ':downstream' => $downstream, ':feature_id' => $child->feature_id));
  712. }
  713. elseif ($i == $num_children->num_children - 1 and $parent->strand < 0) { // reverse direction
  714. // -------------------------- ref
  715. // <---- <----....
  716. // 1 2 up
  717. $q = chado_query($sql, array(':upstream' => $upstream, ':downstream' => 0, ':feature_id' => $child->feature_id));
  718. }
  719. // for internal sub features we don't want upstream or downstream bases
  720. else {
  721. $sql = "EXECUTE sequence_by_parent (%d, %d, %d)";
  722. $q = chado_query($sql, array(':upstream' => 0, ':downstream' => 0, ':feature_id' => $child->feature_id));
  723. }
  724. while ($subseq = $q->fetchObject()) {
  725. // concatenate the sequences of all the sub features
  726. if ($subseq->srcfeature_id == $parent->srcfeature_id) {
  727. $seq .= $subseq->residues;
  728. }
  729. }
  730. $i++;
  731. }
  732. }
  733. // if this isn't an aggregate then use the parent residues
  734. else {
  735. $seq = $parent->residues;
  736. }
  737. // get the reverse compliment if feature is on the reverse strand
  738. $dir = 'forward';
  739. if ($parent->strand < 0) {
  740. $seq = tripal_feature_reverse_complement($seq);
  741. $dir = 'reverse';
  742. }
  743. // now format for display
  744. if ($output_format == 'fasta_html') {
  745. $seq = wordwrap($seq, $num_bases_per_line, "<br>", TRUE);
  746. }
  747. elseif ($output_format == 'fasta_txt') {
  748. $seq = wordwrap($seq, $num_bases_per_line, "\r\n", TRUE);
  749. }
  750. $residues .= ">$feature_name. Sequence derived from feature of type, '$parent->srctypename', of $parent->genus $parent->species: $parent->srcname:" . ($parent->adjfmin + 1) . ".." . $parent->adjfmax . " ($dir). ";
  751. if (count($types) > 0) {
  752. $residues .= "Excludes all bases but those of type(s): " . implode(', ', $types) . ". " ;
  753. }
  754. if ($parent->upstream > 0) {
  755. $residues .= "Includes " . $parent->upstream . " bases upstream. ";
  756. }
  757. if ($parent->downstream > 0) {
  758. $residues .= "Includes " . $parent->downstream . " bases downstream. ";
  759. }
  760. if (!$seq) {
  761. if ($output_format == 'fasta_html') {
  762. $residues .= "No sequence available.</br>";
  763. }
  764. else {
  765. $residues .= "No sequence available.\r\n";
  766. }
  767. }
  768. else {
  769. if ($output_format == 'fasta_html') {
  770. $residues .= "<br>";
  771. }
  772. $residues .= "\r\n" . $seq . "\r\n";
  773. if ($output_format == 'fasta_html') {
  774. $residues .= "<br>";
  775. }
  776. }
  777. }
  778. }
  779. // if we are not getting the sequence from the parent sequence then
  780. // use what comes through from the feature record
  781. else {
  782. $sql = "SELECT * FROM {feature} F WHERE feature_id = :feature_id";
  783. $values = chado_query($sql, array(':feature_id' => $feature_id))->fetchObject();
  784. $residues = $values->residues;
  785. if ($output_format == 'fasta_html') {
  786. $residues = wordwrap($residues, $num_bases_per_line, "<br>", TRUE);
  787. }
  788. elseif ($output_format == 'fasta_txt') {
  789. $residues = wordwrap($residues, $num_bases_per_line, "\r\n", TRUE);
  790. }
  791. $residues = ">$feature_name\r\n$residues\r\n";
  792. }
  793. // format the residues for display
  794. if ($residues and $num_bases_per_line) {
  795. if ($output_format == 'fasta_html') {
  796. $residues = '<span style="font-family: monospace;">' . $residues . '</span>';
  797. }
  798. }
  799. return $residues;
  800. }
  801. /**
  802. * This function adds an entry to the feature_dbxref table.
  803. *
  804. * @param $feature_id
  805. * The numeric feature_if of the feature
  806. * @param $dbname
  807. * The name of the database to which the term belongs
  808. * @param accession
  809. * The accession of the term
  810. *
  811. * @return
  812. * TRUE on success. FALSE on failure.
  813. *
  814. * @ingroup tripal_feature_api
  815. */
  816. function tripal_feature_add_dbxref($feature_id, $dbname, $accession) {
  817. // make sure the db exists. If it doesn't, then add it
  818. $values = array('name' => $dbname);
  819. $options = array('statement_name' => 'sel_db_na');
  820. $db = chado_select_record('db', array('db_id'), $values, $options);
  821. if (!$db or count($db) == 0) {
  822. $options = array('statement_name' => 'ins_db_na');
  823. $success = chado_insert_record('db', $values, $options);
  824. if (!$success) {
  825. tripal_report_error('tripal_feature', TRIPAL_WARNING, 'tripal_feature_add_dbxref: The feature dbxref entry for feature, %feature_id, " .
  826. "could not be added because the database, %dbname, does not exist and cannot be added.',
  827. array('%feature_id' => $feature_id, '%dbname' => $dbname));
  828. return FALSE;
  829. }
  830. }
  831. // first make sure that the record doesn't already exist
  832. $values = array(
  833. 'dbxref_id' => array(
  834. 'accession' => $accession,
  835. 'db_id' => array(
  836. 'name' => $dbname
  837. ),
  838. ),
  839. 'feature_id' => $feature_id,
  840. );
  841. $options = array('statement_name' => 'sel_featuredbxref_dbfe');
  842. $xref = chado_select_record('feature_dbxref', array('feature_dbxref_id'), $values, $options);
  843. if (count($xref) == 0) {
  844. // if the record doesn't exist then add it.
  845. $options = array('statement_name' => 'ins_featuredbxref_dbfe');
  846. $success = chado_insert_record('feature_dbxref', $values, $options);
  847. if (!$success) {
  848. tripal_report_error('tripal_feature', TRIPAL_WARNING, 'tripal_feature_add_dbxref: The feature dbxref entry for feature, %feature_id, ' .
  849. 'could not be added: %db:%accession.', array('%feature_id' => $feature_id, '%db' => $dbname,
  850. '%accession' => $accession));
  851. return FALSE;
  852. }
  853. }
  854. return TRUE;
  855. }
  856. /**
  857. * This function adds an entry to the feature_cvterm table.
  858. *
  859. * @param $feature_id
  860. * The numeric feature_if of the feature
  861. * @param $cvname
  862. * The name of the controlled vocabulary to which the term belongs
  863. * @param cvterm
  864. * The name of the cvterm
  865. *
  866. * @return
  867. * TRUE on success. FALSE on failure.
  868. *
  869. * @ingroup tripal_feature_api
  870. */
  871. function tripal_feature_add_cvterm($feature_id, $cvname, $cvterm) {
  872. // make sure the cv exists. If it doesn't, then add it
  873. $values = array('name' => $cvname);
  874. $options = array('statement_name' => 'sel_cv_na');
  875. $cv = chado_select_record('cv', array('cv_id'), $values, $options);
  876. if (!$cv or count($cv) == 0) {
  877. $options = array('statement_name' => 'ins_cv_na');
  878. $success = chado_insert_record('cv', $values, $options);
  879. if (!$success) {
  880. tripal_report_error('tripal_feature', TRIPAL_WARNING, 'tripal_feature_add_cvterm: The feature cvterm entry for feature, %feature_id, " .
  881. "could not be added because the CV, %cvname, does not exist and cannot be added.',
  882. array('%feature_id' => $feature_id, '%cvname' => $cvname));
  883. return FALSE;
  884. }
  885. }
  886. // first make sure that the record doesn't already exist
  887. $values = array(
  888. 'cvterm_id' => array(
  889. 'name' => $cvterm,
  890. 'cv_id' => array(
  891. 'name' => $cvname
  892. ),
  893. ),
  894. 'feature_id' => $feature_id,
  895. 'pub_id' => 1,
  896. );
  897. $options = array('statement_name' => 'sel_featuredcvterm_cvfepu');
  898. $xref = chado_select_record('feature_cvterm', array('feature_cvterm_id'), $values, $options);
  899. if (count($xref) == 0) {
  900. // if the record doesn't exist then add it.
  901. $options = array('statement_name' => 'ins_featurecvterm_cvfepu');
  902. $success = chado_insert_record('feature_cvterm', $values, $options);
  903. if (!$success) {
  904. tripal_report_error('tripal_feature', TRIPAL_WARNING, 'tripal_feature_add_cvterm: The feature cvterm entry for feature, %feature_id, ' .
  905. 'could not be added: %cvterm.', array('%feature_id' => $feature_id, '%cvterm' => $cvterm));
  906. return FALSE;
  907. }
  908. }
  909. return TRUE;
  910. }
  911. /**
  912. * Returns a fasta record for the passed in feature
  913. *
  914. * @param $feature
  915. * A single feature object containing all the fields from the chado.feature table
  916. * @param $desc
  917. * A string containing any additional details you want added to the definition line of
  918. * the fasta record.
  919. *
  920. * Note: the feature accession and name separated by a | will be added
  921. * before the description but on the same line
  922. *
  923. * @ingroup tripal_feature_api
  924. */
  925. function tripal_feature_return_fasta($feature, $desc) {
  926. $fasta = ">" . variable_get('chado_feature_accession_prefix', 'FID') . "$feature->feature_id|$feature->name";
  927. $fasta .= " $desc\n";
  928. $fasta .= wordwrap($feature->residues, 50, "\n", TRUE);
  929. $fasta .= "\n\n";
  930. return $fasta;
  931. }