tripal_feature.module 57 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556
  1. <?php
  2. require_once "admin.php";
  3. require_once "syncFeatures.php";
  4. require_once "indexFeatures.php";
  5. require_once "fasta_loader.php";
  6. /*************************************************************************
  7. *
  8. */
  9. function tripal_feature_init(){
  10. // add the jGCharts JS and CSS
  11. drupal_add_js (drupal_get_path('theme', 'tripal').'/js/tripal_feature.js');
  12. drupal_add_js (drupal_get_path('theme', 'tripal').'/js/jgcharts/jgcharts.js');
  13. }
  14. /*************************************************************************
  15. * Implements hook_views_api()
  16. * Purpose: Essentially this hook tells drupal that there is views support for
  17. * for this module which then includes tripal_db.views.inc where all the
  18. * views integration code is
  19. */
  20. function tripal_feature_views_api() {
  21. return array(
  22. 'api' => 2.0,
  23. );
  24. }
  25. /************************************************************************
  26. * Display help and module information
  27. * @param path which path of the site we're displaying help
  28. * @param arg array that holds the current path as would be returned from arg() function
  29. * @return help text for the path
  30. */
  31. function tripal_feature_help($path, $arg) {
  32. $output = '';
  33. switch ($path) {
  34. case "admin/help#tripal_feature":
  35. $output='<p>'.t("Displays links to nodes created on this date").'</p>';
  36. break;
  37. }
  38. return $output;
  39. }
  40. /************************************************************************
  41. * Provide information to drupal about the node types that we're creating
  42. * in this module
  43. */
  44. function tripal_feature_node_info() {
  45. $nodes = array();
  46. $nodes['chado_feature'] = array(
  47. 'name' => t('Feature'),
  48. 'module' => 'chado_feature',
  49. 'description' => t('A feature from the chado database'),
  50. 'has_title' => FALSE,
  51. 'title_label' => t('Feature'),
  52. 'has_body' => FALSE,
  53. 'body_label' => t('Feature Description'),
  54. 'locked' => TRUE
  55. );
  56. return $nodes;
  57. }
  58. /************************************************************************
  59. * Set the permission types that the chado module uses. Essentially we
  60. * want permissionis that protect creation, editing and deleting of chado
  61. * data objects
  62. */
  63. function tripal_feature_perm(){
  64. return array(
  65. 'access chado_feature content',
  66. 'create chado_feature content',
  67. 'delete chado_feature content',
  68. 'edit chado_feature content',
  69. );
  70. }
  71. /************************************************************************
  72. * Set the permission types that the module uses.
  73. */
  74. function chado_feature_access($op, $node, $account) {
  75. if ($op == 'create') {
  76. return user_access('create chado_feature content', $account);
  77. }
  78. if ($op == 'update') {
  79. if (user_access('edit chado_feature content', $account)) {
  80. return TRUE;
  81. }
  82. }
  83. if ($op == 'delete') {
  84. if (user_access('delete chado_feature content', $account)) {
  85. return TRUE;
  86. }
  87. }
  88. if ($op == 'view') {
  89. if (user_access('access chado_feature content', $account)) {
  90. return TRUE;
  91. }
  92. }
  93. return FALSE;
  94. }
  95. /************************************************************************
  96. * Menu items are automatically added for the new node types created
  97. * by this module to the 'Create Content' Navigation menu item. This function
  98. * adds more menu items needed for this module.
  99. */
  100. function tripal_feature_menu() {
  101. $items = array();
  102. // the administative settings menu
  103. $items['admin/tripal/tripal_feature'] = array(
  104. 'title' => 'Features',
  105. 'description' => 'Settings for Chado Features',
  106. 'page callback' => 'drupal_get_form',
  107. 'page arguments' => array('tripal_feature_admin'),
  108. 'access arguments' => array('administer site configuration'),
  109. 'type' => MENU_NORMAL_ITEM,
  110. );
  111. $items['admin/tripal/fasta_loader'] = array(
  112. 'title' => 'Import a multi-FASTA file',
  113. 'description' => 'Load sequences from a multi-FASTA file into Chado',
  114. 'page callback' => 'drupal_get_form',
  115. 'page arguments' => array('tripal_feature_fasta_load_form'),
  116. 'access arguments' => array('administer site configuration'),
  117. 'type' => MENU_NORMAL_ITEM,
  118. );
  119. $items['admin/settings/tripal/tripal_feature/load'] = array(
  120. 'title' => 'Bulk Load',
  121. 'description' => 'Upload Data into Chado & Drupal',
  122. 'page callback' => 'tripal_feature_bulkload',
  123. 'access arguments' => array('administer site configuration'),
  124. 'type' => MENU_NORMAL_ITEM,
  125. );
  126. return $items;
  127. }
  128. /************************************************************************
  129. * When a new chado_feature node is created we also need to add information
  130. * to our chado_feature table. This function is called on insert of a new node
  131. * of type 'chado_feature' and inserts the necessary information.
  132. */
  133. function chado_feature_insert($node){
  134. // remove spaces, newlines from residues
  135. $residues = preg_replace("/[\n\r\s]/","",$node->residues);
  136. // If this feature already exists then don't recreate it in chado
  137. // TODO: the unique index in chado for this also includes the type_id. If the site
  138. // ever needs to have the same feature name for different types then this will break.
  139. $feature_sql = "SELECT *
  140. FROM {Feature} F
  141. INNER JOIN {cvterm} CVT ON F.type_id = CVT.cvterm_id
  142. WHERE uniquename = '%s' and organism_id = %d and CVT.name = '%s'";
  143. $previous_db = tripal_db_set_active('chado');
  144. $feature = db_fetch_object(db_query($feature_sql,$node->uniquename,$node->organism_id,$node->feature_type));
  145. tripal_db_set_active($previous_db);
  146. // if the feature doesn't exist then let's create it in chado.
  147. if(!$feature){
  148. $sql = "INSERT INTO {feature} (organism_id, name, uniquename, residues, seqlen,".
  149. " is_obsolete, type_id)".
  150. " VALUES(%d,'%s','%s','%s',%d, %s, ".
  151. " (SELECT cvterm_id ".
  152. " FROM {CVTerm} CVT ".
  153. " INNER JOIN CV ON CVT.cv_id = CV.cv_id ".
  154. " WHERE CV.name = 'sequence' and CVT.name = '%s'))";
  155. $obsolete = 'FALSE';
  156. if($node->is_obsolete){
  157. $obsolete = 'TRUE';
  158. }
  159. // use chado database
  160. $previous_db = tripal_db_set_active('chado');
  161. db_query($sql,$node->organism_id,$node->name,$node->uniquename,
  162. $residues,strlen($residues),$obsolete,$node->feature_type);
  163. // now that we've added the feature, get the feature id for this feature
  164. $feature = db_fetch_object(db_query($feature_sql,$node->uniquename,$node->organism_id,$node->feature_type));
  165. // now use drupal database
  166. tripal_db_set_active($previous_db);
  167. }
  168. // add the genbank accession and synonyms
  169. chado_feature_add_synonyms($node->synonyms,$feature->feature_id);
  170. // make sure the entry for this feature doesn't already exist in the chado_feature table
  171. // if it doesn't exist then we want to add it.
  172. $node_check_sql = "SELECT * FROM {chado_feature} ".
  173. "WHERE feature_id = '%s'";
  174. $node_check = db_fetch_object(db_query($node_check_sql,$feature->feature_id));
  175. if(!$node_check){
  176. // next add the item to the drupal table
  177. $sql = "INSERT INTO {chado_feature} (nid, vid, feature_id, sync_date) ".
  178. "VALUES (%d, %d, %d, " . time() . ")";
  179. db_query($sql,$node->nid,$node->vid,$feature->feature_id);
  180. }
  181. }
  182. /************************************************************************
  183. */
  184. function chado_feature_delete($node){
  185. // get feature_id so we can remove it from chado database
  186. $sql_drupal = "SELECT feature_id ".
  187. "FROM {chado_feature} ".
  188. "WHERE nid = %d AND vid = %d";
  189. $feature_id = db_result(db_query($sql_drupal, $node->nid, $node->vid));
  190. // remove the drupal content
  191. $sql_del = "DELETE FROM {chado_feature} ".
  192. "WHERE nid = %d ".
  193. "AND vid = %d";
  194. db_query($sql_del, $node->nid, $node->vid);
  195. $sql_del = "DELETE FROM {node} ".
  196. "WHERE nid = %d ".
  197. "AND vid = %d";
  198. db_query($sql_del, $node->nid, $node->vid);
  199. $sql_del = "DELETE FROM {node_revisions} ".
  200. "WHERE nid = %d ".
  201. "AND vid = %d";
  202. db_query($sql_del, $node->nid, $node->vid);
  203. // Remove data from feature tables of chado database. This will
  204. // cause a cascade delete and remove all data in referencing tables
  205. // for this feature
  206. $previous_db = tripal_db_set_active('chado');
  207. db_query("DELETE FROM {feature} WHERE feature_id = %d", $feature_id);
  208. tripal_db_set_active($previous_db);
  209. drupal_set_message("The feature and all associated data were removed from ".
  210. "chado");
  211. }
  212. /************************************************************************
  213. */
  214. function chado_feature_update($node){
  215. if($node->revision){
  216. // TODO -- decide what to do about revisions
  217. } else {
  218. // get the feature for this node:
  219. $sql = 'SELECT feature_id FROM {chado_feature} WHERE vid = %d';
  220. $feature = db_fetch_object(db_query($sql, $node->vid));
  221. // remove spaces, newlines from residues
  222. $residues = preg_replace("/[\n\r\s]/","",$node->residues);
  223. $sql = "UPDATE {feature} ".
  224. " SET residues = '%s', ".
  225. " name = '%s', ".
  226. " uniquename = '%s', ".
  227. " seqlen = %d, ".
  228. " organism_id = %d, ".
  229. " is_obsolete = %s, ".
  230. " type_id = (SELECT cvterm_id ".
  231. " FROM {CVTerm} CVT ".
  232. " INNER JOIN CV ON CVT.cv_id = CV.cv_id ".
  233. " WHERE CV.name = 'sequence' and CVT.name = '%s') ".
  234. "WHERE feature_id = %d ";
  235. $obsolete = 'FALSE';
  236. if($node->is_obsolete){
  237. $obsolete = 'TRUE';
  238. }
  239. $previous_db = tripal_db_set_active('chado'); // use chado database
  240. db_query($sql,$residues,$node->name,$node->uniquename,
  241. strlen($residues),$node->organism_id,$obsolete,$node->feature_type,
  242. $feature->feature_id);
  243. tripal_db_set_active($previous_db); // now use drupal database
  244. // add the genbank accession & synonyms
  245. // chado_feature_add_gbaccession($node->gbaccession,$feature->feature_id);
  246. chado_feature_add_synonyms($node->synonyms,$feature->feature_id);
  247. }
  248. }
  249. /************************************************************************
  250. *
  251. */
  252. function chado_feature_add_synonyms($synonyms,$feature_id){
  253. // make sure we only have a single space between each synonym
  254. $synonyms = preg_replace("/[\s\n\r]+/"," ",$synonyms);
  255. // split the synonyms into an array based on a space as the delimieter
  256. $syn_array = array();
  257. $syn_array = explode(" ",$synonyms);
  258. // use the chado database
  259. $previous_db = tripal_db_set_active('chado');
  260. // remove any old synonyms
  261. $feature_syn_dsql = "DELETE FROM {feature_synonym} WHERE feature_id = %d";
  262. if(!db_query($feature_syn_dsql,$feature_id)){
  263. $error .= "Could not remove synonyms from feature. ";
  264. }
  265. // return if we don't have any synonmys to add
  266. if(!$synonyms){
  267. tripal_db_set_active($previous_db);
  268. return;
  269. }
  270. // iterate through each synonym and add it to the database
  271. foreach($syn_array as $syn){
  272. // skip this item if it's empty
  273. if(!$syn){ break; }
  274. // check to see if we have this accession number already in the database
  275. // if so then don't add it again. it messes up drupal if the insert fails.
  276. // It is possible for the accession number to be present and not the feature
  277. $synonym_sql = "SELECT synonym_id FROM {synonym} ".
  278. "WHERE name = '%s'";
  279. $synonym = db_fetch_object(db_query($synonym_sql,$syn));
  280. if(!$synonym){
  281. $synonym_isql = "INSERT INTO {synonym} (name,synonym_sgml,type_id) ".
  282. "VALUES ('%s','%s', ".
  283. " (SELECT cvterm_id ".
  284. " FROM {CVTerm} CVT ".
  285. " INNER JOIN CV ON CVT.cv_id = CV.cv_id ".
  286. " WHERE CV.name = 'feature_property' and CVT.name = 'synonym'))";
  287. if(!db_query($synonym_isql,$syn,$syn)){
  288. $error .= "Could not add synonym. ";
  289. }
  290. // now get the synonym we just added
  291. $synonym_sql = "SELECT synonym_id FROM {synonym} ".
  292. "WHERE name = '%s'";
  293. $synonym = db_fetch_object(db_query($synonym_sql,$syn));
  294. }
  295. // now add in our new sysnonym
  296. $feature_syn_isql = "INSERT INTO {feature_synonym} (synonym_id,feature_id,pub_id) ".
  297. "VALUES (%d,%d,1)";
  298. if(!db_query($feature_syn_isql,$synonym->synonym_id,$feature_id)){
  299. $error .= "Could not add synonyms to feature. ";
  300. }
  301. }
  302. // return to the drupal database
  303. tripal_db_set_active($previous_db);
  304. return $error;
  305. }
  306. /************************************************************************
  307. *
  308. */
  309. function chado_feature_add_gbaccession($accession,$feature_id){
  310. // use chado database
  311. $previous_db = tripal_db_set_active('chado');
  312. // remove any old accession from genbank dbEST
  313. $fdbxref_dsql = "DELETE FROM {feature_dbxref} ".
  314. "WHERE feature_id = %d and dbxref_id IN ".
  315. " (SELECT DBX.dbxref_id FROM {dbxref} DBX ".
  316. " INNER JOIN DB ON DB.db_id = DBX.db_id ".
  317. " INNER JOIN feature_dbxref FDBX ON DBX.dbxref_id = FDBX.dbxref_id ".
  318. " WHERE DB.name = 'DB:Genbank' and FDBX.feature_id = %d)";
  319. if(!db_query($fdbxref_dsql,$feature_id,$feature_id)){
  320. $error .= "Could not remove accession from feature. ";
  321. }
  322. // if we don't have an accession number to add then just return
  323. if(!$accession){
  324. tripal_db_set_active($previous_db);
  325. return;
  326. }
  327. // get the db_id
  328. $db_sql = "SELECT db_id FROM {DB} ".
  329. "WHERE name = 'DB:Genbank_est'";
  330. $db = db_fetch_object(db_query($db_sql));
  331. // check to see if we have this accession number already in the database
  332. // if so then don't add it again. it messes up drupal if the insert fails.
  333. // It is possible for the accession number to be present and not the feature
  334. $dbxref_sql = "SELECT dbxref_id FROM {dbxref} ".
  335. "WHERE db_id = %d and accession = '%s'";
  336. $dbxref = db_fetch_object(db_query($dbxref_sql,$db->db_id,$accession));
  337. if(!$dbxref){
  338. // add the accession number
  339. $dbxref_isql = "INSERT INTO {dbxref} (db_id,accession) ".
  340. " VALUES (%d, '%s') ";
  341. if(!db_query($dbxref_isql,$db->db_id,$accession)){
  342. $error .= 'Could not add accession as a database reference ';
  343. }
  344. // get the dbxref_id for the just added accession number
  345. $dbxref_sql = "SELECT dbxref_id FROM {dbxref} ".
  346. "WHERE db_id = %d and accession = '%s'";
  347. $dbxref = db_fetch_object(db_query($dbxref_sql,$db->db_id,$accession));
  348. }
  349. // associate the accession number with the feature
  350. $feature_dbxref_isql = "INSERT INTO {feature_dbxref} (feature_id,dbxref_id) ".
  351. " VALUES (%d, %d) ";
  352. if(!db_query($feature_dbxref_isql,$feature_id,$dbxref->dbxref_id)){
  353. $error .= 'Could not add feature database reference. ';
  354. }
  355. tripal_db_set_active($previous_db);
  356. return $error;
  357. }
  358. /************************************************************************
  359. *
  360. */
  361. function chado_feature_form ($node,$param){
  362. $type = node_get_types('type', $node);
  363. $form = array();
  364. $feature = $node->feature;
  365. $synonyms = $node->synonyms;
  366. $analyses = $node->analyses;
  367. $references = $node->references;
  368. // We need to pass above variables for preview to show
  369. $form['feature'] = array(
  370. '#type' => 'value',
  371. '#value' => $feature
  372. );
  373. // This field is read when previewing a node
  374. $form['synonyms'] = array(
  375. '#type' => 'value',
  376. '#value' => $synonyms
  377. );
  378. // This field is read when previewing a node
  379. $form['analyses'] = array(
  380. '#type' => 'value',
  381. '#value' => $analyses
  382. );
  383. // This field is read when previewing a node
  384. $form['references'] = array(
  385. '#type' => 'value',
  386. '#value' => $references
  387. );
  388. // keep track of the feature id if we have one. If we do have one then
  389. // this would indicate an update as opposed to an insert.
  390. $form['feature_id'] = array(
  391. '#type' => 'value',
  392. '#value' => $feature->feature_id,
  393. );
  394. $form['title']= array(
  395. '#type' => 'textfield',
  396. '#title' => t('Title'),
  397. '#required' => TRUE,
  398. '#default_value' => $feature->featurename,
  399. '#description' => t('The title must be a unique identifier for this feature. It is recommended to use a combination of uniquename, organism and feature type in the title as this is guranteed to be unique.'),
  400. '#weight' => 1,
  401. '#maxlength' => 255
  402. );
  403. $form['uniquename']= array(
  404. '#type' => 'textfield',
  405. '#title' => t('Unique Feature Name'),
  406. '#required' => TRUE,
  407. '#default_value' => $feature->featurename,
  408. '#description' => t('Enter a unique name for this feature. This name must be unique for the organism and feature type.'),
  409. '#weight' => 1,
  410. '#maxlength' => 255
  411. );
  412. $form['name']= array(
  413. '#type' => 'textfield',
  414. '#title' => t('Feature Name'),
  415. '#required' => TRUE,
  416. '#default_value' => $feature->featurename,
  417. '#description' => t('Enter the name used by humans to refer to this feature.'),
  418. '#weight' => 1,
  419. '#maxlength' => 255
  420. );
  421. // get the list of supported feature types
  422. $ftypes = array();
  423. $ftypes[''] = '';
  424. $supported_ftypes = split("[ \n]",variable_get('chado_feature_types','EST contig'));
  425. foreach($supported_ftypes as $ftype){
  426. $ftypes["$ftype"] = $ftype;
  427. }
  428. $form['feature_type'] = array (
  429. '#title' => t('Feature Type'),
  430. '#type' => t('select'),
  431. '#description' => t("Choose the feature type."),
  432. '#required' => TRUE,
  433. '#default_value' => $feature->cvname,
  434. '#options' => $ftypes,
  435. '#weight' => 2
  436. );
  437. // get the list of organisms
  438. $sql = "SELECT * FROM {Organism} ORDER BY genus, species";
  439. $previous_db = tripal_db_set_active('chado'); // use chado database
  440. $org_rset = db_query($sql);
  441. tripal_db_set_active($previous_db); // now use drupal database
  442. //
  443. $organisms = array();
  444. $organisms[''] = '';
  445. while($organism = db_fetch_object($org_rset)){
  446. $organisms[$organism->organism_id] = "$organism->genus $organism->species ($organism->common_name)";
  447. }
  448. $form['organism_id'] = array (
  449. '#title' => t('Organism'),
  450. '#type' => t('select'),
  451. '#description' => t("Choose the organism with which this feature is associated "),
  452. '#required' => TRUE,
  453. '#default_value' => $feature->organism_id,
  454. '#options' => $organisms,
  455. '#weight' => 3,
  456. );
  457. // Get synonyms
  458. if ($synonyms) {
  459. if (is_array($synonyms)) {
  460. foreach ($synonyms as $synonym){
  461. $syn_text .= "$synonym->name\n";
  462. }
  463. } else {
  464. $syn_text = $synonyms;
  465. }
  466. }
  467. $form['synonyms']= array(
  468. '#type' => 'textarea',
  469. '#title' => t('Synonyms'),
  470. '#required' => FALSE,
  471. '#default_value' => $syn_text,
  472. '#description' => t('Enter alternate names (synonmys) for this feature to help in searching and identification. You may enter as many alternate names as needed separated by spaces or on different lines.'),
  473. '#weight' => 5,
  474. );
  475. $form['residues']= array(
  476. '#type' => 'textarea',
  477. '#title' => t('Residues'),
  478. '#required' => FALSE,
  479. '#default_value' => $feature->residues,
  480. '#description' => t('Enter the nucelotide sequences for this feature'),
  481. '#weight' => 6
  482. );
  483. $checked = '';
  484. if($feature->is_obsolete == 't'){
  485. $checked = '1';
  486. }
  487. $form['is_obsolete']= array(
  488. '#type' => 'checkbox',
  489. '#title' => t('Is Obsolete'),
  490. '#required' => FALSE,
  491. '#default_value' => $checked,
  492. '#description' => t('Check this box if this sequence should be retired and no longer included in further analysis.'),
  493. '#weight' => 8
  494. );
  495. return $form;
  496. }
  497. /************************************************************************
  498. *
  499. */
  500. function chado_feature_validate($node){
  501. $result = 0;
  502. // if this is an update, we want to make sure that a different feature for
  503. // the organism doesn't already have this uniquename. We don't want to give
  504. // two sequences the same uniquename
  505. if($node->feature_id){
  506. $sql = "SELECT *
  507. FROM {Feature} F
  508. INNER JOIN {cvterm} CVT ON F.type_id = CVT.cvterm_id
  509. WHERE uniquename = '%s'
  510. AND organism_id = %d AND CVT.name = '%s' AND NOT feature_id = %d";
  511. $previous_db = tripal_db_set_active('chado');
  512. $result = db_fetch_object(db_query($sql, $node->uniquename,$node->organism_id,$node->feature_type,$node->feature_id));
  513. tripal_db_set_active($previous_db);
  514. if($result){
  515. form_set_error('uniquename',t("Feature update cannot proceed. The feature name '$node->uniquename' is not unique for this organism. Please provide a unique name for this feature. "));
  516. }
  517. }
  518. // if this is an insert then we just need to make sure this name doesn't
  519. // already exist for this organism if it does then we need to throw an error
  520. else {
  521. $sql = "SELECT *
  522. FROM {Feature} F
  523. INNER JOIN {cvterm} CVT ON F.type_id = CVT.cvterm_id
  524. WHERE uniquename = '%s'
  525. AND organism_id = %d AND CVT.name = '%s'";
  526. $previous_db = tripal_db_set_active('chado');
  527. $result = db_fetch_object(db_query($sql, $node->uniquename,$node->organism_id,$node->feature_type));
  528. tripal_db_set_active($previous_db);
  529. if($result){
  530. form_set_error('uniquename',t("Feature insert cannot proceed. The feature name '$node->uniquename' already exists for this organism. Please provide a unique name for this feature. "));
  531. }
  532. }
  533. // we want to remove all characters except IUPAC nucleotide characters from the
  534. // the residues. however, residues are not required so if blank then we'll skip
  535. // this step
  536. if($node->residues){
  537. $residues = preg_replace("/[^\w]/",'',$node->residues);
  538. if(!preg_match("/^[ACTGURYMKSWBDHVN]+$/i",$residues)){
  539. form_set_error('residues',t("The residues in feature $node->name contains more than the nucleotide IUPAC characters. Only the following characters are allowed: A,C,T,G,U,R,Y,M,K,S,W,B,D,H,V,N: '" . $residues ."'"));
  540. }
  541. }
  542. // we don't allow a genbank accession number for a contig
  543. if($node->feature_type == 'contig' and $node->gbaccession){
  544. form_set_error('gbaccession',t("Contigs cannot have a genbank accession number. Please change the feature type or remove the accession number"));
  545. }
  546. }
  547. /************************************************************************
  548. * When a node is requested by the user this function is called to allow us
  549. * to add auxiliary data to the node object.
  550. */
  551. function chado_feature_load($node){
  552. // add the feature_id for this node:
  553. $sql = 'SELECT feature_id FROM {chado_feature} WHERE vid = %d';
  554. $map = db_fetch_object(db_query($sql, $node->vid));
  555. // get information about this organism and add it to the items in this node
  556. $sql = "SELECT F.feature_id, F.name as featurename, F.uniquename, ".
  557. "F.residues, F.seqlen, O.genus, O.species, O.common_name, ".
  558. " CVT.name as cvname, O.organism_id, F.type_id, F.is_obsolete ".
  559. "FROM {Feature} F ".
  560. " INNER JOIN Organism O ON F.organism_id = O.organism_id ".
  561. " INNER JOIN CVterm CVT ON F.type_id = CVT.cvterm_id ".
  562. "WHERE F.feature_id = %d";
  563. $previous_db = tripal_db_set_active('chado'); // use chado database
  564. $feature = db_fetch_object(db_query($sql,$map->feature_id));
  565. tripal_db_set_active($previous_db); // now use drupal database
  566. $additions->feature = $feature;
  567. $additions->seqlen = $feature->seqlen;
  568. // add organism node nid
  569. $sql = "SELECT nid FROM {chado_organism} WHERE organism_id = %d";
  570. $org_nid = db_result(db_query($sql, $additions->feature->organism_id));
  571. $additions->org_nid = $org_nid;
  572. $additions->accession = variable_get('chado_feature_accession_prefix','ID') . $feature->feature_id;
  573. // add the feature synonyms
  574. $sql = "SELECT S.name ".
  575. "FROM {Feature_Synonym} FS ".
  576. " INNER JOIN Synonym S ".
  577. " ON FS.synonym_id = S.Synonym_id ".
  578. "WHERE FS.feature_id = %d";
  579. $previous_db = tripal_db_set_active('chado'); // use chado database
  580. $results = db_query($sql,$map->feature_id);
  581. tripal_db_set_active($previous_db); // now use drupal database
  582. $synonyms = array();
  583. $i=0;
  584. while($synonym = db_fetch_object($results)){
  585. $synonyms[$i++] = $synonym;
  586. }
  587. $additions->synonyms = $synonyms;
  588. // add feature references in external databases
  589. $sql = "SELECT F.uniquename,F.Feature_id,DBX.accession,DB.description as dbdesc, ".
  590. " DB.db_id, DB.name as db_name, DB.urlprefix ".
  591. "FROM {Feature} F ".
  592. " INNER JOIN Feature_dbxref FDBX on F.feature_id = FDBX.feature_id ".
  593. " INNER JOIN Dbxref DBX on DBX.dbxref_id = FDBX.dbxref_id ".
  594. " INNER JOIN DB on DB.db_id = DBX.db_id ".
  595. "WHERE F.feature_id = %d";
  596. $previous_db = tripal_db_set_active('chado'); // use chado database
  597. $results = db_query($sql,$map->feature_id);
  598. tripal_db_set_active($previous_db); // now use drupal database
  599. $references = array();
  600. $i=0;
  601. while($accession = db_fetch_object($results)){
  602. $references[$i++] = $accession;
  603. }
  604. $additions->references = $references;
  605. // add the feature relationsips
  606. $sql = "SELECT
  607. FS.name as subject_name,
  608. FS.uniquename as subject_uniquename,
  609. CVTS.name as subject_type,
  610. FS.residues as subject_residues,
  611. FR.subject_id,
  612. FR.type_id,
  613. CVT.name as rel_type,
  614. FO.name as object_name,
  615. FO.uniquename as object_uniquename,
  616. CVTO.name as object_type,
  617. FO.residues as object_residues,
  618. FR.object_id
  619. FROM {feature_relationship} FR
  620. INNER JOIN {cvterm} CVT ON FR.type_id = CVT.cvterm_id
  621. INNER JOIN {feature} FS ON FS.feature_id = FR.subject_id
  622. INNER JOIN {feature} FO ON FO.feature_id = FR.object_id
  623. INNER JOIN {cvterm} CVTO ON FO.type_id = CVTO.cvterm_id
  624. INNER JOIN {cvterm} CVTS ON FS.type_id = CVTS.cvterm_id ";
  625. $osql = "$sql WHERE FR.object_id = %d";
  626. $ssql = "$sql WHERE FR.subject_id = %d";
  627. // first get the relationships where this feature is the object
  628. // then where it is the subject
  629. $previous_db = tripal_db_set_active('chado'); // use chado database
  630. $oresults = db_query($osql, $map->feature_id);
  631. $sresults = db_query($ssql, $map->feature_id);
  632. tripal_db_set_active($previous_db); // now use drupal database
  633. // identify the drupal node for each feature and add that to the
  634. // relationship records
  635. $srelationships = array();
  636. $orelationships = array();
  637. $i=0;
  638. $nodesql = "SELECT nid FROM {chado_feature} WHERE feature_id = %d";
  639. while($rel = db_fetch_object($oresults)){
  640. $node = db_fetch_object(db_query($nodesql,$rel->subject_id));
  641. if($node){
  642. $rel->subject_nid = $node->nid;
  643. }
  644. $node = db_fetch_object(db_query($nodesql,$rel->object_id));
  645. if($node){
  646. $rel->object_nid = $node->nid;
  647. }
  648. $orelationships[$i++] = $rel;
  649. }
  650. $i=0;
  651. while($rel = db_fetch_object($sresults)){
  652. $node = db_fetch_object(db_query($nodesql,$rel->subject_id));
  653. if($node){
  654. $rel->subject_nid = $node->nid;
  655. }
  656. $node = db_fetch_object(db_query($nodesql,$rel->object_id));
  657. if($node){
  658. $rel->object_nid = $node->nid;
  659. }
  660. $srelationships[$i++] = $rel;
  661. }
  662. $additions->orelationships = $orelationships;
  663. $additions->srelationships = $srelationships;
  664. // add the feature properties
  665. return $additions;
  666. }
  667. /************************************************************************
  668. * This function customizes the view of the chado_feature node. It allows
  669. * us to generate the markup.
  670. */
  671. function chado_feature_view ($node, $teaser = FALSE, $page = FALSE) {
  672. if (!$teaser) {
  673. // use drupal's default node view:
  674. $node = node_prepare($node, $teaser);
  675. // if we're building the node for searching then
  676. // we want to handle this within the module and
  677. // not allow theme customization. We don't want to
  678. // index all items (such as DNA sequence).
  679. if($node->build_mode == NODE_BUILD_SEARCH_INDEX){
  680. $node->content['index_version'] = array(
  681. '#value' => theme('tripal_feature_search_index',$node),
  682. '#weight' => 1,
  683. );
  684. }
  685. else if($node->build_mode == NODE_BUILD_SEARCH_RESULT){
  686. $node->content['index_version'] = array(
  687. '#value' => theme('tripal_feature_search_results',$node),
  688. '#weight' => 1,
  689. );
  690. }
  691. else {
  692. // do nothing here, let the theme derived template handle display
  693. }
  694. }
  695. return $node;
  696. }
  697. /*******************************************************************************
  698. * Display feature information for associated organisms. This function also
  699. * provides contents for indexing
  700. */
  701. function tripal_feature_nodeapi(&$node, $op, $teaser, $page) {
  702. switch ($op) {
  703. // Note that this function only adds feature view to an organism node.
  704. // The view of a feature node is controled by the theme *.tpl file
  705. case 'view':
  706. // Set the node types for showing feature information
  707. $types_to_show = array('chado_organism', 'chado_library');
  708. // Abort if this node is not one of the types we should show.
  709. if (!in_array($node->type, $types_to_show, TRUE)) {
  710. break;
  711. }
  712. // Add feature to the content item if it's not a teaser
  713. if (!$teaser) {
  714. // Show feature browser
  715. $node->content['tripal_feature_browser'] = array(
  716. '#value' => theme('tripal_feature_browser', $node),
  717. '#weight' => 5
  718. );
  719. $node->content['tripal_feature_org_counts'] = array(
  720. '#value' => theme('tripal_feature_counts', $node),
  721. '#weight' => 4
  722. );
  723. }
  724. }
  725. }
  726. /************************************************************************
  727. * We need to let drupal know about our theme functions and their arguments.
  728. * We create theme functions to allow users of the module to customize the
  729. * look and feel of the output generated in this module
  730. */
  731. function tripal_feature_theme () {
  732. return array(
  733. 'tripal_feature_search_index' => array (
  734. 'arguments' => array('node'),
  735. ),
  736. 'tripal_feature_search_results' => array (
  737. 'arguments' => array('node'),
  738. ),
  739. 'tripal_feature_browser' => array (
  740. 'arguments' => array('node'),
  741. ),
  742. 'tripal_feature_counts' => array (
  743. 'arguments' => array('node'),
  744. )
  745. );
  746. }
  747. /*******************************************************************************
  748. * create a list of features for the organism and pie chart
  749. */
  750. function theme_tripal_feature_counts($node){
  751. // don't show the summary if the settings in the admin page is turned off
  752. $show_browser = variable_get('tripal_feature_summary_setting',array('show_feature_summary'));
  753. if(strcmp($show_browser[0],'show_feature_summary')!=0){
  754. return;
  755. }
  756. // get the feature counts. This is dependent on a materialized view
  757. // installed with the organism module
  758. $content = '';
  759. if ($node->organism_id && $node->type == 'chado_organism') {
  760. $sql = "SELECT * FROM {organism_feature_count} ".
  761. "WHERE organism_id = %d AND NOT feature_type = 'EST_match' ".
  762. "ORDER BY num_features desc";
  763. $features = array();
  764. $previous_db = tripal_db_set_active('chado'); // use chado database
  765. $results = db_query($sql,$node->organism_id);
  766. tripal_db_set_active($previous_db); // now use drupal database
  767. $feature = db_fetch_object($results); // retrieve the first result
  768. if ($feature) {
  769. $content .= "<div class=\"tripal_feature_summary-info-box\"><br>
  770. <div class=\"tripal_expandableBox\">".
  771. "<h3>Feature Summary</h3>".
  772. "</div>";
  773. $content .= "<div class=\"tripal_expandableBoxContent\">";
  774. $content .= "<table class=\"tripal_table_horz\">";
  775. $content .= " <tr>";
  776. $content .= " <th class=\"dbfieldname\">Type</th>";
  777. $content .= " <th class=\"dbfieldname\">Number</th>";
  778. $content .= " </tr>";
  779. do {
  780. $content .= "<tr>";
  781. $content .= " <td>$feature->feature_type</td>";
  782. $content .= " <td>". number_format($feature->num_features) . "</td>";
  783. $content .= "</tr>";
  784. } while($feature = db_fetch_object($results));
  785. $content .= "</table>";
  786. $content .= "
  787. <img class=\"tripal_cv_chart\" id=\"tripal_feature_cv_chart_$node->organism_id\" src=\"\" border=\"0\">
  788. ";
  789. $content .= "</div></div>";
  790. }
  791. }
  792. return $content;
  793. }
  794. /************************************************************************
  795. *
  796. */
  797. function tripal_feature_cv_chart($chart_id){
  798. // The CV module will create the JSON array necessary for buillding a
  799. // pie chart using jgChart and Google Charts. We have to pass to it
  800. // a table that contains count information, tell it which column
  801. // contains the cvterm_id and provide a filter for getting the
  802. // results we want from the table.
  803. $organism_id = preg_replace("/^tripal_feature_cv_chart_(\d+)$/","$1",$chart_id);
  804. $options = array(
  805. count_mview => 'organism_feature_count',
  806. cvterm_id_column => 'cvterm_id',
  807. count_column => 'num_features',
  808. size => '650x200',
  809. filter => "CNT.organism_id = $organism_id AND NOT feature_type = 'EST_match' ",
  810. );
  811. return $options;
  812. }
  813. /************************************************************************
  814. *
  815. */
  816. function tripal_feature_cv_tree($tree_id){
  817. // The CV module will create the JSON array necessary for buillding a
  818. // pie chart using jgChart and Google Charts. We have to pass to it
  819. // a table that contains count information, tell it which column
  820. // contains the cvterm_id and provide a filter for getting the
  821. // results we want from the table.
  822. $organism_id = preg_replace("/^tripal_feature_cv_tree_(\d+)$/","$1",$tree_id);
  823. $options = array(
  824. cv_id => tripal_cv_get_cv_id('sequence'),
  825. count_mview => 'organism_feature_count',
  826. cvterm_id_column => 'cvterm_id',
  827. count_column => 'num_features',
  828. filter => "CNT.organism_id = $organism_id",
  829. label => 'Features',
  830. );
  831. return $options;
  832. }
  833. /*******************************************************************************
  834. * create a simple paged feature browser
  835. */
  836. function theme_tripal_feature_browser($node){
  837. // don't show the browser if the settings in the admin page is turned off
  838. $show_browser = variable_get('tripal_feature_browse_setting',array('show_feature_browser'));
  839. if(strcmp($show_browser[0],'show_feature_browser')!=0){
  840. return;
  841. }
  842. if ($node->organism_id && $node->type == 'chado_organism') {
  843. # get the list of available sequence ontology terms for which
  844. # we will build drupal pages from features in chado. If a feature
  845. # is not one of the specified typse we won't build a node for it.
  846. $allowed_types = variable_get('chado_feature_types','EST contig');
  847. $allowed_types = preg_replace("/[\s\n\r]+/"," ",$allowed_types);
  848. $so_terms = split(' ',$allowed_types);
  849. $where_cvt = "";
  850. foreach ($so_terms as $term){
  851. $where_cvt .= "CVT.name = '$term' OR ";
  852. }
  853. $where_cvt = substr($where_cvt,0,strlen($where_cvt)-3); # strip trailing 'OR'
  854. // get the features for this organism
  855. $sql = "SELECT F.name,F.feature_id,F.uniquename,CVT.name as cvname ".
  856. "FROM {feature} F ".
  857. " INNER JOIN {cvterm} CVT on F.type_id = CVT.cvterm_id ".
  858. "WHERE organism_id = $node->organism_id and ($where_cvt) ".
  859. "ORDER BY feature_id ASC";
  860. // the counting SQL
  861. $csql = "SELECT count(*) ".
  862. "FROM {feature} F".
  863. " INNER JOIN {cvterm} CVT on F.type_id = CVT.cvterm_id ".
  864. "WHERE organism_id = $node->organism_id and ($where_cvt) ".
  865. "GROUP BY organism_id ";
  866. $previous_db = tripal_db_set_active('chado'); // use chado database
  867. $features = pager_query($sql,10,0,$csql);
  868. tripal_db_set_active($previous_db); // now use drupal database
  869. $content = "<br><div id=\"tripal_feature_box\" class=\"feature-info-box\">";
  870. $content .= "<div class=\"tripal_expandableBox\">".
  871. "<h3>Browse Features</h3>".
  872. "</div>";
  873. $content .= "<div class=\"tripal_expandableBoxContent\">";
  874. $content .= "Below are the features associated with this organism.\n";
  875. $content .= "<table class=\"tripal_table_horz\">";
  876. $content .= " <tr>";
  877. $content .= " <th>Feature Name</th>";
  878. $content .= " <th>Type</th>";
  879. $content .= " </tr>";
  880. // prepare the query that will lookup node ids
  881. $sql = "SELECT nid FROM {chado_feature} ".
  882. "WHERE feature_id = %d";
  883. while($feature = db_fetch_object($features)){
  884. $node = db_fetch_object(db_query($sql,$feature->feature_id));
  885. if($node){
  886. $name= "<a href=\"" . url("node/$node->nid") . "\">$feature->name</a>";
  887. } else {
  888. $name= "$feature->name";
  889. }
  890. $content .= " <tr>";
  891. $content .= " <td>$name</td>";
  892. $content .= " <td>$feature->cvname</td>";
  893. $content .= " </tr>";
  894. }
  895. $content .= "</table>";
  896. $content .= theme('pager');
  897. $content .= "</div></div>";
  898. return $content;
  899. }
  900. }
  901. /************************************************************************
  902. * This function is an extension of the chado_feature_view by providing
  903. * the markup for the feature object THAT WILL BE INDEXED.
  904. */
  905. function theme_tripal_feature_search_index ($node) {
  906. $feature = $node->feature;
  907. $content = '';
  908. // get the accession prefix
  909. $aprefix = variable_get('chado_feature_accession_prefix','ID');
  910. $content .= "<h1>$feature->uniquename</h1>. ";
  911. $content .= "<strong>$aprefix$feature->feature_id.</strong> ";
  912. $content .= "$feature->cvname ";
  913. $content .= "$feature->common_name ";
  914. // add the synonyms of this feature to the text for searching
  915. $synonyms = $node->synonyms;
  916. if(count($synonyms) > 0){
  917. foreach ($synonyms as $result){
  918. $content .= "$result->name ";
  919. }
  920. }
  921. return $content;
  922. }
  923. /************************************************************************
  924. * This function is an extension of the chado_feature_view by providing
  925. * the markup for the feature object THAT WILL BE INDEXED.
  926. */
  927. function theme_tripal_feature_search_results ($node) {
  928. $feature = $node->feature;
  929. $content = '';
  930. // get the accession prefix
  931. $aprefix = variable_get('chado_feature_accession_prefix','ID');
  932. $content .= "Feature Name: <h1>$feature->uniquename</h1>. ";
  933. $content .= "<strong>Accession: $aprefix$feature->feature_id.</strong>";
  934. $content .= "Type: $feature->cvname. ";
  935. $content .= "Organism: $feature->common_name. ";
  936. // add the synonyms of this feature to the text for searching
  937. $synonyms = $node->synonyms;
  938. if(count($synonyms) > 0){
  939. $content .= "Synonyms: ";
  940. foreach ($synonyms as $result){
  941. $content .= "$result->name, ";
  942. }
  943. }
  944. return $content;
  945. }
  946. /************************************************************************
  947. *
  948. */
  949. function tripal_feature_set_vocabulary (){
  950. //include the file containing the required functions for adding taxonomy vocabs
  951. module_load_include('inc', 'taxonomy', 'taxonomy.admin');
  952. // get the vocabularies so that we make sure we don't recreate
  953. // the vocabs that already exist
  954. $vocabularies = taxonomy_get_vocabularies();
  955. $ft_vid = NULL;
  956. $op_vid = NULL;
  957. $lb_vid = NULL;
  958. $an_vid = NULL;
  959. // These taxonomic terms are hard coded because we
  960. // konw we have these relationships in the chado tables
  961. // through foreign key relationships. The tripal
  962. // modules that correspond to these chado "modules" don't
  963. // need to be installed for the taxonomy to work.
  964. foreach($vocabularies as $vocab){
  965. if($vocab->name == 'Feature Type'){
  966. $ft_vid = $vocab->vid;
  967. }
  968. if($vocab->name == 'Organism'){
  969. $op_vid = $vocab->vid;
  970. }
  971. if($vocab->name == 'Library'){
  972. $lb_vid = $vocab->vid;
  973. }
  974. if($vocab->name == 'Analysis'){
  975. $an_vid = $vocab->vid;
  976. }
  977. }
  978. if(!$ft_vid){
  979. $form_state = array();
  980. $values = array(
  981. 'name' => t('Feature Type'),
  982. 'nodes' => array('chado_feature' => 'chado_feature'),
  983. 'description' => t('The feature type (or SO cvterm for this feature).'),
  984. 'help' => t('Select the term that matches the feature '),
  985. 'tags' => 0,
  986. 'hierarchy' => 1,
  987. 'relations' => 1,
  988. 'multiple' => 0,
  989. 'required' => 0,
  990. 'weight' => 1,
  991. );
  992. drupal_execute('taxonomy_form_vocabulary', $form_state,$values);
  993. drupal_execute('taxonomy_form_vocabulary', $form_state);
  994. }
  995. if(!$op_vid){
  996. $form_state = array();
  997. $values = array(
  998. 'name' => t('Organism'),
  999. 'nodes' => array('chado_feature' => 'chado_feature'),
  1000. 'description' => t('The organism to which this feature belongs.'),
  1001. 'help' => t('Select the term that matches the feature '),
  1002. 'tags' => 0,
  1003. 'hierarchy' => 1,
  1004. 'relations' => 1,
  1005. 'multiple' => 0,
  1006. 'required' => 0,
  1007. 'weight' => 2,
  1008. );
  1009. drupal_execute('taxonomy_form_vocabulary', $form_state,$values);
  1010. drupal_execute('taxonomy_form_vocabulary', $form_state);
  1011. }
  1012. if(!$lb_vid){
  1013. $form_state = array();
  1014. $values = array(
  1015. 'name' => t('Library'),
  1016. 'nodes' => array('chado_feature' => 'chado_feature'),
  1017. 'description' => t('Chado features associated with a library are assigned the term associated with the library'),
  1018. 'help' => t('Select the term that matches the feature '),
  1019. 'tags' => 0,
  1020. 'hierarchy' => 1,
  1021. 'relations' => 1,
  1022. 'multiple' => 0,
  1023. 'required' => 0,
  1024. 'weight' => 3,
  1025. );
  1026. drupal_execute('taxonomy_form_vocabulary', $form_state, $values);
  1027. drupal_execute('taxonomy_form_vocabulary', $form_state);
  1028. }
  1029. if(!$an_vid){
  1030. $form_state = array();
  1031. $values = array(
  1032. 'name' => t('Analysis'),
  1033. 'nodes' => array('chado_feature' => 'chado_feature'),
  1034. 'description' => t('Any analysis to which this feature belongs.'),
  1035. 'help' => t('Select the term that matches the feature '),
  1036. 'tags' => 0,
  1037. 'hierarchy' => 1,
  1038. 'relations' => 1,
  1039. 'multiple' => 1,
  1040. 'required' => 0,
  1041. 'weight' => 4,
  1042. );
  1043. drupal_execute('taxonomy_form_vocabulary', $form_state,$values);
  1044. drupal_execute('taxonomy_form_vocabulary', $form_state);
  1045. }
  1046. }
  1047. /************************************************************************
  1048. *
  1049. */
  1050. function tripal_feature_del_vocabulary(){
  1051. //include the file containing the required functions for adding taxonomy vocabs
  1052. module_load_include('inc', 'taxonomy', 'taxonomy.admin');
  1053. // get the vocabularies
  1054. $vocabularies = taxonomy_get_vocabularies();
  1055. // These taxonomic terms are hard coded because we
  1056. // know we have these relationships in the chado tables
  1057. // through foreign key relationships. The tripal
  1058. // modules that correspond to these chado "modules" don't
  1059. // need to be installed for the taxonomy to work.
  1060. foreach($vocabularies as $vocab){
  1061. if($vocab->name == 'Feature Type'){
  1062. taxonomy_del_vocabulary($vocab->vid);
  1063. }
  1064. if($vocab->name == 'Organism'){
  1065. taxonomy_del_vocabulary($vocab->vid);
  1066. }
  1067. if($vocab->name == 'Library'){
  1068. taxonomy_del_vocabulary($vocab->vid);
  1069. }
  1070. if($vocab->name == 'Analysis'){
  1071. taxonomy_del_vocabulary($vocab->vid);
  1072. }
  1073. }
  1074. }
  1075. /************************************************************************
  1076. *
  1077. */
  1078. function tripal_features_set_taxonomy($max_sync = 0,$job_id = NULL){
  1079. // make sure our vocabularies are cleaned and reset before proceeding
  1080. tripal_feature_del_vocabulary();
  1081. tripal_feature_set_vocabulary();
  1082. // iterate through all drupal feature nodes and set the taxonomy
  1083. $results = db_query("SELECT * FROM {chado_feature}");
  1084. $nsql = "SELECT * FROM {node} ".
  1085. "WHERE nid = %d";
  1086. $i = 0;
  1087. // load into ids array
  1088. $count = 0;
  1089. $chado_features = array();
  1090. while($chado_feature = db_fetch_object($results)){
  1091. $chado_features[$count] = $chado_feature;
  1092. $count++;
  1093. }
  1094. // Iterate through features that need to be synced
  1095. $interval = intval($count * 0.01);
  1096. foreach($chado_features as $chado_feature){
  1097. // update the job status every 1% features
  1098. if($job_id and $i % $interval == 0){
  1099. tripal_job_set_progress($job_id,intval(($i/$count)*100));
  1100. }
  1101. $node = db_fetch_object(db_query($nsql,$chado_feature->nid));
  1102. tripal_feature_set_taxonomy($node,$chado_feature->feature_id);
  1103. $i++;
  1104. }
  1105. }
  1106. /************************************************************************
  1107. *
  1108. */
  1109. function tripal_feature_set_taxonomy ($node,$feature_id){
  1110. // iterate through the taxonomy classes that have been
  1111. // selected by the admin user and make sure we only set those
  1112. $tax_classes = variable_get('tax_classes', '');
  1113. $do_ft = 0;
  1114. $do_op = 0;
  1115. $do_lb = 0;
  1116. $do_an = 0;
  1117. foreach($tax_classes as $class){
  1118. if(strcmp($class ,'organism')==0){
  1119. $do_op = 1;
  1120. }
  1121. if(strcmp($class,'feature_type')==0){
  1122. $do_ft = 1;
  1123. }
  1124. if(strcmp($class,'library')==0){
  1125. $do_lb = 1;
  1126. }
  1127. if(strcmp($class,'analysis')==0){
  1128. $do_an = 1;
  1129. }
  1130. }
  1131. // get the list of vocabularies and find our two vocabularies of interest
  1132. $vocabularies = taxonomy_get_vocabularies();
  1133. $ft_vid = NULL;
  1134. $op_vid = NULL;
  1135. $lb_vid = NULL;
  1136. $an_vid = NULL;
  1137. foreach($vocabularies as $vocab){
  1138. if($vocab->name == 'Feature Type'){
  1139. $ft_vid = $vocab->vid;
  1140. }
  1141. if($vocab->name == 'Organism'){
  1142. $op_vid = $vocab->vid;
  1143. }
  1144. if($vocab->name == 'Library'){
  1145. $lb_vid = $vocab->vid;
  1146. }
  1147. if($vocab->name == 'Analysis'){
  1148. $an_vid = $vocab->vid;
  1149. }
  1150. }
  1151. // get the cvterm and the organism for this feature
  1152. $sql = "SELECT CVT.name AS cvname, O.genus, O.species ".
  1153. "FROM {CVTerm} CVT ".
  1154. " INNER JOIN Feature F on F.type_id = CVT.cvterm_id ".
  1155. " INNER JOIN Organism O ON F.organism_id = O.organism_id ".
  1156. "WHERE F.feature_id = $feature_id";
  1157. $previous_db = tripal_db_set_active('chado'); // use chado database
  1158. $feature = db_fetch_object(db_query($sql));
  1159. tripal_db_set_active($previous_db); // now use drupal database
  1160. // Set the feature type for this feature
  1161. if($do_ft && $ft_vid){
  1162. $tags["$ft_vid"] = "$feature->cvname";
  1163. }
  1164. // Set the organism for this feature type
  1165. if($do_op && $op_vid){
  1166. $tags["$op_vid"] = "$feature->genus $feature->species";
  1167. }
  1168. // get the library that this feature may belong to and add it as taxonomy
  1169. if($do_lb && $lb_vid){
  1170. $sql = "SELECT L.name ".
  1171. "FROM {Library} L ".
  1172. " INNER JOIN Library_feature LF ON LF.library_id = L.library_id ".
  1173. "WHERE LF.feature_id = %d ";
  1174. $previous_db = tripal_db_set_active('chado'); // use chado database
  1175. $library = db_fetch_object(db_query($sql,$feature_id));
  1176. tripal_db_set_active($previous_db); // now use drupal database
  1177. $tags["$lb_vid"] = "$library->name";
  1178. }
  1179. // now add the taxonomy to the node
  1180. $terms['tags'] = $tags;
  1181. taxonomy_node_save($node,$terms);
  1182. // print "Setting $node->name: " . implode(", ",$tags) . "\n";
  1183. // get the analysis that this feature may belong to and add it as taxonomy
  1184. // We'll add each one individually since there may be more than one analysis
  1185. if($do_an && $an_vid){
  1186. $sql = "SELECT A.name ".
  1187. "FROM {Analysis} A ".
  1188. " INNER JOIN Analysisfeature AF ON AF.analysis_id = A.analysis_id ".
  1189. "WHERE AF.feature_id = $feature_id ";
  1190. $results = db_query($sql);
  1191. $previous_db = tripal_db_set_active('chado'); // use chado database
  1192. $analysis_terms = array();
  1193. while($analysis=db_fetch_object($results)){
  1194. $tags2["$an_vid"] = "$analysis->name";
  1195. $terms['tags'] = $tags2;
  1196. taxonomy_node_save($node,$terms);
  1197. }
  1198. tripal_db_set_active($previous_db); // now use drupal database
  1199. }
  1200. }
  1201. /************************************************************************
  1202. *
  1203. */
  1204. function tripal_features_cleanup($dummy = NULL, $job_id = NULL) {
  1205. // build the SQL statments needed to check if nodes point to valid features
  1206. $dsql = "SELECT * FROM {node} WHERE type = 'chado_feature' order by nid";
  1207. $nsql = "SELECT * FROM {node} WHERE nid = %d";
  1208. $csql = "SELECT * FROM {chado_feature} where nid = %d ";
  1209. $cfsql= "SELECT * FROM {chado_feature}";
  1210. $tsql = "SELECT * FROM {feature} F ".
  1211. " INNER JOIN CVTerm CVT ON F.type_id = CVT.cvterm_id ".
  1212. "WHERE feature_id = %d AND (";
  1213. $supported_ftypes = split("[ \n]",variable_get('chado_feature_types','EST contig'));
  1214. foreach($supported_ftypes as $ftype){
  1215. $tsql .= " CVT.name = '$ftype' OR ";
  1216. }
  1217. $tsql .= " 0=1) "; // add a 0=1 just as a filler so we don't have to remove a trailing 'OR'
  1218. // load into nodes array
  1219. $results = db_query($dsql);
  1220. $count = 0;
  1221. $nodes = array();
  1222. while($node = db_fetch_object($results)){
  1223. $nodes[$count] = $node;
  1224. $count++;
  1225. }
  1226. // load the chado_features into an array
  1227. $results = db_query($cfsql);
  1228. $cnodes = array();
  1229. while($node = db_fetch_object($results)){
  1230. $cnodes[$count] = $node;
  1231. $count++;
  1232. }
  1233. $interval = intval($count * 0.01);
  1234. // iterate through all of the chado_feature nodes and delete those that aren't valid
  1235. foreach($nodes as $nid){
  1236. // update the job status every 1% features
  1237. if($job_id and $i % $interval == 0){
  1238. tripal_job_set_progress($job_id,intval(($i/$count)*100));
  1239. }
  1240. // first check to see if the node has a corresponding entry
  1241. // in the chado_feature table. If not then delete the node.
  1242. $feature = db_fetch_object(db_query($csql,$nid->nid));
  1243. if(!$feature){
  1244. node_delete($nid->nid);
  1245. $message = "Missing in chado_feature table.... DELETING: $nid->nid\n";
  1246. watchdog('tripal_feature',$message,array(),WATCHDOG_WARNING);
  1247. continue;
  1248. }
  1249. // second check to see if the node is for a feature of an allowed type.
  1250. // if not, then delete the node. This check will also take care of the
  1251. // case when a node exists and an entry in the chado_feature table exists
  1252. // but no feature with a matching feature_id exists
  1253. $previous_db = tripal_db_set_active('chado'); // use chado database
  1254. $ftype = db_fetch_object(db_query($tsql,$feature->feature_id));
  1255. tripal_db_set_active($previous_db); // now use drupal database
  1256. if(!$ftype){
  1257. node_delete($nid->nid);
  1258. db_query("DELETE FROM {chado_feature} WHERE feature_id = $feature->feature_id");
  1259. $message = "Node of the wrong feature type.... DELETING: $nid->nid\n";
  1260. watchdog('tripal_feature',$message,array(),WATCHDOG_WARNING);
  1261. }
  1262. $i++;
  1263. }
  1264. // iterate through all of the chado_feature nodes and delete those that aren't valid
  1265. foreach($cnodes as $nid){
  1266. // update the job status every 1% features
  1267. if($job_id and $i % $interval == 0){
  1268. tripal_job_set_progress($job_id,intval(($i/$count)*100));
  1269. }
  1270. $node = db_fetch_object(db_query($nsql,$nid->nid));
  1271. if(!$node){
  1272. db_query("DELETE FROM {chado_feature} WHERE nid = $nid->nid");
  1273. $message = "chado_feature missing node.... DELETING: $nid->nid\n";
  1274. watchdog('tripal_feature',$message,array(),WATCHDOG_WARNING);
  1275. }
  1276. $i++;
  1277. }
  1278. return '';
  1279. }
  1280. /************************************************************************
  1281. *
  1282. */
  1283. function tripal_feature_bulkload(){
  1284. return drupal_get_form('tripal_feature_load_fasta_form');
  1285. }
  1286. /************************************************************************
  1287. *
  1288. */
  1289. function tripal_feature_load_fasta_form (&$form_state = NULL){
  1290. // get the list of organisms
  1291. $sql = "SELECT * FROM {Organism} ORDER BY genus,species";
  1292. $previous_db = tripal_db_set_active('chado'); // use chado database
  1293. $org_rset = db_query($sql);
  1294. tripal_db_set_active($previous_db); // now use drupal database
  1295. $organisms = array();
  1296. $organisms[''] = '';
  1297. while($organism = db_fetch_object($org_rset)){
  1298. $organisms[$organism->organism_id] = "$organism->genus $organism->species ($organism->common_name)";
  1299. }
  1300. // get the list of supported feature types
  1301. $ftypes = array();
  1302. $ftypes[''] = '';
  1303. $supported_ftypes = split("[ \n]",variable_get('chado_feature_feature_types','EST contig'));
  1304. foreach($supported_ftypes as $ftype){
  1305. $ftypes["$ftype"] = $ftype;
  1306. }
  1307. // get the list of libraries
  1308. // TODO !!!! Use Ajax to filter this automatically based on the organism
  1309. // selected by the user. This will prevent mistakes from user input.
  1310. $sql = "SELECT * FROM {Library} L ".
  1311. " INNER JOIN Organism O ON L.organism_id = O.organism_id ".
  1312. "ORDER BY L.name";
  1313. $previous_db = tripal_db_set_active('chado'); // use chado database
  1314. $lib_rset = db_query($sql);
  1315. tripal_db_set_active($previous_db); // now use drupal database
  1316. $libraries = array();
  1317. $libraries[''] = '';
  1318. while($library = db_fetch_object($lib_rset)){
  1319. $libraries[$library->library_id] = "$library->name ($library->genus $library->species)";
  1320. }
  1321. $form['#attributes']['enctype'] = 'multipart/form-data';
  1322. $form['organism'] = array (
  1323. '#title' => t('Organism'),
  1324. '#type' => t('select'),
  1325. '#description' => t("Choose the organism with which these sequences are associated "),
  1326. '#required' => TRUE,
  1327. '#default_vaule' => '',
  1328. '#options' => $organisms,
  1329. '#weight' => 1,
  1330. );
  1331. $form['library'] = array (
  1332. '#title' => t('Library'),
  1333. '#type' => t('select'),
  1334. '#description' => t("Choose the library with from which these sequences are derived. Leave blank if not applicable."),
  1335. '#required' => FALSE,
  1336. '#default_vaule' => '',
  1337. '#options' => $libraries,
  1338. '#weight' => 2,
  1339. );
  1340. $form['ftype'] = array (
  1341. '#title' => t('Feature Type'),
  1342. '#type' => t('select'),
  1343. '#description' => t("Choose the category of sequences you are uploading. All sequences in the FASTA file will be imported as this type"),
  1344. '#required' => TRUE,
  1345. '#default_vaule' => '',
  1346. '#options' => $ftypes,
  1347. '#weight' => 3,
  1348. );
  1349. $form['fasta_file'] = array(
  1350. '#type' => t('file'),
  1351. '#title' => t('Fasta File'),
  1352. '#description' => t('Upload a FASTA file of sequences. The definition line should contain only the feature name. All other annotations should be removed. The file must not be larger than ' . file_upload_max_size() . ' bytes'),
  1353. '#weight' => 4,
  1354. );
  1355. $form['upload'] = array(
  1356. '#type' => 'submit',
  1357. '#value' => t('Upload File'),
  1358. '#weight' => 2,
  1359. '#executes_submit_callback' => TRUE,
  1360. '#weight' => 5,
  1361. );
  1362. return $form;
  1363. }
  1364. /************************************************************************
  1365. *
  1366. */
  1367. function tripal_feature_load_fasta_form_validate($form, &$form_state){
  1368. // TODO !!! check that the fasta file is valid
  1369. global $user;
  1370. // we need a path within the drupal installation to temporarily use as the destination
  1371. // after we upload, we'll move the file to analysis directory
  1372. $upload_url = file_directory_path() . "/chado_feature_bulk_upload/$user->uid";
  1373. // create the download directory. We do it this way rather than the
  1374. // file_check_directory because we don't want a drupal message presented
  1375. // the user when the directory is created.
  1376. if (!is_dir($upload_url)) {
  1377. mkdir($upload_url,0775,TRUE);
  1378. }
  1379. // upload the file and copy it to the proper location
  1380. $validators = array(); // we don't have any validators
  1381. if($file = file_save_upload('fasta_file',$validators,$upload_url)){
  1382. drupal_set_message("File $file->name uploaded succesfully");
  1383. } else {
  1384. form_set_error('fasta_file',t('Upload Failed'));
  1385. }
  1386. }
  1387. /************************************************************************
  1388. *
  1389. */
  1390. function tripal_feature_load_fasta_form_submit($form, &$form_state){
  1391. global $user;
  1392. // add a job to be executed
  1393. tripal_add_job ($job_name,$type,$callback,$uid);
  1394. }
  1395. /************************************************************************
  1396. *
  1397. */
  1398. function tripal_feature_return_fasta($feature,$desc){
  1399. $fasta = ">" . variable_get('chado_feature_accession_prefix','ID') . "$feature->feature_id|$feature->name";
  1400. $fasta .= " $desc\n";
  1401. $fasta .= wordwrap($feature->residues, 50, "\n", true);
  1402. $fasta .= "\n\n";
  1403. return $fasta;
  1404. }