Browse Source

Fixed multiple things including the following
1. Properties not showing on the feature page
2. Properties not showing on the library page
3. OBO loader would crash when the name of a term was changed but ID and dbxref were unchaged
4. Added a mechanism for bulk delete of features
5. Changed the way features are synced by allowing users to specify an organism and feature types each time
6. Fixed the GFF loader to load any other attributes in the GFF file as featureprops in the featureprop table
7. Fixed some divide by zero errors when indexing and syncing features
8. Created some API functions for creating db's, cv's, cvterms and dbxrefs

spficklin 13 years ago
parent
commit
95e1b150fc

+ 4 - 2
theme_tripal/tripal_feature/tripal_feature_properties.tpl.php

@@ -23,11 +23,13 @@
 
 <?php
  //uncomment this line to see a full listing of the fields avail. to $node
- //print '<pre>'.print_r($node,TRUE).'</pre>';
+ dpm($node);
 ?>
 
 <?php
-  $properties = $node->feature->featureprop;
+  $feature = $node->feature;
+  $feature = tripal_core_expand_chado_vars($feature,'table','featureprop');
+  $properties = $feature->featureprop;
   if (!$properties) {
     $properties = array();
   } elseif (!is_array($properties)) { 

+ 5 - 1
theme_tripal/tripal_library/tripal_library_properties.tpl.php

@@ -26,8 +26,12 @@
  //print '<pre>'.print_r($node,TRUE).'</pre>';
 ?>
 
+
 <?php
-  $properties = $node->library->libraryprop;
+  $library = $node->library;
+  $library = tripal_core_expand_chado_vars($library,'table','libraryprop');
+  $properties = $library->libraryprop;
+
   if (!$properties) {
     $properties = array();
   } elseif (!is_array($properties)) { 

+ 33 - 22
tripal_core/tripal_core.api.inc

@@ -124,7 +124,7 @@ function tripal_core_chado_insert($table,$values){
          if (sizeof($results) > 1) {
            watchdog('tripal_core', 'tripal_core_chado_insert: Too many records match the criteria supplied for !foreign_key foreign key constraint (!criteria)', array('!foreign_key' => $field, '!criteria' => print_r($value,TRUE)), WATCHDOG_ERROR);         
          } elseif (sizeof($results) < 1) {
-           watchdog('tripal_core', 'tripal_core_chado_insert: no record matches criteria supplied for !foreign_key foreign key constraint (!criteria)', array('!foreign_key' => $field, '!criteria' => print_r($value,TRUE)), WATCHDOG_ERROR);
+           //watchdog('tripal_core', 'tripal_core_chado_insert: no record matches criteria supplied for !foreign_key foreign key constraint (!criteria)', array('!foreign_key' => $field, '!criteria' => print_r($value,TRUE)), WATCHDOG_ERROR);
          } else {
            $insert_values[$field] = $results[0];
          }
@@ -272,13 +272,19 @@ function tripal_core_chado_delete($table,$match){
    // get the values needed for matching in the SQL statement
    foreach ($match as $field => $value){
       if(is_array($value)){
-         $results = tripal_core_chado_get_foreign_key($table_desc,$field,$value);
-         if (sizeof($results) > 1) {
-           watchdog('tripal_core', 'tripal_core_chado_delete: When trying to find record to delete, too many records match the criteria supplied for !foreign_key foreign key constraint (!criteria)', array('!foreign_key' => $field, '!criteria' => print_r($value,TRUE)), WATCHDOG_ERROR);         
-         } elseif (sizeof($results) < 1) {
-           watchdog('tripal_core', 'tripal_core_chado_delete: When trying to find record to delete, no record matches criteria supplied for !foreign_key foreign key constraint (!criteria)', array('!foreign_key' => $field, '!criteria' => print_r($value,TRUE)), WATCHDOG_ERROR);
+         // if the user has specified an array of values to delete rather than
+         // FK relationships the keep those in our match 
+         if(array_values($value) === $value){
+            $delete_matches[$field] = $value;
          } else {
-           $delete_matches[$field] = $results[0];
+            $results = tripal_core_chado_get_foreign_key($table_desc,$field,$value);
+            if (sizeof($results) > 1) {
+              watchdog('tripal_core', 'tripal_core_chado_delete: When trying to find record to delete, too many records match the criteria supplied for !foreign_key foreign key constraint (!criteria)', array('!foreign_key' => $field, '!criteria' => print_r($value,TRUE)), WATCHDOG_ERROR);         
+            } elseif (sizeof($results) < 1) {
+              //watchdog('tripal_core', 'tripal_core_chado_delete: When trying to find record to delete, no record matches criteria supplied for !foreign_key foreign key constraint (!criteria)', array('!foreign_key' => $field, '!criteria' => print_r($value,TRUE)), WATCHDOG_ERROR);
+            } else {
+              $delete_matches[$field] = $results[0];
+            }
          }
       }
       else {
@@ -289,13 +295,18 @@ function tripal_core_chado_delete($table,$match){
    $sql = "DELETE FROM {$table} WHERE ";
    $dargs = array();
    foreach($delete_matches as $field => $value){
-      if(strcmp($fields[$field]['type'],'serial')==0 or 
-         strcmp($fields[$field]['type'],'int')==0){
-         $sql .= " $field = %d AND ";
+      if (count($value) > 1) {
+         $sql .= "$field IN (".db_placeholders($value,'varchar').") AND ";
+         foreach ($value as $v) { $dargs[] = $v; }
       } else {
-         $sql .= " $field = '%s' AND ";
+         if(strcmp($fields[$field]['type'],'serial')==0 or 
+            strcmp($fields[$field]['type'],'int')==0){
+            $sql .= " $field = %d AND ";
+         } else {
+            $sql .= " $field = '%s' AND ";
+         }
+         array_push($dargs,$value);
       }
-      array_push($dargs,$value);
    }
    $sql = substr($sql,0,-4);  // get rid of the trailing 'AND'
    
@@ -384,7 +395,7 @@ function tripal_core_chado_update($table,$match,$values){
          if (sizeof($results) > 1) {
            watchdog('tripal_core', 'tripal_core_chado_update: When trying to find record to update, too many records match the criteria supplied for !foreign_key foreign key constraint (!criteria)', array('!foreign_key' => $field, '!criteria' => print_r($value,TRUE)), WATCHDOG_ERROR);         
          } elseif (sizeof($results) < 1) {
-           watchdog('tripal_core', 'tripal_core_chado_update: When trying to find record to update, no record matches criteria supplied for !foreign_key foreign key constraint (!criteria)', array('!foreign_key' => $field, '!criteria' => print_r($value,TRUE)), WATCHDOG_ERROR);
+           //watchdog('tripal_core', 'tripal_core_chado_update: When trying to find record to update, no record matches criteria supplied for !foreign_key foreign key constraint (!criteria)', array('!foreign_key' => $field, '!criteria' => print_r($value,TRUE)), WATCHDOG_ERROR);
          } else {
            $update_matches[$field] = $results[0];
          }
@@ -401,7 +412,7 @@ function tripal_core_chado_update($table,$match,$values){
          if (sizeof($results) > 1) {
            watchdog('tripal_core', 'tripal_core_chado_update: When trying to find update values, too many records match the criteria supplied for !foreign_key foreign key constraint (!criteria)', array('!foreign_key' => $field, '!criteria' => print_r($value,TRUE)), WATCHDOG_ERROR);         
          } elseif (sizeof($results) < 1) {
-           watchdog('tripal_core', 'tripal_core_chado_update: When trying to find update values, no record matches criteria supplied for !foreign_key foreign key constraint (!criteria)', array('!foreign_key' => $field, '!criteria' => print_r($value,TRUE)), WATCHDOG_ERROR);
+           //watchdog('tripal_core', 'tripal_core_chado_update: When trying to find update values, no record matches criteria supplied for !foreign_key foreign key constraint (!criteria)', array('!foreign_key' => $field, '!criteria' => print_r($value,TRUE)), WATCHDOG_ERROR);
          } else {
            $update_values[$field] = $results[0];
          }         
@@ -560,14 +571,14 @@ function tripal_core_chado_select($table,$columns,$values,$options = null){
             if (sizeof($results) < 1) {
               // foreign key records are required
               // thus if none matched then return false and alert the admin through watchdog
-              watchdog('tripal_core', 
-               'tripal_core_chado_select: no record in the table referenced by the foreign key (!field)   exists. tripal_core_chado_select table=!table, columns=!columns, values=!values', 
-               array('!table' => $table, 
-                 '!columns' => '<pre>' . print_r($columns, TRUE) . '</pre>', 
-                 '!values' => '<pre>' . print_r($values, TRUE) . '</pre>',
-                 '!field' => $field,
-               ), 
-               WATCHDOG_WARNING);
+              //watchdog('tripal_core', 
+              // 'tripal_core_chado_select: no record in the table referenced by the foreign key (!field)   exists. tripal_core_chado_select table=!table, columns=!columns, values=!values', 
+              // array('!table' => $table, 
+              //   '!columns' => '<pre>' . print_r($columns, TRUE) . '</pre>', 
+              //   '!values' => '<pre>' . print_r($values, TRUE) . '</pre>',
+              //   '!field' => $field,
+              // ), 
+              // WATCHDOG_WARNING);
               return false;           
             } else {
               $where[$field] = $results;

+ 9 - 0
tripal_core/tripal_core.module

@@ -274,3 +274,12 @@ function tripal_core_job_describe_args($callback,$args){
    }
    return $new_args;
 }
+
+// this is just a wrapper for backwards compatibility with a naming mistake.
+// it can go away in the future as it only is useful for jobs created by v0.3b 
+function tripal_core_load_gff3($gff_file, $organism_id,$analysis_id,$add_only =0, 
+   $update = 0, $refresh = 0, $remove = 0, $job = NULL)
+{
+   tripal_feature_load_gff3($gff_file, $organism_id,$analysis_id,$add_only, 
+      $update, $refresh, $remove, $job);
+}

+ 235 - 187
tripal_cv/obo_loader.php

@@ -16,7 +16,7 @@ function tripal_cv_load_obo_v1_2_id($obo_id,$jobid = NULL){
    $obo = db_fetch_object(db_query($sql,$obo_id));
 
    // if the reference is for a remote URL then run the URL processing function
-   if(preg_match("/^http:\/\/",$obo->path) or preg_match("/^ftp:\/\/",$obo->path)){
+   if(preg_match("/^http:\/\//",$obo->path) or preg_match("/^ftp:\/\//",$obo->path)){
       tripal_cv_load_obo_v1_2_url($obo->name,$obo->path,$jobid,0);
    } 
    // if the reference is for a local file then run the file processing function
@@ -29,7 +29,11 @@ function tripal_cv_load_obo_v1_2_id($obo_id,$jobid = NULL){
       // if not local to Drupal, the file must be someplace else, just use
       // the full path provided
       else{
-         tripal_cv_load_obo_v1_2_file($obo->name,$obo->path,$jobid,0);
+         if(file_exists($obo->path)){
+            tripal_cv_load_obo_v1_2_file($obo->name,$obo->path,$jobid,0);
+         } else {
+            print "ERROR: counld not find OBO file: '$obo->path'\n";
+         }
       }
    }  
 }
@@ -58,7 +62,7 @@ function tripal_cv_load_obo_v1_2_url($obo_name,$url,$jobid = NULL,$is_new = 1){
 
    // first download the OBO
    $temp = tempnam(sys_get_temp_dir(),'obo_');
-   print "Opening URL $url\n";
+   print "Downloading URL $url, saving to $temp\n";
    $url_fh = fopen($url,"r");
    $obo_fh = fopen($temp,"w");
    while(!feof($url_fh)){
@@ -199,7 +203,7 @@ function tripal_cv_obo_process_terms($terms,$defaultcv,$obo,$jobid=null,&$newcvs
 function tripal_cv_obo_process_term($term,$defaultcv,$obo,$is_relationship=0,&$newcvs){
 
    // add the cvterm
-   $cvterm = tripal_cv_obo_add_cv_term($term,$defaultcv,$is_relationship,1);     
+   $cvterm = tripal_cv_obo_add_cvterm($term,$defaultcv,$is_relationship,1);     
    if(!$cvterm){ 
       tripal_cv_obo_quiterror("Cannot add the term " . $term['id'][0]);
    }
@@ -266,13 +270,27 @@ function tripal_cv_obo_process_term($term,$defaultcv,$obo,$is_relationship=0,&$n
       }
    }    
    // add any other external dbxrefs
-   if(isset($term['xref']) or isset($term['xref_analog']) or isset($term['xref_unk'])){
+   if(isset($term['xref'])){
       foreach($term['xref'] as $xref){
          if(!tripal_cv_obo_add_cvterm_dbxref($cvterm,$xref)){
             tripal_cv_obo_quiterror("Cannot add/update cvterm database reference (dbxref).");
          }
       }
    }
+   if(isset($term['xref_analog'])){
+      foreach($term['xref_analog'] as $xref){
+         if(!tripal_cv_obo_add_cvterm_dbxref($cvterm,$xref)){
+            tripal_cv_obo_quiterror("Cannot add/update cvterm database reference (dbxref).");
+         }
+      }
+   }
+   if(isset($term['xref_unk'])){
+      foreach($term['xref_unk'] as $xref){
+         if(!tripal_cv_obo_add_cvterm_dbxref($cvterm,$xref)){
+            tripal_cv_obo_quiterror("Cannot add/update cvterm database reference (dbxref).");
+         }
+      }
+   }
 
    // add is_a relationships for this cvterm
    if(isset($term['is_a'])){
@@ -358,53 +376,7 @@ function tripal_cv_obo_add_cv($name,$comment){
    }
    return $cv;
 }
-/**
-*
-* @ingroup tripal_obo_loader
-*/
-function tripal_cv_obo_add_cvterm_prop($cvterm,$property,$value,$rank){
-
-   // make sure the 'cvterm_property_type' CV exists
-   $cv = tripal_cv_obo_add_cv('cvterm_property_type','');
-   if(!$cv){ 
-      tripal_cv_obo_quiterror("Cannot add/find cvterm_property_type cvterm");
-   }
-
-   // get the property type cvterm.  If it doesn't exist then we want to add it
-   $sql = "
-        SELECT * 
-        FROM {cvterm} CVT INNER JOIN {cv} CV on CVT.cv_id = CV.cv_id
-        WHERE CVT.name = '%s' and CV.name = '%s'
-   ";
-   $cvproptype = db_fetch_object(db_query($sql,$property,'cvterm_property_type'));
-   if(!$cvproptype){
-      $term = array(
-         'name' => array($property),
-         'id' => array("internal:$property"),
-         'definition' => array(''),
-         'is_obsolete' => array(0),
-      );
-      $cvproptype = tripal_cv_obo_add_cv_term($term,$cv,0,0);
-      if(!$cvproptype){  
-         tripal_cv_obo_quiterror("Cannot add cvterm property: internal:$property");
-      }
-   }
-
-
-   // remove any properties that currently exist for this term.  We'll reset them
-   if($rank == 0){
-      $sql = "DELETE FROM {cvtermprop} WHERE cvterm_id = %d";
-      db_query($sql,$cvterm->cvterm_id);
-   }
 
-   // now add the property
-   $sql = "INSERT INTO {cvtermprop} (cvterm_id,type_id,value,rank) ".
-          "VALUES (%d, %d, '%s',%d)";
-   if(!db_query($sql,$cvterm->cvterm_id,$cvproptype->cvterm_id,$value,$rank)){
-      tripal_cv_obo_quiterror("Could not add property $property for term\n");
-   }
-   return 1;
-}
 /**
 *
 * @ingroup tripal_obo_loader
@@ -418,7 +390,7 @@ function tripal_cv_obo_add_relationship($cvterm,$defaultcv,$obo,$rel,$objname,$o
       'definition' => array(''),
       'is_obsolete' => array(0),
    );
-   $relcvterm = tripal_cv_obo_add_cv_term($term,$defaultcv,1,0);
+   $relcvterm = tripal_cv_obo_add_cvterm($term,$defaultcv,1,0);
    if(!$relcvterm){
       tripal_cv_obo_quiterror("Cannot find or insert the relationship term: $rel\n");
    }
@@ -428,7 +400,7 @@ function tripal_cv_obo_add_relationship($cvterm,$defaultcv,$obo,$rel,$objname,$o
    if(!$objterm) { 
       tripal_cv_obo_quiterror("Could not find object term $objname\n"); 
    }
-   $objcvterm = tripal_cv_obo_add_cv_term($objterm,$defaultcv,$object_is_relationship,1);
+   $objcvterm = tripal_cv_obo_add_cvterm($objterm,$defaultcv,$object_is_relationship,1);
    if(!$objcvterm){ 
       tripal_cv_obo_quiterror("Cannot add/find cvterm");
    }
@@ -500,7 +472,7 @@ function tripal_cv_obo_add_synonyms($term,$cvterm){
                'definition' => array(''),
                'is_obsolete' => array(0),
             );
-            $syntype = tripal_cv_obo_add_cv_term($term,$syncv,0,1);
+            $syntype = tripal_cv_obo_add_cvterm($term,$syncv,0,1);
             if(!$syntype){
                tripal_cv_obo_quiterror("Cannot add synonym type: internal:$type");
             }
@@ -510,9 +482,9 @@ function tripal_cv_obo_add_synonyms($term,$cvterm){
          $sql = "
             SELECT * 
             FROM {cvtermsynonym} 
-            WHERE cvterm_id = %d and synonym = '%s' and type_id = %d
+            WHERE cvterm_id = %d and synonym = '%s'
          ";
-         $syn = db_fetch_object(db_query($sql,$cvterm->cvterm_id,$def,$syntype->cvterm_id));
+         $syn = db_fetch_object(db_query($sql,$cvterm->cvterm_id,$def));
          if(!$syn){
             $sql = "INSERT INTO {cvtermsynonym} (cvterm_id,synonym,type_id)
                     VALUES(%d,'%s',%d)";
@@ -537,11 +509,178 @@ function tripal_cv_obo_add_synonyms($term,$cvterm){
    }
    return 1;
 }
+
+/**
+*
+* @ingroup tripal_obo_loader
+*/
+function tripal_cv_obo_parse($obo_file,&$obo,&$header){
+   $i = 0;
+   $in_header = 1;
+   $stanza = array();
+
+   // iterate through the lines in the OBO file and parse the stanzas
+   $fh = fopen($obo_file,'r');
+   while($line = fgets($fh)) {
+      $i++;
+
+      // remove newlines
+      $line = rtrim($line);  
+      // skip empty lines
+      if(strcmp($line,'')==0) { continue; }
+      //remove comments from end of lines
+      $line = preg_replace('/^(.*?)\!.*$/','\1',$line);  // TODO: if the explamation is escaped
+
+      if(preg_match('/^\s*\[/',$line)){  // at the first stanza we're out of header
+         $in_header = 0;
+         // load the stanza we just finished reading
+         if(sizeof($stanza) > 0){
+            if(!isset($obo[$type])){
+               $obo[$type] = array();
+            }
+            if(!isset($obo[$type][$stanza['id'][0]])){
+               $obo[$type][$stanza['id'][0]] = $stanza;
+            } else {
+               array_merge($obo[$type][$stanza['id'][0]],$stanza);
+            }
+         } 
+         // get the stanza type:  Term, Typedef or Instance
+         $type = preg_replace('/^\s*\[\s*(.+?)\s*\]\s*$/','\1',$line);
+
+         // start fresh with a new array
+         $stanza = array();
+         continue;
+      }
+      // break apart the line into the tag and value but ignore any escaped colons
+      preg_replace("/\\:/","|-|-|",$line); // temporarily replace escaped colons
+      $pair = explode(":",$line,2);
+      $tag = $pair[0];
+      $value = ltrim(rtrim($pair[1]));// remove surrounding spaces
+      $tag = preg_replace("/\|-\|-\|/","\:",$tag); // return the escaped colon
+      $value = preg_replace("/\|-\|-\|/","\:",$value);
+      if($in_header){
+         if(!isset($header[$tag])){
+            $header[$tag] = array();
+         }
+         $header[$tag][] = $value;
+      } else {
+         if(!isset($stanza[$tag])){
+            $stanza[$tag] = array();
+         }  
+         $stanza[$tag][] = $value;
+      }          
+   }
+   // now add the last term in the file
+   if(sizeof($stanza) > 0){
+      if(!isset($obo[$type])){
+         $obo[$type] = array();
+      }
+      if(!isset($obo[$type][$stanza['id'][0]])){
+         $obo[$type][$stanza['id'][0]] = $stanza;
+      } else {
+         array_merge($obo[$type][$stanza['id'][0]],$stanza);
+      }
+   }
+}
+/**
+*
+* @ingroup tripal_obo_loader
+*/
+function tripal_cv_obo_add_cvterm_dbxref($cvterm,$xref){
+
+   $dbname = preg_replace('/^(.+?):.*$/','$1',$xref);
+   $accession = preg_replace('/^.+?:\s*(.*?)(\{.+$|\[.+$|\s.+$|\".+$|$)/','$1',$xref);
+   $description = preg_replace('/^.+?\"(.+?)\".*?$/','$1',$xref);
+   $dbxrefs = preg_replace('/^.+?\[(.+?)\].*?$/','$1',$xref);
+
+   if(!$accession){
+      tripal_cv_obo_quiterror();
+      watchdog('tripal_cv',"Cannot add a dbxref without an accession: '$xref'"
+         ,NULL,WATCHDOG_WARNING);
+      return 0;
+   }
+
+   // if the xref is a database link, handle that specially
+   if(strcmp($dbname,'http')==0){
+      $accession = $xref;
+      $dbname = 'URL';
+   }
+
+   // check to see if the database exists
+   $db = tripal_cv_obo_add_db($dbname);
+   if(!$db){
+      tripal_cv_obo_quiterror("Cannot find database '$dbname' in Chado.");
+   }
+
+   // now add the dbxref
+   $dbxref = tripal_cv_obo_add_dbxref($db->db_id,$accession,'',$description);
+   if(!$dbxref){ 
+      tripal_cv_obo_quiterror("Cannot find or add the database reference (dbxref)");
+   }
+
+   // finally add the cvterm_dbxref but first check to make sure it exists
+   $sql = "SELECT * from {cvterm_dbxref} WHERE cvterm_id = %d and dbxref_id = %d";
+   if(!db_fetch_object(db_query($sql,$cvterm->cvterm_id,$dbxref->dbxref_id))){            
+      $sql = "INSERT INTO {cvterm_dbxref} (cvterm_id,dbxref_id)".
+             "VALUES (%d,%d)";
+      if(!db_query($sql,$cvterm->cvterm_id,$dbxref->dbxref_id)){
+         tripal_cv_obo_quiterror("Cannot add cvterm_dbxref: $xref");
+      }
+   }
+   return 1;
+}
+/**
+*
+* @ingroup tripal_obo_loader
+*/
+function tripal_cv_obo_add_cvterm_prop($cvterm,$property,$value,$rank){
+
+   // make sure the 'cvterm_property_type' CV exists
+   $cv = tripal_cv_obo_add_cv('cvterm_property_type','');
+   if(!$cv){ 
+      tripal_cv_obo_quiterror("Cannot add/find cvterm_property_type cvterm");
+   }
+
+   // get the property type cvterm.  If it doesn't exist then we want to add it
+   $sql = "
+        SELECT * 
+        FROM {cvterm} CVT INNER JOIN {cv} CV on CVT.cv_id = CV.cv_id
+        WHERE CVT.name = '%s' and CV.name = '%s'
+   ";
+   $cvproptype = db_fetch_object(db_query($sql,$property,'cvterm_property_type'));
+   if(!$cvproptype){
+      $term = array(
+         'name' => array($property),
+         'id' => array("internal:$property"),
+         'definition' => array(''),
+         'is_obsolete' => array(0),
+      );
+      $cvproptype = tripal_cv_obo_add_cvterm($term,$cv,0,0);
+      if(!$cvproptype){  
+         tripal_cv_obo_quiterror("Cannot add cvterm property: internal:$property");
+      }
+   }
+
+
+   // remove any properties that currently exist for this term.  We'll reset them
+   if($rank == 0){
+      $sql = "DELETE FROM {cvtermprop} WHERE cvterm_id = %d";
+      db_query($sql,$cvterm->cvterm_id);
+   }
+
+   // now add the property
+   $sql = "INSERT INTO {cvtermprop} (cvterm_id,type_id,value,rank) ".
+          "VALUES (%d, %d, '%s',%d)";
+   if(!db_query($sql,$cvterm->cvterm_id,$cvproptype->cvterm_id,$value,$rank)){
+      tripal_cv_obo_quiterror("Could not add property $property for term\n");
+   }
+   return 1;
+}
 /**
 *
 * @ingroup tripal_obo_loader
 */
-function tripal_cv_obo_add_cv_term($term,$defaultcv,$is_relationship = 0,$update = 1){
+function tripal_cv_obo_add_cvterm($term,$defaultcv,$is_relationship = 0,$update = 1){
 
    // get the term properties
    $id = $term['id'][0];
@@ -614,20 +753,45 @@ function tripal_cv_obo_add_cv_term($term,$defaultcv,$is_relationship = 0,$update
          tripal_cv_obo_quiterror("Failed to find or insert the dbxref record for cvterm, $name (id: $accession), for database $dbname");
       }
 
-      // now add the cvterm
-      $sql = "
-         INSERT INTO {cvterm} (cv_id, name, definition, dbxref_id, 
-            is_obsolete, is_relationshiptype) 
-         VALUES (%d,'%s','%s',%d,%d,%d)
-      ";
-      if(!db_query($sql,$cv->cv_id,$name,$definition,
-          $dbxref->dbxref_id,$is_obsolete,$is_relationship)){
-         if(!$is_relationship){
-            tripal_cv_obo_quiterror("Failed to insert the term: $name ($dbname)");
-         } else {
-           tripal_cv_obo_quiterror("Failed to insert the relationship term: $name (cv: " . $cvname . " db: $dbname)");
-         }
-      }     
+      // check to see if the dbxref already has an entry in the cvterm table
+      $sql = "SELECT * FROM {cvterm} WHERE dbxref_id = %d";
+      $check = db_fetch_object(db_query($sql,$dbxref->dbxref_id));
+
+      if(!$check){
+         // now add the cvterm
+         $sql = "
+            INSERT INTO {cvterm} (cv_id, name, definition, dbxref_id, 
+               is_obsolete, is_relationshiptype) 
+            VALUES (%d,'%s','%s',%d,%d,%d)
+         ";
+         if(!db_query($sql,$cv->cv_id,$name,$definition,
+             $dbxref->dbxref_id,$is_obsolete,$is_relationship)){
+            if(!$is_relationship){
+               tripal_cv_obo_quiterror("Failed to insert the term: $name ($dbname)");
+            } else {
+               tripal_cv_obo_quiterror("Failed to insert the relationship term: $name (cv: " . $cvname . " db: $dbname)");
+            }
+         }  
+      }
+      elseif($check and strcmp($check->name,$name)!=0){
+         // this dbxref_id alrady exists in the database but the name is 
+         // different.  We will trust that the OBO is correct and that there
+         // has been a name change for this dbxref, so we'll update
+         $sql = "
+            UPDATE {cvterm} SET name = '%s', definition = '%s',
+               is_obsolete = %d, is_relationshiptype = %d 
+         ";
+         if(!db_query($sql,$name,$definition,$is_obsolete,$is_relationship)){
+            if(!$is_relationship){
+               tripal_cv_obo_quiterror("Failed to update the term: $name ($dbname)");
+            } else {
+               tripal_cv_obo_quiterror("Failed to update the relationship term: $name (cv: " . $cvname . " db: $dbname)");
+            }
+         } 
+      }
+      elseif($check and strcmp($check->name,$name)==0){
+         // this entry already exists. We're good, so do nothing
+      }
       $cvterm = db_fetch_object(db_query($cvtermsql,$name,$dbname));
       if(!$is_relationship){
          print "Added CV term: $name ($dbname)\n";
@@ -655,50 +819,7 @@ function tripal_cv_obo_add_cv_term($term,$defaultcv,$is_relationship = 0,$update
    // return the cvterm
    return $cvterm;
 }
-/**
-*
-* @ingroup tripal_obo_loader
-*/
-function tripal_cv_obo_add_cvterm_dbxref($cvterm,$xref){
-
-   $dbname = preg_replace('/^(.+?):.*$/','$1',$xref);
-   $accession = preg_replace('/^.+?:\s*(.*?)(\{.+$|\[.+$|\s.+$|\".+$|$)/','$1',$xref);
-   $description = preg_replace('/^.+?\"(.+?)\".*?$/','$1',$xref);
-   $dbxrefs = preg_replace('/^.+?\[(.+?)\].*?$/','$1',$xref);
-
-   if(!$accession){
-      tripal_cv_obo_quiterror("Cannot add a dbxref without an accession: '$xref'");
-   }
-
-   // if the xref is a database link, handle that specially
-   if(strcmp($dbname,'http')==0){
-      $accession = $xref;
-      $dbname = 'URL';
-   }
-
-   // check to see if the database exists
-   $db = tripal_cv_obo_add_db($dbname);
-   if(!$db){
-      tripal_cv_obo_quiterror("Cannot find database '$dbname' in Chado.");
-   }
-
-   // now add the dbxref
-   $dbxref = tripal_cv_obo_add_dbxref($db->db_id,$accession,'',$description);
-   if(!$dbxref){ 
-      tripal_cv_obo_quiterror("Cannot find or add the database reference (dbxref)");
-   }
 
-   // finally add the cvterm_dbxref but first check to make sure it exists
-   $sql = "SELECT * from {cvterm_dbxref} WHERE cvterm_id = %d and dbxref_id = %d";
-   if(!db_fetch_object(db_query($sql,$cvterm->cvterm_id,$dbxref->dbxref_id))){            
-      $sql = "INSERT INTO {cvterm_dbxref} (cvterm_id,dbxref_id)".
-             "VALUES (%d,%d)";
-      if(!db_query($sql,$cvterm->cvterm_id,$dbxref->dbxref_id)){
-         tripal_cv_obo_quiterror("Cannot add cvterm_dbxref: $xref");
-      }
-   }
-   return 1;
-}
 /**
 *
 * @ingroup tripal_obo_loader
@@ -722,77 +843,4 @@ function tripal_cv_obo_add_dbxref($db_id,$accession,$version='',$description='')
    return $dbxref;
 
 }
-/**
-*
-* @ingroup tripal_obo_loader
-*/
-function tripal_cv_obo_parse($obo_file,&$obo,&$header){
-   $i = 0;
-   $in_header = 1;
-   $stanza = array();
-
-   // iterate through the lines in the OBO file and parse the stanzas
-   $fh = fopen($obo_file,'r');
-   while($line = fgets($fh)) {
-      $i++;
-
-      // remove newlines
-      $line = rtrim($line);  
-      // skip empty lines
-      if(strcmp($line,'')==0) { continue; }
-      //remove comments from end of lines
-      $line = preg_replace('/^(.*?)\!.*$/','\1',$line);  // TODO: if the explamation is escaped
-
-      if(preg_match('/^\s*\[/',$line)){  // at the first stanza we're out of header
-         $in_header = 0;
-         // load the stanza we just finished reading
-         if(sizeof($stanza) > 0){
-            if(!isset($obo[$type])){
-               $obo[$type] = array();
-            }
-            if(!isset($obo[$type][$stanza['id'][0]])){
-               $obo[$type][$stanza['id'][0]] = $stanza;
-            } else {
-               array_merge($obo[$type][$stanza['id'][0]],$stanza);
-            }
-         } 
-         // get the stanza type:  Term, Typedef or Instance
-         $type = preg_replace('/^\s*\[\s*(.+?)\s*\]\s*$/','\1',$line);
-
-         // start fresh with a new array
-         $stanza = array();
-         continue;
-      }
-      // break apart the line into the tag and value but ignore any escaped colons
-      preg_replace("/\\:/","|-|-|",$line); // temporarily replace escaped colons
-      $pair = explode(":",$line,2);
-      $tag = $pair[0];
-      $value = ltrim(rtrim($pair[1]));// remove surrounding spaces
-      $tag = preg_replace("/\|-\|-\|/","\:",$tag); // return the escaped colon
-      $value = preg_replace("/\|-\|-\|/","\:",$value);
-      if($in_header){
-         if(!isset($header[$tag])){
-            $header[$tag] = array();
-         }
-         $header[$tag][] = $value;
-      } else {
-         if(!isset($stanza[$tag])){
-            $stanza[$tag] = array();
-         }  
-         $stanza[$tag][] = $value;
-      }          
-   }
-   // now add the last term in the file
-   if(sizeof($stanza) > 0){
-      if(!isset($obo[$type])){
-         $obo[$type] = array();
-      }
-      if(!isset($obo[$type][$stanza['id'][0]])){
-         $obo[$type][$stanza['id'][0]] = $stanza;
-      } else {
-         array_merge($obo[$type][$stanza['id'][0]],$stanza);
-      }
-   }
-}
-
 

+ 172 - 0
tripal_cv/tripal_cv.api.inc

@@ -343,3 +343,175 @@ function tripal_cv_chado_cvterm_schema() {
 
   return $description;
 }
+
+/**
+*
+* @ingroup tripal_cv_api
+*/
+function tripal_cv_add_cv($name,$comment){
+
+ // see if the CV (default-namespace) exists already in the database
+   $vocab = $name;
+   $remark = $comment;
+   $cv_sql = "SELECT * FROM {cv} WHERE name = '%s'";
+   $cv = db_fetch_object(db_query($cv_sql,$vocab));
+
+   // if the CV exists then update it, otherwise insert
+   if(!$cv){
+      $sql = "INSERT INTO {cv} (name,definition) VALUES ('%s','%s')";
+      if(!db_query($sql,$vocab,$remark)){
+         watchdog('tripal_cv', "Failed to create the CV record",NULL,WATCHDOG_WARNING);
+         return 0;
+      }
+      $cv = db_fetch_object(db_query($cv_sql,$vocab));
+   } else {
+      $sql = "UPDATE {cv} SET definition = '%s' WHERE name ='%s'";
+      if(!db_query($sql,$remark,$vocab)){
+         watchdog('tripal_cv', "Failed to update the CV record",NULL,WATCHDOG_WARNING);
+         return 0;
+      }
+      $cv = db_fetch_object(db_query($cv_sql,$vocab));
+   }
+   return $cv;
+}
+/**
+*
+* @ingroup tripal_cv_api
+*/
+function tripal_cv_add_cvterm($term,$defaultcv,$is_relationship = 0,$update = 1){
+
+   // get the term properties
+   $id = $term['id'];
+   $name = $term['name'];
+   $cvname = $term['namespace'];
+   $definition = preg_replace('/^\"(.*)\"/','\1',$term['def']);
+   $is_obsolete = 0;
+   if(isset($term['is_obsolete']) and  strcmp($term['is_obsolete'],'true')==0){
+     $is_obsolete = 1;
+   }
+   if(!$cvname){
+      $cvname = $defaultcv->name;
+   }
+   // make sure the CV name exists
+   $cv = tripal_cv_add_cv($cvname,'');
+   if(!$cv){
+      watchdog('tripal_cv', "Cannot find namespace '$cvname' when adding/updating $id",NULL,WATCHDOG_WARNING);
+      return 0;
+   }
+
+   // this SQL statement will be used a lot to find a cvterm so just set it
+   // here for easy reference below.
+   $cvtermsql = "SELECT CVT.name, CVT.cvterm_id, DB.name as dbname, DB.db_id 
+                  FROM {cvterm} CVT
+                    INNER JOIN {dbxref} DBX on CVT.dbxref_id = DBX.dbxref_id
+                    INNER JOIN {db} DB on DBX.db_id = DB.db_id
+                    INNER JOIN {cv} CV on CV.cv_id = CVT.cv_id
+                  WHERE CVT.name = '%s' and DB.name = '%s'";  
+
+   // get the accession and the database from the cvterm
+   if(preg_match('/^.+?:.*$/',$id)){
+      $accession = preg_replace('/^.+?:(.*)$/','\1',$id);
+      $dbname = preg_replace('/^(.+?):.*$/','\1',$id);
+   } 
+   if($is_relationship and !$dbname){
+      $accession = $id;
+      // because this is a relationship cvterm first check to see if it 
+      // exists in the relationship ontology. If it does then return the cvterm.
+      //  If not then set the dbname to _global and we'll add it or find it there
+      $cvterm = db_fetch_object(db_query($cvtermsql,$name,'OBO_REL'));
+      if($cvterm){
+         return $cvterm;
+      } else {
+         // next check if this term is in the _global ontology.  If it is then
+         // return it no matter what the original CV
+         $dbname = '_global';
+
+         $cvterm = db_fetch_object(db_query($cvtermsql,$name,$dbname));
+         if($cvterm){
+            return $cvterm;
+         }
+      }
+   }
+   if(!$is_relationship and !$dbname){
+      watchdog('tripal_cv', "A database identifier is missing from the term: $id",NULL,WATCHDOG_WARNING);
+      return 0;
+   }
+
+   // check to see if the database exists. 
+   $db = tripal_db_add_db($dbname);
+   if(!$db){
+      watchdog('tripal_cv', "Cannot find database '$dbname' in Chado.",NULL,WATCHDOG_WARNING);
+      return 0;
+   }
+
+
+   // if the cvterm doesn't exist then add it otherwise just update it
+   $cvterm = db_fetch_object(db_query($cvtermsql,$name,$dbname));
+   if(!$cvterm){
+      // check to see if the dbxref exists if not, add it
+      $dbxref =  tripal_db_add_dbxref($db->db_id,$accession);
+      if(!$dbxref){
+         watchdog('tripal_cv', "Failed to find or insert the dbxref record for cvterm, $name (id: $accession), for database $dbname",NULL,WATCHDOG_WARNING);
+         return 0;
+      }
+
+      // check to see if the dbxref already has an entry in the cvterm table
+      $sql = "SELECT * FROM {cvterm} WHERE dbxref_id = %d";
+      $check = db_fetch_object(db_query($sql,$dbxref->dbxref_id));
+
+      if(!$check){
+         // now add the cvterm
+         $sql = "
+            INSERT INTO {cvterm} (cv_id, name, definition, dbxref_id, 
+               is_obsolete, is_relationshiptype) 
+            VALUES (%d,'%s','%s',%d,%d,%d)
+         ";
+         if(!db_query($sql,$cv->cv_id,$name,$definition,
+             $dbxref->dbxref_id,$is_obsolete,$is_relationship)){
+            if(!$is_relationship){
+               watchdog('tripal_cv', "Failed to insert the term: $name ($dbname)",NULL,WATCHDOG_WARNING);
+               return 0;
+            } else {
+               watchdog('tripal_cv', "Failed to insert the relationship term: $name (cv: " . $cvname . " db: $dbname)",NULL,WATCHDOG_WARNING);
+               return 0;
+            }
+         }  
+      }
+      elseif($check and strcmp($check->name,$name)==0){
+         // this entry already exists. We're good, so do nothing
+      }
+      elseif($check and strcmp($check->name,$name)!=0){
+         watchdog('tripal_cv', "The dbxref already exists in the cvterm table: $dbxref->dbxref_id ($$accession) for term $name",NULL,WATCHDOG_WARNING);
+         return 0;
+      }
+      $cvterm = db_fetch_object(db_query($cvtermsql,$name,$dbname));
+      if(!$is_relationship){
+         print "Added CV term: $name ($dbname)\n";
+      } else {
+         print "Added relationship CV term: $name ($dbname)\n";
+      }
+   }
+   elseif($update) { // update the cvterm
+      $sql = "
+         UPDATE {cvterm} SET name='%s', definition='%s',
+            is_obsolete = %d, is_relationshiptype = %d
+         WHERE cvterm_id = %d
+      ";
+      if(!db_query($sql,$term['name'],$definition,
+          $is_obsolete,$is_relationship,$cvterm->cvterm_id)){
+         watchdog('tripal_cv', "Failed to update the term: $name",NULL,WATCHDOG_WARNING);
+         return 0;
+
+      }  
+      $cvterm = db_fetch_object(db_query($cvtermsql,$name,$dbname));         
+      if(!$is_relationship){
+         print "Updated CV term: $name ($dbname)\n";
+      } else {
+         print "Updated relationship CV term: $name ($dbname)\n";
+      }
+   }
+   // return the cvterm
+   return $cvterm;
+}
+
+

+ 41 - 0
tripal_db/tripal_db.api.inc

@@ -290,3 +290,44 @@ function tripal_db_chado_dbxref_schema() {
 
   return $description;
 }
+/**
+*
+* @ingroup tripal_db_api
+*/
+function tripal_db_add_db($dbname){
+
+   $db_sql = "SELECT * FROM {db} WHERE name ='%s'";
+   $db = db_fetch_object(db_query($db_sql,$dbname));
+   if(!$db){
+      if(!db_query("INSERT INTO {db} (name) VALUES ('%s')",$dbname)){
+         watchdog('tripal_cv', "Cannot create '$dbname' db in Chado.",NULL,WATCHDOG_WARNING);
+         return 0;
+      }      
+     $db = db_fetch_object(db_query($db_sql,$dbname));
+   }
+   return $db;
+}
+/**
+*
+* @ingroup tripal_db_api
+*/
+function tripal_db_add_dbxref($db_id,$accession,$version='',$description=''){
+
+   // check to see if the dbxref exists if not, add it
+   $dbxsql = "SELECT dbxref_id FROM {dbxref} WHERE db_id = %d and accession = '%s'";
+   $dbxref = db_fetch_object(db_query($dbxsql,$db_id,$accession));
+   if(!$dbxref){
+      $sql = "
+         INSERT INTO {dbxref} (db_id, accession, version, description)
+         VALUES (%d,'%s','%s','%s')
+      ";
+      if(!db_query($sql,$db_id,$accession,$version,$description)){
+         watchdog('tripal_cv', "Failed to insert the dbxref record $accession",NULL,WATCHDOG_WARNING);
+         return 0;
+      }
+      print "Added Dbxref accession: $accession\n";
+      $dbxref = db_fetch_object(db_query($dbxsql,$db_id,$accession));
+   }
+   return $dbxref;
+
+}

+ 69 - 25
tripal_feature/gff_loader.php

@@ -17,7 +17,7 @@
  *
  * @ingroup gff3_loader
  */
-function tripal_core_gff3_load_form (){
+function tripal_feature_gff3_load_form (){
 
    $form['gff_file']= array(
       '#type'          => 'textfield',
@@ -100,7 +100,7 @@ function tripal_core_gff3_load_form (){
          data set, but at least indicates the source of the data."), 
    );
 
-   // get the list of organisms
+   // get the list of analyses
    $sql = "SELECT * FROM {analysis} ORDER BY name";
    $previous_db = tripal_db_set_active('chado');  // use chado database
    $org_rset = db_query($sql);
@@ -133,7 +133,7 @@ function tripal_core_gff3_load_form (){
  *
  * @ingroup gff3_loader
  */
-function tripal_core_gff3_load_form_validate ($form, &$form_state){
+function tripal_feature_gff3_load_form_validate ($form, &$form_state){
 
    $gff_file = $form_state['values']['gff_file'];
    $organism_id = $form_state['values']['organism_id'];
@@ -165,7 +165,7 @@ function tripal_core_gff3_load_form_validate ($form, &$form_state){
  *
  * @ingroup gff3_loader
  */
-function tripal_core_gff3_load_form_submit ($form, &$form_state){
+function tripal_feature_gff3_load_form_submit ($form, &$form_state){
    global $user;
 
    $gff_file = $form_state['values']['gff_file'];
@@ -190,8 +190,8 @@ function tripal_core_gff3_load_form_submit ($form, &$form_state){
    if($remove){
      $type = 'delete features';
    }
-   tripal_add_job("$type GFF3 file $gff_file",'tripal_core',
-      'tripal_core_load_gff3',$args,$user->uid);
+   tripal_add_job("$type GFF3 file $gff_file",'tripal_feature',
+      'tripal_feature_load_gff3',$args,$user->uid);
 
    return '';
 }
@@ -201,7 +201,7 @@ function tripal_core_gff3_load_form_submit ($form, &$form_state){
  *
  * @ingroup gff3_loader
  */
-function tripal_core_load_gff3($gff_file, $organism_id,$analysis_id,$add_only =0, 
+function tripal_feature_load_gff3($gff_file, $organism_id,$analysis_id,$add_only =0, 
    $update = 0, $refresh = 0, $remove = 0, $job = NULL)
 {
 
@@ -248,6 +248,7 @@ function tripal_core_load_gff3($gff_file, $organism_id,$analysis_id,$add_only =0
    }
    $in_fasta = 0;
    foreach ($lines as $line_num => $line) {
+   
       $i++;  // update the line count
       // update the job status every 1% features
       if($job and $i % $interval == 0){
@@ -257,6 +258,7 @@ function tripal_core_load_gff3($gff_file, $organism_id,$analysis_id,$add_only =0
       // to start parsing
       if(preg_match('/^##FASTA/i',$line)){
          $in_fasta = 1;
+         break;
       }
       // skip comments
       if(preg_match('/^#/',$line)){
@@ -270,9 +272,9 @@ function tripal_core_load_gff3($gff_file, $organism_id,$analysis_id,$add_only =0
 
       // handle FASTA section
       
+      // TODO: handle URL encoding
 
-      // TODO: remove URL encoding
-  
+      // remove URL encoding and get the columns
       $cols = explode("\t",$line);
       if(sizeof($cols) != 9){
          print "ERROR: improper number of columns on line $i\n";
@@ -434,7 +436,7 @@ function tripal_core_load_gff3($gff_file, $organism_id,$analysis_id,$add_only =0
 
          // add/update the feature
          print "$i ";
-         $feature = tripal_core_load_gff3_feature($organism,$analysis_id,$cvterm,
+         $feature = tripal_feature_load_gff3_feature($organism,$analysis_id,$cvterm,
             $attr_uniquename,$attr_name,$residues,$attr_is_analysis,
             $attr_is_obsolete, $add_only);
 
@@ -448,29 +450,37 @@ function tripal_core_load_gff3($gff_file, $organism_id,$analysis_id,$add_only =0
             // add/update the featureloc if the landmark and the ID are not the same
             // if they are the same then this entry in the GFF is probably a landmark identifier
             if(strcmp($landmark,$attr_uniquename)!=0){
-               tripal_core_load_gff3_featureloc($feature,$organism,
+               tripal_feature_load_gff3_featureloc($feature,$organism,
                   $landmark,$fmin,$fmax,$strand,$phase,$attr_fmin_partial,
                   $attr_fmax_partial,$attr_residue_info,$attr_locgroup);
             }
             // add any aliases for this feature
             if(array_key_exists('Alias',$tags)){
-               tripal_core_load_gff3_alias($feature,$tags['Alias']);
+               tripal_feature_load_gff3_alias($feature,$tags['Alias']);
             }
             // add any aliases for this feature
             if(array_key_exists('Dbxref',$tags)){
-               tripal_core_load_gff3_dbxref($feature,$tags['Dbxref']);
+               tripal_feature_load_gff3_dbxref($feature,$tags['Dbxref']);
             }
             // add any aliases for this feature
             if(array_key_exists('Ontology_term',$tags)){
-               tripal_core_load_gff3_ontology($feature,$tags['Ontology_term']);
+               tripal_feature_load_gff3_ontology($feature,$tags['Ontology_term']);
             }
             // add parent relationships
             if(array_key_exists('Parent',$tags)){
-               tripal_core_load_gff3_parents($feature,$cvterm,$tags['Parent'],$gff_features,$organism_id,$fmin);
+               tripal_feature_load_gff3_parents($feature,$cvterm,$tags['Parent'],$gff_features,$organism_id,$fmin);
             }
             // add in the GFF3_source dbxref so that GBrowse can find the feature using the source column
             $source_ref = array('GFF_source:'.$source);
-            tripal_core_load_gff3_dbxref($feature,$source_ref);
+            tripal_feature_load_gff3_dbxref($feature,$source_ref);
+
+            // add any additional attributes
+            if($attr_others){
+               foreach($attr_others as $property => $value){
+                  print "   Setting feature property: $property -> $value\n";
+                  tripal_feature_load_gff3_property($feature,$property,$value);
+               }
+            }
          }
       }      
    }
@@ -535,7 +545,7 @@ function tripal_core_load_gff3($gff_file, $organism_id,$analysis_id,$add_only =0
  *
  * @ingroup gff3_loader
  */
-function tripal_core_load_gff3_parents($feature,$cvterm,$parents,&$gff_features,$organism_id,$fmin){
+function tripal_feature_load_gff3_parents($feature,$cvterm,$parents,&$gff_features,$organism_id,$fmin){
 
    $uname = $feature->uniquename;
    $type = $cvterm->name;
@@ -598,7 +608,7 @@ function tripal_core_load_gff3_parents($feature,$cvterm,$parents,&$gff_features,
  * @ingroup gff3_loader
  */
 
-function tripal_core_load_gff3_dbxref($feature,$dbxrefs){
+function tripal_feature_load_gff3_dbxref($feature,$dbxrefs){
 
    // iterate through each of the dbxrefs
    foreach($dbxrefs as $dbxref){
@@ -669,7 +679,7 @@ function tripal_core_load_gff3_dbxref($feature,$dbxrefs){
  *
  * @ingroup gff3_loader
  */
-function tripal_core_load_gff3_ontology($feature,$dbxrefs){
+function tripal_feature_load_gff3_ontology($feature,$dbxrefs){
 
    // iterate through each of the dbxrefs
    foreach($dbxrefs as $dbxref){
@@ -746,7 +756,7 @@ function tripal_core_load_gff3_ontology($feature,$dbxrefs){
  *
  * @ingroup gff3_loader
  */
-function tripal_core_load_gff3_alias($feature,$aliases){
+function tripal_feature_load_gff3_alias($feature,$aliases){
 
    // make sure we have a 'synonym_type' vocabulary
    $sql = "SELECT * FROM {cv} WHERE name='synonym_type'";
@@ -774,9 +784,10 @@ function tripal_core_load_gff3_alias($feature,$aliases){
          'definition' => array(''),
          'is_obsolete' => array(0),
       );
-      $syntype = tripal_cv_obo_add_cv_term($term,$syncv,0,1);
+      $syntype = tripal_cv_add_cvterm($term,$syncv,0,1);
       if(!$syntype){
-         tripal_cv_obo_quiterror("Cannot add synonym type: internal:$type");
+         print("Cannot add synonym type: internal:$type");
+         return 0;
       }
    }
 
@@ -835,7 +846,7 @@ function tripal_core_load_gff3_alias($feature,$aliases){
             return 0;
          }
       } else {
-         print "Synonym $alias already exists. Skipping\n";
+         print "   Synonym $alias already exists. Skipping\n";
       }
    }
    return 1;
@@ -846,7 +857,7 @@ function tripal_core_load_gff3_alias($feature,$aliases){
  *
  * @ingroup gff3_loader
  */
-function tripal_core_load_gff3_feature($organism,$analysis_id,$cvterm,$uniquename,$name,
+function tripal_feature_load_gff3_feature($organism,$analysis_id,$cvterm,$uniquename,$name,
    $residues,$is_analysis='f',$is_obsolete='f',$add_only)  {
 
    // check to see if the feature already exists
@@ -915,7 +926,7 @@ function tripal_core_load_gff3_feature($organism,$analysis_id,$cvterm,$uniquenam
  *
  * @ingroup gff3_loader
  */
-function tripal_core_load_gff3_featureloc($feature,$organism,$landmark,$fmin,
+function tripal_feature_load_gff3_featureloc($feature,$organism,$landmark,$fmin,
    $fmax,$strand,$phase,$is_fmin_partial,$is_fmax_partial,$residue_info,$locgroup)
 {
  
@@ -986,5 +997,38 @@ function tripal_core_load_gff3_featureloc($feature,$organism,$landmark,$fmin,
    }
    return 1;
 }
+/**
+ *
+ *
+ * @ingroup gff3_loader
+ */
+function tripal_feature_load_gff3_property($feature,$property,$value){
+   // first make sure the cvterm exists.  If the term already exists then
+   // the function should return it
+   $match = array(
+      'name' => $property,
+      'cv_id' => array(
+         'name' => 'feature_property',
+      ),
+   );
+   $cvterm = tripal_core_chado_select('cvterm',array('*'),$match);
+   if(sizeof($cvterm) == 0){
+      $term = array(
+         'id' => "null:$property",
+         'name' => $property,
+         'namespace' => 'feature_property', 
+         'is_obsolete' => 0,
+      );
+      print "   Adding cvterm, $property\n";
+      $cvterm = tripal_cv_add_cvterm($term,'feature_property',0,0);
+   }
 
+   if(!$cvterm){
+      print "ERROR: cannot add cvterm, $property, before adding property\n";
+      exit;
+   }
+
+   // next give the feature the property
+   tripal_core_insert_property('feature',$feature->feature_id,$property,'feature_property',$value,1);
+}
 

+ 2 - 2
tripal_feature/indexFeatures.php

@@ -155,8 +155,8 @@ function tripal_feature_index_feature ($feature_id,$nid){
    $node = node_build_content($node, FALSE, FALSE);
    $node->body = drupal_render($node->content);
    node_invoke_nodeapi($node, 'view', FALSE, FALSE);
-   $node->body .= module_invoke('comment', 'nodeapi', $node, 'update index');
-   $node->body .= module_invoke('taxonomy','nodeapi', $node, 'update index');
+//   $node->body .= module_invoke('comment', 'nodeapi', $node, 'update index');
+//   $node->body .= module_invoke('taxonomy','nodeapi', $node, 'update index');
    //   print "$node->title: $node->body\n";
    search_index($node->nid,'node',$node->body);
 

+ 106 - 39
tripal_feature/syncFeatures.php

@@ -29,6 +29,91 @@ if(isset($arguments['f'])){
 }
 /**
 *
+*/
+function tripal_feature_sync_form (){
+
+   $form['description'] = array(
+      '#type' => 'item',
+      '#value' => t("Add feature types, optionally select an organism and ".
+         "click the 'Sync all Features' button to create Drupal ".
+         "content for features in chado. Only features of the types listed ".
+         "below in the Feature Types box will be synced. You may limit the ".
+         "features to be synced by a specific organism. Depending on the ".
+         "number of features in the chado database this may take a long ".
+         "time to complete. "),
+   );
+
+   $form['feature_types'] = array(
+      '#title'       => t('Feature Types'),
+      '#type'        => 'textarea',
+      '#description' => t('Enter the names of the sequence types that the ".
+         "site will support with independent pages.  Pages for these data ".
+         "types will be built automatically for features that exist in the ".
+         "chado database.  The names listed here should be spearated by ".
+         "spaces or entered separately on new lines. The names must match ".
+         "exactly (spelling and case) with terms in the sequence ontology'),
+      '#required'    => TRUE,
+      '#default_value' => variable_get('chado_feature_types','EST contig'),
+   );
+
+   // get the list of organisms
+   $sql = "SELECT * FROM {organism} ORDER BY genus, species";
+   $orgs = tripal_organism_get_synced(); 
+   $organisms[] = ''; 
+   foreach($orgs as $organism){
+      $organisms[$organism->organism_id] = "$organism->genus $organism->species ($organism->common_name)";
+   }
+   $form['organism_id'] = array (
+     '#title'       => t('Organism'),
+     '#type'        => t('select'),
+     '#description' => t("Choose the organism for which features will be deleted."),
+     '#options'     => $organisms,
+   );
+
+
+   $form['button'] = array(
+      '#type' => 'submit',
+      '#value' => t('Sync all Features'),
+      '#weight' => 3,
+   );
+
+   return $form;
+}
+/**
+*
+*/
+function tripal_feature_sync_form_validate ($form, &$form_state){
+   $organism_id   = $form_state['values']['organism_id'];
+   $feature_types = $form_state['values']['feature_types'];
+
+   // nothing to do
+}
+/**
+*
+*/
+function tripal_feature_sync_form_submit ($form, &$form_state){
+
+   global $user;
+
+   $organism_id   = $form_state['values']['organism_id'];
+   $feature_types = $form_state['values']['feature_types'];
+
+   $job_args = array(0,$organism_id,$feature_types);
+
+   if($organism_id){
+      $organism = tripal_core_chado_select('organism',array('genus','species'),array('organism_id' => $organism_id));
+      $title = "Sync all features for " .  $organism[0]->genus . " " . $organism[0]->species;
+   } else {
+      $title = t('Sync all features for all synced organisms');
+   }
+
+   variable_get('chado_feature_types',$feature_types);
+
+   tripal_add_job($title,'tripal_feature',
+         'tripal_feature_sync_features',$job_args,$user->uid);
+}
+/**
+*
 */   
 function tripal_feature_set_urls($job_id = NULL){
    // first get the list of features that have been synced
@@ -73,14 +158,20 @@ function tripal_feature_set_feature_url($node,$feature){
  *
  * @ingroup tripal_feature
  */
-function tripal_feature_sync_features ($max_sync = 0, $job_id = NULL){
+function tripal_feature_sync_features ($max_sync = 0, $organism_id = NULL, 
+   $feature_types = NULL, $job_id = NULL)
+{
    //print "Syncing features (max of $max_sync)\n";
    $i = 0;
 
    // get the list of available sequence ontology terms for which
    // we will build drupal pages from features in chado.  If a feature
    // is not one of the specified typse we won't build a node for it.
-   $allowed_types = variable_get('chado_feature_types','EST contig');
+   if(!$feature_types){
+      $allowed_types = variable_get('chado_feature_types','EST contig');
+   } else {
+      $allowed_types = $feature_types;
+   }
    $allowed_types = preg_replace("/[\s\n\r]+/"," ",$allowed_types);
 
    print "Looking for features of type: $allowed_types\n";
@@ -94,11 +185,18 @@ function tripal_feature_sync_features ($max_sync = 0, $job_id = NULL){
 
    // get the list of organisms that are synced and only include features from
    // those organisms
-   $orgs = organism_get_synced();
+   $orgs = tripal_organism_get_synced();
    $where_org = "";
    foreach($orgs as $org){
-      if($org->organism_id){
-         $where_org .= "F.organism_id = $org->organism_id OR ";
+      if($organism_id){
+         if($org->organism_id and $org->organism_id == $organism_id){
+            $where_org .= "F.organism_id = $org->organism_id OR ";
+         }
+      } 
+      else {
+         if($org->organism_id){
+            $where_org .= "F.organism_id = $org->organism_id OR ";
+         }
       }
    }
    $where_org = substr($where_org,0,strlen($where_org)-3);  # strip trailing 'OR'
@@ -135,6 +233,9 @@ function tripal_feature_sync_features ($max_sync = 0, $job_id = NULL){
 
    // Iterate through features that need to be synced
    $interval = intval($count * 0.01);
+   if($interval > 1){
+      $interval = 1;
+   }
    $num_ids = sizeof($ids);
    $i = 0;
    foreach($ids as $feature_id){
@@ -314,38 +415,4 @@ function tripal_feature_sync_feature ($feature_id){
 
    return '';
 }
-
-
-
-/**
- *  Returns a list of organisms that are currently synced with Drupal
- *
- * @ingroup tripal_feature
- */
-function organism_get_synced() {
-
-   // use this SQL for getting synced organisms
-   $dsql =  "SELECT * FROM {chado_organism}";
-   $orgs = db_query($dsql);
-
-   // use this SQL statement for getting the organisms
-   $csql =  "SELECT * FROM {Organism} ".
-            "WHERE organism_id = %d";
-
-   $org_list = array();
-
-   // iterate through the organisms and build an array of those that are synced
-   while($org = db_fetch_object($orgs)){
-      $previous_db = tripal_db_set_active('chado');  // use chado database
-      $info = db_fetch_object(db_query($csql,$org->organism_id));
-      tripal_db_set_active($previous_db);  // now use drupal database
-      $org_list[] = $info;
-   }    
-   return $org_list;
-}
-
-
-
-
-
 ?>

+ 178 - 0
tripal_feature/tripal_feature-delete.inc

@@ -0,0 +1,178 @@
+<?php
+
+
+function tripal_feature_delete_form (){
+   // get the list of organisms
+   $sql = "SELECT * FROM {organism} ORDER BY genus, species";
+   $previous_db = tripal_db_set_active('chado');  // use chado database
+   $org_rset = db_query($sql);
+   tripal_db_set_active($previous_db);  // now use drupal database
+   $organisms = array();
+   $organisms[''] = '';
+   while($organism = db_fetch_object($org_rset)){
+      $organisms[$organism->organism_id] = "$organism->genus $organism->species ($organism->common_name)";
+   }
+   $form['desc'] = array(
+      '#type' => 'markup',
+      '#value' => t("Use one or more of the following fields to identify sets of features to be deleted."), 
+   );
+
+   $form['feature_names']= array(
+      '#type' => 'textarea',
+      '#title' => t('Feature Names'),
+      '#description' => t('Please provide a list of feature names or unique names, 
+         separated by spaces or by new lines to be delete. If you specify feature names then
+         all other options below will be ignored (except the unique checkbox).'),
+   );
+	$form['is_uniquename'] = array(
+      '#title' => t('Names are Unique Names'),
+      '#type' => 'checkbox',
+      '#description' => t('Select this checbox if the names listed in the feature 
+        names box above are the unique name of the feature rather than the human readable names.'),
+	);
+   $form['seq_type']= array(
+      '#type' => 'textfield',
+      '#title' => t('Sequence Type'),
+      '#description' => t('Please enter the Sequence Ontology term that describes the features to be deleted. Use in conjunction with an organism or anaylysis.'),
+   );
+
+   $form['organism_id'] = array (
+     '#title'       => t('Organism'),
+     '#type'        => t('select'),
+     '#description' => t("Choose the organism for which features will be deleted."),
+     '#options'     => $organisms,
+   );
+
+
+   // get the list of analyses
+   $sql = "SELECT * FROM {analysis} ORDER BY name";
+   $previous_db = tripal_db_set_active('chado');  // use chado database
+   $org_rset = db_query($sql);
+   tripal_db_set_active($previous_db);  // now use drupal database
+   $analyses = array();
+   $analyses[''] = '';
+   while($analysis = db_fetch_object($org_rset)){
+      $analyses[$analysis->analysis_id] = "$analysis->name ($analysis->program $analysis->programversion, $analysis->sourcename)";
+   }
+//  TODO: ADD THIS BACK IN LATER
+//
+//   $form['analysis']['analysis_id'] = array (
+//     '#title'       => t('Analysis'),
+//     '#type'        => t('select'),
+//     '#description' => t("Choose the analysis for which associated features will be deleted."),
+//     '#options'     => $analyses,
+//   );
+
+   $form['button'] = array(
+      '#type' => 'submit',
+      '#value' => t('Delete Features'),
+   );
+   return $form;
+}
+
+function tripal_feature_delete_form_validate ($form, &$form_state){
+   $organism_id   = $form_state['values']['organism_id'];
+   $seq_type      = trim($form_state['values']['seq_type']);
+   $analysis_id   = $form_state['values']['analysis_id'];
+   $is_unique     = $form_state['values']['is_unique'];
+   $feature_names = $form_state['values']['feature_names'];
+
+   if (!$organism_id and !$anaysis_id and !$seq_type and !$feature_names){
+      form_set_error('feature_names',t("Please select at least one option"));
+   }
+
+   // check to make sure the types exists
+   if($seq_type){
+      $cvtermsql = "SELECT CVT.cvterm_id
+                    FROM {cvterm} CVT
+                       INNER JOIN {cv} CV on CVT.cv_id = CV.cv_id
+                       LEFT JOIN {cvtermsynonym} CVTS on CVTS.cvterm_id = CVT.cvterm_id
+                    WHERE cv.name = '%s' and (CVT.name = '%s' or CVTS.synonym = '%s')";
+      $cvterm = db_fetch_object(db_query($cvtermsql,'sequence',$seq_type,$seq_type));
+      if(!$cvterm){
+         form_set_error('seq_type',t("The Sequence Ontology (SO) term selected for the sequence type is not available in the database. Please check spelling or select another."));
+      }
+   }
+}
+
+function tripal_feature_delete_form_submit ($form, &$form_state){
+   global $user;
+
+   $organism_id   = $form_state['values']['organism_id'];
+   $seq_type      = trim($form_state['values']['seq_type']);
+   $analysis_id   = $form_state['values']['analysis_id'];
+   $is_unique     = $form_state['values']['is_unique'];
+   $feature_names = $form_state['values']['feature_names'];
+
+   $args = array($organism_id,$analysis_id,$seq_type,$is_unique,$feature_names);
+
+   tripal_add_job("Delete features",'tripal_feature',
+      'tripal_feature_delete_features',$args,$user->uid);
+}
+
+
+function tripal_feature_delete_features($organism_id,$analysis_id,$seq_type,
+   $is_unique,$feature_names,$job = NULL)
+{
+
+   global $user;
+   $match = array();   
+
+   // if feature names have been provided then handle that separately
+   if($feature_names){
+      $names = preg_split('/\s+/',$feature_names);
+      if(sizeof($names) == 1){
+         $names = $names[0];
+      }
+      if($is_unique){
+         $match['uniquename'] = $names;
+      } else {
+         $match['name'] = $names;
+      }
+      $num_deletes = tripal_core_chado_select('feature',array('count(*) as cnt'),$match);
+      print "Deleting ".$num_deletes[0]->cnt ." features\n"; 
+      tripal_core_chado_delete('feature',$match);
+   }
+
+   // if the user has provided an analysis_id then handle that separately
+   elseif($analysis_id){
+      tripal_feature_delete_by_analysis();
+   }
+   else {
+
+
+      if($organism_id){
+         $match['organism_id'] = $organism_id;
+      }
+      if($seq_type){
+         $match['type_id'] = array(
+            'name' => $seq_type,
+            'cv_id' => array(
+               'name' => 'sequence'
+            ),
+         );
+      }
+      $num_deletes = tripal_core_chado_select('feature',array('count(*) as cnt'),$match);
+      print "Deleting ".$num_deletes[0]->cnt ." features\n"; 
+      tripal_core_chado_delete('feature',$match);
+   }
+
+   print "Removing orphaned feature pages\n";
+   tripal_features_cleanup(array(),$user->uid);
+}
+
+function tripal_feature_delete_by_analysis($organism_id,$analysis_id,$seq_type,
+   $is_unique,$feature_names,$job = NULL)
+{
+
+}
+
+
+
+
+
+
+
+
+
+

+ 34 - 86
tripal_feature/tripal_feature.admin.inc

@@ -15,9 +15,10 @@ function tripal_feature_module_description_page() {
              <li><a href=\"".url("admin/tripal/tripal_feature/configuration") . "\">Feature Configuration</a></li>
              <li><a href=\"".url("admin/tripal/tripal_feature/fasta_loader"). "\">Import a multi-FASTA file</a></li>
              <li><a href=\"".url("admin/tripal/tripal_feature/gff3_load"). "\">Import a GFF3 file</a></li>
-             <li><a href=\"".url("admin/tripal/tripal_feature/aggregate"). "\">Feature Relationship Aggegators</a></li>
+             <li><a href=\"".url("admin/tripal/tripal_feature/sync") . "\">Sync Features</a></li>
+             <li><a href=\"".url("admin/tripal/tripal_feature/delete") . "\">Delete Features</a></li>
            </ul>";
- 
+#             <li><a href=\"".url("admin/tripal/tripal_feature/aggregate"). "\">Feature Relationship Aggegators</a></li> 
 
   $text .= '<h3>Module Description:</h3>';
   $text .= '<p>This module provides an interface for the Chado feature module which stores information
@@ -64,7 +65,7 @@ function tripal_feature_module_description_page() {
                later to visualize data pipelines.  Before loading feature data through the FASTA or GFF loaders
                you will need to <a href="'.url('node/add').'">create an analysis</a> for the data.</p></li>
 
-               <li><p><b>Create Database</b>:  If you would like to associate your feature data with an 
+               <li><p><b>Create Referring Database Entries</b>:  If you would like to associate your feature data with an 
                external reference database, check to ensure that the <a href="'.url('admin/tripal/tripal_db/edit_db').'">
                database record already exists</a>.  If not you should <a href="'.url('admin/tripal/tripal_db/add_db').'">add a new database record</a> before importing
                feature data.</p></li>
@@ -83,7 +84,7 @@ function tripal_feature_module_description_page() {
                have loaded whole genome sequence with fully defined gene models with several features to define
                a gene and its products (e.g. gene, mRNA, CDS, 5\'UTR, 3\'UTR, etc) you probably only want to create
                pages for genes or genes and mRNA.  You probably do not want a page for a 5\'UTR.  
-               Using the <a href="'.url('admin/tripal/tripal_feature/configuration').'">Feature Configuration page</a> 
+               Using the <a href="'.url('admin/tripal/tripal_feature/configuration/sync').'">Feature Sync page</a> 
                you can sync (or create pages) for the desired feature types. </p></li>
 
                <li><p><b>Set Feature URL</b>:  It is often convenient to have a simple URL for each feature page. 
@@ -141,6 +142,10 @@ function tripal_feature_module_description_page() {
               tool</a> for finding or listing features in Chado. It does not require indexing for Drupal searching but relies
               on Drupal Views.  <a href="http://drupal.org/project/views">Drupal Views</a> must be installed. </p></li>              
 
+              <li><p><b>Delete Features</b>: This module provides a <a href="'.url('admin/tripal/tripal_feature/delete').'">Delete Feature page</a>
+              for bulk deltions of features. You may delete features using a list of feature names, or for a specific organism
+              or for a specific feature type.</p></li>              
+
             </ul>
             </p>';
 
@@ -214,32 +219,8 @@ function tripal_feature_admin () {
    if(tripal_get_module_active_jobs('tripal_feature')){
       $active_jobs = TRUE;
    }
-   if(!$active_jobs){
-
-      $form['chado_feature_accession_prefix'] = array (
-         '#title'       => t('Internal ID Prefix'),
-         '#type'        => t('textfield'),
-         '#description' => t("Internal ID numbers for features consist of the ".
-            "chado feature_id and a site specific prefix.  Set the prefix that ".
-            "will be incorporated in front of each feature_id."),
-         '#required'    => TRUE,
-         '#default_value' => variable_get('chado_feature_accession_prefix','ID'),
-      );
-
-      $form['chado_feature_types'] = array(
-         '#title'       => t('Feature Types'),
-         '#type'        => 'textarea',
-         '#description' => t('Enter the names of the sequence types that the ".
-            "site will support with independent pages.  Pages for these data ".
-            "types will be built automatically for features that exist in the ".
-            "chado database.  The names listed here should be spearated by ".
-            "spaces or entered separately on new lines. The names must match ".
-            "exactly (spelling and case) with terms in the sequence ontology'),
-         '#required'    => TRUE,
-         '#default_value' => variable_get('chado_feature_types','EST contig'),
-      );
+   if($active_jobs){
 
-      get_tripal_feature_admin_form_sync_set($form);
       get_tripal_feature_admin_form_url_set($form);
 
       $form['browser'] = array(
@@ -458,80 +439,47 @@ function get_tripal_feature_admin_form_taxonomy_set (&$form) {
 
 }
 
-/**
- *
- *
- * @ingroup tripal_feature
- */
-function get_tripal_feature_admin_form_sync_set (&$form) {
-
-  
-   // get the list of organisms which will be synced.
-   $feature_sql = "SELECT * FROM {Feature} WHERE uniquename = '%s' and organism_id = %d";
-   $previous_db = tripal_db_set_active('chado');
-   $feature = db_fetch_object(db_query($feature_sql,$node->title,$node->organism_id));
-   tripal_db_set_active($previous_db);
-
-   // define the fieldsets
-   $form['sync'] = array(
-      '#type' => 'fieldset',
-      '#title' => t('Sync Features')
-   );
-
-   $form['sync']['description'] = array(
-      '#type' => 'item',
-      '#value' => t("Click the 'Sync all Features' button to create Drupal ".
-         "content for features in chado. Only features of the types listed ".
-         "above in the Feature Types box will be synced. Depending on the ".
-         "number of features in the chado database this may take a long ".
-         "time to complete. "),
-      '#weight' => 1,
-   );
-
-   $orgs = tripal_organism_get_synced();   
-   $org_list = '';
-   foreach($orgs as $org){
-      $org_list .= "$org->genus $org->species, ";
-   }
-   $form['sync']['description2'] = array(
-      '#type' => 'item',
-      '#value' => "Only features for the following organisms will be synced: ".
-         " $org_list",
-      '#weight' => 1,
-   );
-
-   $form['sync']['button'] = array(
-      '#type' => 'submit',
-      '#value' => t('Sync all Features'),
-      '#weight' => 3,
-   );
-
-}
 function get_tripal_feature_admin_form_url_set (&$form) {
 
    $form['url'] = array(
       '#type' => 'fieldset',
       '#title' => t('Feature URL Path')
    );
-
-   $form['url']['chado_feature_url'] = array(
-      '#title'       => t('Feature URL'),
-      '#type'        => 'radios',
-      '#description' => t('Each synced feature will have a unique URL which consists of '.
+   $form['url']['desc'] = array (
+      '#type'        => 'markup',
+      '#value' => t('Each synced feature will have a unique URL which consists of '.
                           'the site domain followed by a unique identifer: for '.
                           'example http://my-tripal-site.org/ID1034, where the '.
                           'element just after the final slash is the unique '.
-                          'identifier for the feature.  Choose a feature descriptor '.
-                          'from the list that is guaranteed to be unique in your synced '.
+                          'identifier for the feature.'),
+
+   );
+
+   $form['url']['chado_feature_url'] = array(
+      '#title'       => t('Unique Identifier'),
+      '#type'        => 'radios',
+      '#description' => t('Choose an identifier type '.
+                          'from the list above that is guaranteed to be unique in your synced '.
                           'dataset. If in doubt it is safest to coose the internal ID. '.
                           'The descrpitor need not be unique amont the total dataset. '.
                           'It only need be unique among the synced dataset.'),
       '#required'    => FALSE,
-      '#options'     => array('internal ID' => 'internal ID',
+      '#options'     => array('internal ID' => 'internal ID (Chado feature_id)',
                               'feature unique name' => 'feature unique name', 
                               'feature name' => 'feature name'),
       '#default_value' => variable_get('chado_feature_url','internal ID'),
    );
+
+   $form['url']['chado_feature_accession_prefix'] = array (
+      '#title'       => t('ID Prefix'),
+      '#type'        => t('textfield'),
+      '#description' => t("If you choose an Internal ID above you must also enter an ID prefix.".
+                          "this prefix will be prepended to the internal ID number (e.g. ID38294). ".
+                          "if you chose to use the feature name or unique name then this prfix is not used"),
+      '#required'    => TRUE,
+      '#default_value' => variable_get('chado_feature_accession_prefix','ID'),
+   );
+
    $form['url']['button'] = array(
       '#type' => 'submit',
       '#value' => t('Set Feature URLs'),

+ 52 - 1
tripal_feature/tripal_feature.module

@@ -16,6 +16,7 @@ require_once "gff_loader.php";
 
 require_once "tripal_feature.api.inc";
 
+require_once "tripal_feature-delete.inc";
 require_once "tripal_feature-secondary_tables.inc";
 require_once "tripal_feature-properties.inc";
 require_once "tripal_feature-relationships.inc";
@@ -178,11 +179,29 @@ function tripal_feature_menu() {
      'title' => 'Import a GFF3 file',
      'description' => 'Import a GFF3 file into Chado',
      'page callback' => 'drupal_get_form',
-     'page arguments' => array('tripal_core_gff3_load_form'),
+     'page arguments' => array('tripal_feature_gff3_load_form'),
      'access arguments' => array('access administration pages'),
      'type' => MENU_NORMAL_ITEM,
    );  
 
+   $items['admin/tripal/tripal_feature/delete'] = array(
+     'title' => ' Delete Features',
+     'description' => 'Delete multiple features from Chado',
+     'page callback' => 'drupal_get_form',
+     'page arguments' => array('tripal_feature_delete_form'),
+     'access arguments' => array('access administration pages'),
+     'type' => MENU_NORMAL_ITEM,
+   ); 
+
+   $items['admin/tripal/tripal_feature/sync'] = array(
+     'title' => ' Sync Features',
+     'description' => 'Sync features from Chado with Drupal',
+     'page callback' => 'drupal_get_form',
+     'page arguments' => array('tripal_feature_sync_form'),
+     'access arguments' => array('access administration pages'),
+     'type' => MENU_NORMAL_ITEM,
+   ); 
+
   // Adding Secondary Properties
 
 
@@ -2048,6 +2067,9 @@ function tripal_features_cleanup($dummy = NULL, $job_id = NULL) {
       $count++;
    }
    $interval = intval($count * 0.01);
+   if($interval > 1){
+      $interval = 1;
+   }
 
    // iterate through all of the chado_feature nodes and delete those  that aren't valid
    foreach($nodes as $nid){
@@ -2154,6 +2176,35 @@ function tripal_feature_job_describe_args($callback,$args){
       }
       $new_args['Analysis'] = $analysis[0]->name;
    }
+   if($callback == 'tripal_feature_delete_features'){
+      if($args[0]){
+         $organism = tripal_core_chado_select('organism',array('genus','species'),array('organism_id' => $args[0]));
+         $new_args['Organism'] = $organism[0]->genus." ". $organism[0]->species;
+      } else {
+         $new_args['Organism'] = '';
+      }
+
+      if($args[1]){
+         $analysis = tripal_core_chado_select('analysis',array('name'),array('analysis_id' => $args[1]));
+         $new_args['Analysis'] = $analysis[0]->name;
+      } else {
+         $new_args['Analysis'] = '';
+      }
+      
+      $new_args['Sequence Type'] = $args[2];
+      $new_args['Is Unique Name'] = $args[3];
+      $new_args['Features Names'] = $args[4];
+      
+   }
+   if($callback == 'tripal_feature_sync_features'){
+      if($args[0]){
+         $organism = tripal_core_chado_select('organism',array('genus','species'),array('organism_id' => $args[0]));
+         $new_args['Organism'] = $organism[0]->genus." ". $organism[0]->species;
+      } else {
+         $new_args['Organism'] = '';
+      }
+      $new_args['Feature Types'] = $args[1];
+   }
    return $new_args;
 }
 

+ 1 - 1
tripal_library/tripal_library.module

@@ -397,7 +397,7 @@ function theme_tripal_library_search_index ($node) {
       // get the libraries for the organism
       $previous_db = tripal_db_set_active('chado');
       $sql = "SELECT * FROM {library} L ".
-       	     "WHERE L.Organism_id = $node->organism_id";
+       	     "WHERE L.Organism_id = $node->organism->organism_id";
       $libraries = array();
       $results = db_query($sql);
       while($library = db_fetch_object($results)){

+ 26 - 1
tripal_organism/tripal_organism.api.inc

@@ -124,4 +124,29 @@ function tripal_organism_chado_organismprop_schema() {
   );
   
   return $description;
-}
+}
+/**
+ *  Returns a list of organisms that are currently synced with Drupal
+ * @ingroup tripal_organism_api
+ */
+function tripal_organism_get_synced() {
+
+   // use this SQL for getting synced organisms
+   $dsql =  "SELECT * FROM {chado_organism}";
+   $orgs = db_query($dsql);
+
+   // use this SQL statement for getting the organisms
+   $csql =  "SELECT * FROM {Organism} ".
+            "WHERE organism_id = %d";
+
+   $org_list = array();
+
+   // iterate through the organisms and build an array of those that are synced
+   while($org = db_fetch_object($orgs)){
+      $previous_db = tripal_db_set_active('chado');  // use chado database
+      $info = db_fetch_object(db_query($csql,$org->organism_id));
+      tripal_db_set_active($previous_db);  // now use drupal database
+      $org_list[] = $info;
+   }  
+   return $org_list;
+}

+ 0 - 25
tripal_organism/tripal_organism.module

@@ -1231,31 +1231,6 @@ function tripal_organism_taxonify_features ($organism_id = NULL, $job_id = NULL)
       $i++;
    }
 }
-/**
- *  Returns a list of organisms that are currently synced with Drupal
- * @ingroup tripal_organism
- */
-function tripal_organism_get_synced() {
-
-   // use this SQL for getting synced organisms
-   $dsql =  "SELECT * FROM {chado_organism}";
-   $orgs = db_query($dsql);
-
-   // use this SQL statement for getting the organisms
-   $csql =  "SELECT * FROM {Organism} ".
-            "WHERE organism_id = %d";
-
-   $org_list = array();
-
-   // iterate through the organisms and build an array of those that are synced
-   while($org = db_fetch_object($orgs)){
-      $previous_db = tripal_db_set_active('chado');  // use chado database
-      $info = db_fetch_object(db_query($csql,$org->organism_id));
-      tripal_db_set_active($previous_db);  // now use drupal database
-      $org_list[] = $info;
-   }  
-   return $org_list;
-}
 /**
  *
  * @ingroup tripal_organism