Преглед на файлове

All templates for the feature page are converted except featurepos and phenotype needs testing.

Stephen Ficklin преди 11 години
родител
ревизия
ee855ade6e
променени са 24 файла, в които са добавени 1013 реда и са изтрити 937 реда
  1. 2 1
      tripal_analysis/tripal_analysis.module
  2. 48 24
      tripal_core/api/tripal_core_chado.api.inc
  3. 2 12
      tripal_core/tripal_core.module
  4. 40 22
      tripal_feature/api/tripal_feature.api.inc
  5. 3 59
      tripal_feature/includes/tripal_feature.admin.inc
  6. 12 6
      tripal_feature/includes/tripal_feature.form.inc
  7. 73 55
      tripal_feature/includes/tripal_feature.gff_loader.inc
  8. 142 236
      tripal_feature/includes/tripal_feature.sync_features.inc
  9. 67 51
      tripal_feature/theme/tripal_feature/tripal_feature_alignments.tpl.php
  10. 46 41
      tripal_feature/theme/tripal_feature/tripal_feature_analyses.tpl.php
  11. 1 3
      tripal_feature/theme/tripal_feature/tripal_feature_base.tpl.php
  12. 0 28
      tripal_feature/theme/tripal_feature/tripal_feature_featureloc_sequences.tpl.php
  13. 1 2
      tripal_feature/theme/tripal_feature/tripal_feature_featurepos.tpl.php
  14. 48 35
      tripal_feature/theme/tripal_feature/tripal_feature_phenotypes.tpl.php
  15. 40 24
      tripal_feature/theme/tripal_feature/tripal_feature_properties.tpl.php
  16. 57 40
      tripal_feature/theme/tripal_feature/tripal_feature_references.tpl.php
  17. 116 64
      tripal_feature/theme/tripal_feature/tripal_feature_relationships.tpl.php
  18. 42 7
      tripal_feature/theme/tripal_feature/tripal_feature_sequence.tpl.php
  19. 11 43
      tripal_feature/theme/tripal_feature/tripal_feature_teaser.tpl.php
  20. 52 34
      tripal_feature/theme/tripal_feature/tripal_feature_terms.tpl.php
  21. 1 0
      tripal_feature/theme/tripal_organism/tripal_organism_feature_counts.tpl.php
  22. 208 139
      tripal_feature/tripal_feature.module
  23. 0 10
      tripal_organism/tripal_organism.install
  24. 1 1
      tripal_views/views/handlers/tripal_views_handler_filter_select_string.inc

+ 2 - 1
tripal_analysis/tripal_analysis.module

@@ -332,7 +332,7 @@ function chado_analysis_insert($node) {
   // if there is an analysis_id in the $node object then this must be a sync so
   // we can skip adding the analysis as it is already there, although
   // we do need to proceed with the rest of the insert
-  if (!property_exists($node,'analysis_id')) {
+  if (!property_exists($node, 'analysis_id')) {
 
     // Create a timestamp so we can insert it into the chado database
     $time  = $node->timeexecuted;
@@ -423,6 +423,7 @@ function chado_analysis_insert($node) {
     }
     $properties[$name][$index] = trim($node->new_value);
   }
+  
   // now add in the properties
   foreach ($properties as $property => $elements) {
     foreach ($elements as $rank => $value) {

+ 48 - 24
tripal_core/api/tripal_core_chado.api.inc

@@ -12,6 +12,23 @@ define('TRIPAL_NOTICE',5);
 define('TRIPAL_INFO',6);
 define('TRIPAL_DEBUG',7);
 
+
+/**
+ * This function is used to set the global Chado variables
+ */
+function tripal_core_set_globals() {
+  // these global variables are meant to be accessed by all Tripal
+  // modules to find the chado version installed and if Chado is local.
+  // these variables are stored as globals rather than using the drupal_set_variable
+  // functions because the Drupal functions make databaes queries and for long
+  // running loaders we don't want those queries repeatedly.
+  $GLOBALS["chado_is_installed"]  = tripal_core_is_chado_installed();
+  if ($GLOBALS["chado_is_installed"]) {
+    $GLOBALS["chado_is_local"]      = tripal_core_is_chado_local();
+    $GLOBALS["chado_version"]       = tripal_core_get_chado_version();
+    $GLOBALS["exact_chado_version"] = tripal_core_get_chado_version(TRUE);
+  }
+}
 /**
  * Provide better error notice for Tripal
  * @param $type
@@ -1449,7 +1466,7 @@ function tripal_core_chado_get_foreign_key($table_desc, $field, $values, $option
  */
 function tripal_core_generate_chado_var($table, $values, $base_options = array()) {
   $all = new stdClass();
-
+  
   $return_array = 0;
   if (array_key_exists('return_array', $base_options)) {
     $return_array = 1;
@@ -1559,9 +1576,10 @@ function tripal_core_generate_chado_var($table, $values, $base_options = array()
         $sql = "
           SELECT $table_primary_key, nid
           FROM {chado_$table}
-          WHERE $table_primary_key = :$table_primary_key";
+          WHERE $table_primary_key = :$table_primary_key
+        ";
         $mapping = db_query($sql, array(":$table_primary_key" => $object->{$table_primary_key}))->fetchObject();
-        if ($mapping->{$table_primary_key}) {
+        if ($mapping and $mapping->$table_primary_key) {
           $object->nid = $mapping->nid;
           $object->expandable_nodes[] = $table;
         }
@@ -1609,28 +1627,30 @@ function tripal_core_generate_chado_var($table, $values, $base_options = array()
             if (is_array($include_fk)) {
               $options['include_fk'] = $include_fk[$foreign_key];
             }
+
             $foreign_object = tripal_core_generate_chado_var($foreign_table, $foreign_values, $options);
+            
             // add the foreign record to the current object in a nested manner
             $object->{$foreign_key} = $foreign_object;
             // Flatten expandable_x arrays so only in the bottom object
-            if (is_array($object->{$foreign_key}->expandable_fields)) {
+            if (property_exists($object->{$foreign_key}, 'expandable_fields') and is_array($object->{$foreign_key}->expandable_fields)) {
               $object->expandable_fields = array_merge(
-              $object->expandable_fields,
-              $object->{$foreign_key}->expandable_fields
+                $object->expandable_fields,
+                $object->{$foreign_key}->expandable_fields
               );
               unset($object->{$foreign_key}->expandable_fields);
             }
-            if (is_array($object->{$foreign_key}->expandable_tables)) {
+            if (property_exists($object->{$foreign_key}, 'expandable_tables') and is_array($object->{$foreign_key}->expandable_tables)) {
               $object->expandable_tables = array_merge(
-              $object->expandable_tables,
-              $object->{$foreign_key}->expandable_tables
+                $object->expandable_tables,
+                $object->{$foreign_key}->expandable_tables
               );
               unset($object->{$foreign_key}->expandable_tables);
             }
-            if (is_array($object->{$foreign_key}->expandable_nodes)) {
+            if (property_exists($object->{$foreign_key}, 'expandable_nodes') and is_array($object->{$foreign_key}->expandable_nodes)) {
               $object->expandable_nodes = array_merge(
-              $object->expandable_nodes,
-              $object->{$foreign_key}->expandable_nodes
+                $object->expandable_nodes,
+                $object->{$foreign_key}->expandable_nodes
               );
               unset($object->{$foreign_key}->expandable_nodes);
             }
@@ -1697,7 +1717,7 @@ function tripal_core_generate_chado_var($table, $values, $base_options = array()
  *     multiple records exist.
  *   - include_fk:
  *     an array of FK relationships to follow. By default, the
- *     tripal_core_chado_select function will follow all FK relationships but this
+ *     tripal_core_expand_chado_vars function will follow all FK relationships but this
  *     may generate more queries then is desired slowing down this function call when
  *     there are lots of FK relationships to follow.  Provide an array specifying the
  *     fields to include.  For example, if expanding a property table (e.g. featureprop)
@@ -1817,21 +1837,22 @@ function tripal_core_expand_chado_vars($object, $type, $to_expand, $table_option
           // generate a new object for this table using the FK values in the base table.
           $new_options = $table_options;
           $foreign_object = tripal_core_generate_chado_var($foreign_table, array($left => $object->{$right}), $new_options);
-
+          
           // if the generation of the object was successful, update the base object to include it.
           if ($foreign_object) {
-            // in the case where the foreign key relationships exists more
-            // than once with the same table we want to alter the array structure. rather than
-            // add the object with a key of the table name, we will add the FK field name in between
+            // in the case where the foreign key relationship exists more
+            // than once with the same table we want to alter the array structure to
+            // include the field name.
             if (count($foreign_table_desc['foreign keys'][$base_table]['columns']) > 1) {
-              if (!is_object($object->{$foreign_table})) {
+              if (!property_exists($object, $foreign_table)) {
                 $object->{$foreign_table} = new stdClass();
               }
               $object->{$foreign_table}->{$left} = $foreign_object;
               $object->expanded = $to_expand;
+              
             }
             else {
-              if (!property_exists($object, $foreign_table) or !is_object($object->{$foreign_table})) {
+              if (!property_exists($object, $foreign_table)) {
                 $object->{$foreign_table} = new stdClass();
               }
               $object->{$foreign_table} = $foreign_object;
@@ -1840,8 +1861,11 @@ function tripal_core_expand_chado_vars($object, $type, $to_expand, $table_option
           }
           // if the object returned is NULL then handle that
           else {
+            // in the case where the foreign key relationship exists more
+            // than once with the same table we want to alter the array structure to
+            // include the field name.
             if (count($foreign_table_desc['foreign keys'][$base_table]['columns']) > 1) {
-              if (!is_object($object->{$foreign_table})) {
+              if (!property_exists($object, $foreign_table)) {
                 $object->{$foreign_table} = new stdClass();
               }
               $object->{$foreign_table}->{$left} = NULL;
@@ -1912,8 +1936,8 @@ function tripal_core_expand_chado_vars($object, $type, $to_expand, $table_option
       return FALSE;
   }
 
-  //move extended array downwards-------------------------------------------------------------------
-  if (!$object->expanded) {
+  // move extended array downwards
+  if (!property_exists($object, 'expanded')) {
     //if there's no extended field then go hunting for it
     foreach ( (array)$object as $field_name => $field_value) {
       if (is_object($field_value)) {
@@ -1925,7 +1949,7 @@ function tripal_core_expand_chado_vars($object, $type, $to_expand, $table_option
     }
   }
   //try again becasue now we might have moved it down
-  if ($object->expanded) {
+  if (property_exists($object, 'expanded')) {
     $expandable_name = 'expandable_' . $type . 's';
     if ($object->{$expandable_name}) {
       $key_to_remove = array_search($object->expanded, $object->{$expandable_name});
@@ -2762,7 +2786,7 @@ function tripal_core_get_chado_version($exact = FALSE, $warn_if_unsupported = FA
  * @ingroup tripal_core_api
  */
 function tripal_core_get_chado_table_schema($table) {
-
+  
   // first get the chado version that is installed
   $v = $GLOBALS["chado_version"];
 

+ 2 - 12
tripal_core/tripal_core.module

@@ -50,6 +50,8 @@ require_once "includes/chado_install.inc";
 require_once "includes/form_elements.inc";
 
 
+tripal_core_set_globals();  
+
 /**
  * Implements hook_init().
  * Used to set the search_path, create default content and set default variables.
@@ -63,18 +65,6 @@ function tripal_core_init() {
   drupal_add_js(drupal_get_path('module', 'tripal_core') . '/theme/js/tripal.js');
   drupal_add_css(drupal_get_path('module', 'tripal_core') . '/theme/css/tripal.css');
 
-  // these global variables are meant to be accessed by all Tripal
-  // modules to find the chado version installed and if Chado is local.
-  // these variables are stored as globals rather than using the drupal_set_variable
-  // functions because the Drupal functions make databaes queries and for long
-  // running loaders we don't want those queries repeatedly.
-  $GLOBALS["chado_is_installed"]  = tripal_core_is_chado_installed();
-  if ($GLOBALS["chado_is_installed"]) {
-    $GLOBALS["chado_is_local"]      = tripal_core_is_chado_local();
-    $GLOBALS["chado_version"]       = tripal_core_get_chado_version();
-    $GLOBALS["exact_chado_version"] = tripal_core_get_chado_version(TRUE);
-  }
-  
   
   // create the 'tripal' controlled volcabulary in chado but only if it doesn't already exist, and
   // only if the chado database is present.

+ 40 - 22
tripal_feature/api/tripal_feature.api.inc

@@ -850,18 +850,38 @@ function tripal_feature_get_feature_relationships($feature) {
   // expand the feature object to include the feature relationships.
   $options = array(
     'return_array' => 1,
-    'order_by'     => array('rank' => 'ASC'),
+    'order_by' => array('rank' => 'ASC'),
+    // we don't want to fully recurse we only need information about the 
+    // relationship type and the object and subject features (including feature type
+    // and organism)
+    'include_fk' => array(
+      'type_id' => 1,
+      'object_id' => array(
+        'type_id' => 1,
+        'organism_id' => 1
+      ),
+      'subject_id'  => array(
+        'type_id' => 1,
+        'organism_id' => 1
+      ),
+    ),
   );
-  $feature = tripal_core_expand_chado_vars($feature, 'table',
-    'feature_relationship', $options);
-
+  $feature = tripal_core_expand_chado_vars($feature, 'table', 'feature_relationship', $options);
+  
   // get the subject relationships
   $srelationships = $feature->feature_relationship->subject_id;
   $orelationships = $feature->feature_relationship->object_id;
   
+  
   // get alignment as child. The $feature->featureloc element
   // is already populated from the alignment preprocess function
-  $feature = tripal_core_expand_chado_vars($feature, 'table', 'featureloc');
+  $options = array(
+    'include_fk' => array(
+      'srcfeature_id' => 1,
+      'feature_id' => 1,
+    ),
+  );
+  $feature = tripal_core_expand_chado_vars($feature, 'table', 'featureloc', $options);
   $cfeaturelocs = $feature->featureloc->feature_id;
   if (!$cfeaturelocs) {
      $cfeaturelocs = array();
@@ -872,18 +892,14 @@ function tripal_feature_get_feature_relationships($feature) {
   
   // prepare the SQL statement to get the featureloc for the 
   // feature in the relationships. 
-  $connection = tripal_db_persistent_chado();
-  $psql = " 
-    PREPARE sel_featureloc_preprocess_relationships (int, int) AS 
+  $flrels_sql = "  
     SELECT 
       FL.featureloc_id, F.name as srcfeature_name, FL.srcfeature_id,
       FL.feature_id, FL.fmin, FL.fmax, FL.strand, FL.phase
-    FROM featureloc FL 
-      INNER JOIN feature F ON F.feature_id = FL.srcfeature_id
-    WHERE FL.feature_id = $1 and FL.srcfeature_id = $2
+    FROM {featureloc} FL 
+      INNER JOIN {feature} F ON F.feature_id = FL.srcfeature_id
+    WHERE FL.feature_id = :feature_id and FL.srcfeature_id = :srcfeature_id
   ";
-  tripal_core_chado_prepare('sel_featureloc_preprocess_relationships', $psql, array('int', 'int'));
-
   
   // combine both object and subject relationshisp into a single array
   $relationships = array();
@@ -898,11 +914,12 @@ function tripal_feature_get_feature_relationships($feature) {
        // same landmark feature.
        $rel->child_featurelocs = array();     
        foreach ($cfeaturelocs as $featureloc) {
-          $res = chado_query("EXECUTE sel_featureloc_preprocess_relationships (:relationship, :featureloc)", 
-            array(':relationship' => $relationship->subject_id->feature_id, ':featureloc' => $featureloc->srcfeature_id->feature_id));        
+          $res = chado_query($flrels_sql, array(':feature_id' => $relationship->subject_id->feature_id, ':srcfeature_id' => $featureloc->srcfeature_id->feature_id));        
           while ($loc = $res->fetchObject()) {
              // add in the node id of the src feature if it exists and save this location
-             $loc->nid = $featureloc->srcfeature_id->nid;
+             if (property_exists($featureloc->srcfeature_id, 'nid')) {
+               $loc->nid = $featureloc->srcfeature_id->nid;
+             }
              $rel->child_featurelocs[] = $loc;
           }
        }
@@ -914,7 +931,7 @@ function tripal_feature_get_feature_relationships($feature) {
        
        // get the node id of the subject
        $sql = "SELECT nid FROM {chado_feature} WHERE feature_id = :feature_id";
-       $n = db_query($sql, array('feature_id' => $relationship->subject_id->feature_id))->fetchObject();
+       $n = db_query($sql, array(':feature_id' => $relationship->subject_id->feature_id))->fetchObject();
        if ($n) {
           $rel->record->nid = $n->nid;
        }
@@ -936,12 +953,13 @@ function tripal_feature_get_feature_relationships($feature) {
        // get locations where this feature overlaps with the parent
        $rel->parent_featurelocs = array();     
        foreach ($cfeaturelocs as $featureloc) {
-          $res = chado_query("EXECUTE sel_featureloc_preprocess_relationships (:feature_id, :srcfeature_id)", 
-            array('feature_id' => $relationship->object_id->feature_id, ':srcfeature_id' => $featureloc->srcfeature_id->feature_id));
+          $res = chado_query($flrels_sql, array(':feature_id' => $relationship->object_id->feature_id, ':srcfeature_id' => $featureloc->srcfeature_id->feature_id));
           while ($loc = $res->fetchObject()) {
-             // add in the node id of the src feature if it exists and save this location
-             $loc->nid = $featureloc->srcfeature_id->nid;
-             $rel->parent_featurelocs[] = $loc;
+            // add in the node id of the src feature if it exists and save this location
+            if (property_exists($featureloc->srcfeature_id, 'nid')) {
+              $loc->nid = $featureloc->srcfeature_id->nid;
+            }
+            $rel->parent_featurelocs[] = $loc;
           }
        }
        $rel->record = $relationship;

+ 3 - 59
tripal_feature/includes/tripal_feature.admin.inc

@@ -84,7 +84,7 @@ function tripal_feature_admin() {
        '#type'        => 'textarea',
        '#description' => t("Enter the Sequence Ontology (SO) terms for the feature types that " .
                            "will be shown in the feature browser."),
-       '#default_value' => variable_get('chado_browser_feature_types', 'gene contig'),
+       '#default_value' => variable_get('chado_browser_feature_types', 'gene mRNA'),
     );
 
 
@@ -156,8 +156,7 @@ function tripal_feature_admin() {
     );
 
     get_tripal_feature_admin_form_taxonomy_set($form);
-    get_tripal_feature_admin_form_reindex_set($form);
-    get_tripal_feature_admin_form_cleanup_set($form);
+//    get_tripal_feature_admin_form_reindex_set($form);
 /*  }
   else {
     $form['notice'] = array(
@@ -191,11 +190,6 @@ function tripal_feature_admin_validate($form, &$form_state) {
 
   switch ($form_state['values']['op']) {
 
-    case  t('Sync all Features') :
-      tripal_add_job('Sync all features', 'tripal_feature',
-        'tripal_feature_sync_features', $job_args, $user->uid);
-      break;
-
     case t('Set/Reset Taxonomy for all feature nodes') :
       tripal_add_job('Set all feature taxonomy', 'tripal_feature',
         'tripal_features_set_taxonomy', $job_args, $user->uid);
@@ -206,11 +200,6 @@ function tripal_feature_admin_validate($form, &$form_state) {
         'tripal_features_reindex', $job_args, $user->uid);
       break;
 
-    case t('Clean up orphaned features') :
-      tripal_add_job('Cleanup orphaned features', 'tripal_feature',
-        'tripal_features_cleanup', $job_args, $user->uid);
-      break;
-
     case t('Set Browser') :
       variable_set('tripal_feature_browse_setting', $form_state['values']['browse_features']);
       variable_set('tripal_library_feature_browse_setting', $form_state['values']['browse_features_library']);
@@ -230,37 +219,7 @@ function tripal_feature_admin_validate($form, &$form_state) {
   }
 
 }
-/**
- *
- *
- * @ingroup tripal_feature
- */
-function get_tripal_feature_admin_form_cleanup_set(&$form) {
-  $form['cleanup'] = array(
-    '#type' => 'fieldset',
-    '#title' => t('Clean Up'),
-    '#collapsible' => TRUE,
-    '#collapsed' => TRUE,
-  );
-  $form['cleanup']['description'] = array(
-    '#type' => 'item',
-    '#value' => t("With Drupal and chado residing in different databases " .
-      "it is possible that nodes in Drupal and features in Chado become " .
-      "\"orphaned\".  This can occur if a feature node in Drupal is " .
-      "deleted but the corresponding chado feature is not and/or vice " .
-      "versa.  The Cleanup function will also remove nodes for features " .
-      "that are not in the list of allowed feature types as specified " .
-      "above.  This is helpful when a feature type needs to be " .
-      "removed but was previously present as Drupal nodes. " .
-      "Click the button below to resolve these discrepancies."),
-    '#weight' => 1,
-  );
-  $form['cleanup']['button'] = array(
-    '#type' => 'submit',
-    '#value' => t('Clean up orphaned features'),
-    '#weight' => 2,
-  );
-}
+
 
 /**
  *
@@ -591,22 +550,7 @@ function tripal_feature_set_taxonomy($node, $feature_id) {
 
 }
 
-/**
- *
- * Remove orphaned drupal nodes
- *
- * @param $dummy
- *   Not Used -kept for backwards compatibility
- * @param $job_id
- *   The id of the tripal job executing this function
- *
- * @ingroup tripal_feature
- */
-function tripal_features_cleanup($dummy = NULL, $job_id = NULL) {
-
-  return tripal_core_clean_orphaned_nodes('feature', $job_id);
 
-}
 /**
  *  This function is an extension of the chado_feature_view by providing
  *  the markup for the feature object THAT WILL BE INDEXED.

+ 12 - 6
tripal_feature/includes/tripal_feature.form.inc

@@ -210,14 +210,13 @@ function chado_feature_validate($node, &$form_state) {
   
   $result = 0;
 
-  // make sure the feature type is a real sequence ontology term
-  $type = tripal_cv_get_cvterm_by_name($node->feature_type, NULL, 'sequence');
-  if (!$type) {
-    form_set_error('feature_type', t("The feature type is not a valid name from the Sequence Ontology."));
-  }
-
   // CASE A: if the nid exists then this is an update
   if (property_exists($node, 'nid')) {
+    // make sure the feature type is a real sequence ontology term
+    $type = tripal_cv_get_cvterm_by_name($node->feature_type, NULL, 'sequence');
+    if (!$type) {
+      form_set_error('feature_type', t("The feature type is not a valid name from the Sequence Ontology."));
+    }
     
     // if this is an update, we want to make sure that a different feature for
     // the organism doesn't already have this uniquename. We don't want to give
@@ -249,6 +248,13 @@ function chado_feature_validate($node, &$form_state) {
     }
     else {
       // CASE C: We are validating a form for inserting a new node
+      
+      // make sure the feature type is a real sequence ontology term
+      $type = tripal_cv_get_cvterm_by_name($node->feature_type, NULL, 'sequence');
+      if (!$type) {
+        form_set_error('feature_type', t("The feature type is not a valid name from the Sequence Ontology."));
+      }
+      
       // if this is an insert then we just need to make sure this name doesn't
       // already exist for this organism if it does then we need to throw an error
       $sql = "

+ 73 - 55
tripal_feature/includes/tripal_feature.gff_loader.inc

@@ -375,22 +375,15 @@ function tripal_feature_load_gff3($gff_file, $organism_id, $analysis_id,
     $intv_read = 0;
     
     // prepare the statement used to get the cvterm for each feature.
-    $psql = "
-      PREPARE sel_cvterm_idnasy (int, text, text) AS
+    $sel_cvterm_sql = "
       SELECT CVT.cvterm_id, CVT.cv_id, CVT.name, CVT.definition,
         CVT.dbxref_id, CVT.is_obsolete, CVT.is_relationshiptype
       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.cv_id = $1 and 
-       (lower(CVT.name) = lower($2) or lower(CVTS.synonym) = lower($3))
+      WHERE CV.cv_id = :cv_id and 
+       (lower(CVT.name) = lower(:name) or lower(CVTS.synonym) = lower(:synonym))
      ";
-     $status = chado_query($psql);
-     if (!$status) {
-       watchdog('T_gff3_loader', 'cannot prepare statement \'sel_cvterm_idnasy\'.', 
-         array(), WATCHDOG_ERROR);
-       return '';
-     }  
   
     // iterate through each line of the GFF file
     print "Parsing Line $line_num (0.00%). Memory: " . number_format(memory_get_usage()) . " bytes\r";
@@ -419,7 +412,7 @@ function tripal_feature_load_gff3($gff_file, $organism_id, $analysis_id,
           // we're done because this is a delete operation so break out of the loop.
           break;         
         }
-        tripal_feature_load_gff3_fasta($fh, $interval, $num_read, $intv_read, $line_num);
+        tripal_feature_load_gff3_fasta($fh, $interval, $num_read, $intv_read, $line_num, $filesize, $job);
         continue;
       }
       // if the ##sequence-region line is present then we want to add a new feature
@@ -428,8 +421,7 @@ function tripal_feature_load_gff3($gff_file, $organism_id, $analysis_id,
         $rstart = $region_matches[2];
         $rend = $region_matches[3];
         if ($landmark_type) {
-          $result = chado_query("EXECUTE sel_cvterm_idnasy (:cv_id, :name, :synonym)", 
-            array(':cv_id' => $cv->cv_id, ':name' => $landmark_type, ':synonym' => $landmark_type));
+          $result = chado_query($sel_cvterm_sql, array(':cv_id' => $cv->cv_id, ':name' => $landmark_type, ':synonym' => $landmark_type));
           $cvterm = $result->fetchObject();
           if (!$cvterm) {
             watchdog('T_gff3_loader', 'cannot find feature type \'%landmark_type\' on line %line_num of the GFF file', 
@@ -492,10 +484,8 @@ function tripal_feature_load_gff3($gff_file, $organism_id, $analysis_id,
       }
       if (strcmp($phase, '.') == 0) {
         $phase = '';
-      }
-    
-      $result = chado_query("EXECUTE sel_cvterm_idnasy (:cv_id, :name, :synonym)", 
-        array(':cv_id' => $cv->cv_id, ':name' => $type, ':synonym' => $type));
+      }    
+      $result = chado_query($sel_cvterm_sql, array(':cv_id' => $cv->cv_id, ':name' => $type, ':synonym' => $type));
   
       $cvterm = $result->fetchObject();
       if (!$cvterm) {
@@ -815,9 +805,9 @@ function tripal_feature_load_gff3($gff_file, $organism_id, $analysis_id,
           F.uniquename, FL.strand 
         FROM {tripal_gff_temp} TGT 
           INNER JOIN {feature} F                ON TGT.feature_id = F.feature_id
-          INNER JOIN {feature_relationship} FR  ON FR.object_id = TGT.feature_id
-          INNER JOIN {cvterm} CVT               ON CVT.cvterm_id = FR.type_id  
-          INNER JOIN {featureloc} FL            ON FL.feature_id = F.feature_id    
+          INNER JOIN {feature_relationship} FR  ON FR.object_id   = TGT.feature_id
+          INNER JOIN {cvterm} CVT               ON CVT.cvterm_id  = FR.type_id  
+          INNER JOIN {featureloc} FL            ON FL.feature_id  = F.feature_id    
         WHERE CVT.name = 'part_of'
       ";
       $parents = chado_query($sql);
@@ -833,17 +823,26 @@ function tripal_feature_load_gff3($gff_file, $organism_id, $analysis_id,
       // now set the rank of any parent/child relationships.  The order is based
       // on the fmin.  The start rank is 1.  This allows features with other
       // relationships to be '0' (the default), and doesn't interfer with the
-      // ordering defined here.        
+      // ordering defined here.  
+      $num_recs = $parents->rowCount();
+      $i = 1;
+      $interval = intval($num_recs * 0.0001);
+      if ($interval == 0) {
+        $interval = 1;
+      }
+      $percent = sprintf("%.2f", ($i / $num_recs) * 100);
+      print "Setting $i of $num_recs (" . $percent . "%). Memory: " . number_format(memory_get_usage()) . " bytes.\r";
+      
       while ($parent = $parents->fetchObject()) {
         
-        // get the children
-        if ($connection) {      
-          $result = chado_query($sel_gffchildren_sql, array(':feature_id' => $parent->feature_id));
-        }
-        else {
-          $result = chado_query($sql, array(':feature_id' => $parent->feature_id));
+        if ($i % $interval == 0) {
+          $percent = sprintf("%.2f", ($i / $num_recs) * 100);
+          print "Setting $i of $num_recs (" . $percent . "%). Memory: " . number_format(memory_get_usage()) . " bytes.\r";
         }
         
+        // get the children
+        $result = chado_query($sel_gffchildren_sql, array(':feature_id' => $parent->feature_id));
+        
         // build an array of the children
         $children = array();
         while ($child = $result->fetchObject()) {
@@ -875,6 +874,7 @@ function tripal_feature_load_gff3($gff_file, $organism_id, $analysis_id,
           tripal_core_chado_update('feature_relationship', $match, $values);
           $rank++;
         }
+        $i++;
       }
     }
   }
@@ -891,7 +891,7 @@ function tripal_feature_load_gff3($gff_file, $organism_id, $analysis_id,
     return 0;
   }
 
-  print "Done\n";
+  print "\nDone\n";
   return 1;
 }
 /**
@@ -1712,15 +1712,13 @@ function tripal_feature_load_gff3_property($feature, $property, $value) {
 /*
  * 
  */
-function tripal_feature_load_gff3_fasta($fh, $interval, &$num_read, &$intv_read, &$line_num) {
-  print "Loading FASTA sequences\n";
+function tripal_feature_load_gff3_fasta($fh, $interval, &$num_read, &$intv_read, &$line_num, $filesize, $job) {
+  print "\nLoading FASTA sequences\n";
   $residues = '';
-  $sel_gfftemp_un_sql = " 
-    SELECT feature_id FROM tripal_gff_temp
-    WHERE uniquename = :uname
-  ";
   $id = NULL;
   
+  $percent = sprintf("%.2f", ($num_read / $filesize) * 100);
+  print "Parsing Line $line_num (" . $percent . "%). Memory: " . number_format(memory_get_usage()) . " bytes.\r";
   // iterate through the remaining lines of the file
   while ($line = fgets($fh)) {
     
@@ -1741,45 +1739,49 @@ function tripal_feature_load_gff3_fasta($fh, $interval, &$num_read, &$intv_read,
     
     // if we encounter a definition line then get the name, uniquename,
     // accession and relationship subject from the definition line
-    if (preg_match('/^>/', $line)) {   
-      // if we are beginning a new sequence then save the last one we 
-      // just finished.     
-             
+    if (preg_match('/^>/', $line)) {
+      
+      // if we are beginning a new sequence then save to the database the last one we just finished.     
       if ($id) {
-        $result = chado_query($sel_gfftemp_un_sql, array(':uname' => $id));
-        if (!$result) {
+        $values = array('uniquename' => $id);
+        $result = tripal_core_chado_select('tripal_gff_temp', array('*'), $values); 
+        if (count($result) == 0) {
           watchdog('T_gff3_loader', 'Cannot find feature to assign FASTA sequence: %uname', 
-             array('%uname' => $id), WATCHDOG_WARNING); 
+             array('%uname' => $id), WATCHDOG_WARNING);
         }
-        // if we have a feature then add the residues
-        else {    
-          $feature = $result->fetchObject();    
+        else {
+          // if we have a feature then add the residues
+          $feature = $result[0];
           $values = array('residues' => $residues);
           $match = array('feature_id' => $feature->feature_id);
           tripal_core_chado_update('feature', $match, $values);
         }
       }
+      
       // get the feature ID for this ID from the tripal_gff_temp table
-      $id = preg_replace('/^>(.*)$/', '\1', $line);      
+      $id = preg_replace('/^>(.*)$/', '\1', $line);
       $residues = '';
     }
     else {
       $residues .= trim($line);
     }
   } 
+  
   // add in the last sequence
-  $result = chado_query($sel_gfftemp_un_sql, array(':uname' => $id));
-  if (!$result) {
+  $values = array('uniquename' => $id);
+  $result = tripal_core_chado_select('tripal_gff_temp', array('*'), $values); 
+  if (count($result) == 0) {
     watchdog('T_gff3_loader', 'Cannot find feature to assign FASTA sequence: %uname', 
-       array('%uname' => $id), WATCHDOG_WARNING); 
+       array('%uname' => $id), WATCHDOG_WARNING);
   }
-  // if we have a feature then add the residues
-  else {        
-    $feature = $result->fetchObject();    
+  else {
+    // if we have a feature then add the residues
+    $feature = $result[0];
     $values = array('residues' => $residues);
     $match = array('feature_id' => $feature->feature_id);
     tripal_core_chado_update('feature', $match, $values);
-  } 
+  }
+
 }
 
 /*
@@ -1878,14 +1880,30 @@ function tripal_feature_load_gff3_target($feature, $tags, $target_organism_id, $
            'name' => 'sequence',
         )
       );
+      
+      // get the cvterm_id for the target type
       $type = tripal_core_chado_select('cvterm', array('cvterm_id'), $values);
       if (count($type) == 1) {
         $t_type_id = $type[0]->cvterm_id;
       }
       else {
-        watchdog('T_gff3_loader', "The target_type attribute does not exist in the sequence ontology: %type. ", 
-          array('%type' => $gff_target_type), WATCHDOG_WARNING);
-        $t_type_id = '';
+        // check to see if this is a synonym
+        $sql = "
+          SELECT CVTS.cvterm_id
+          FROM {cvtermsynonym} CVTS
+            INNER JOIN {cvterm} CVT ON CVT.cvterm_id = CVTS.cvterm_id
+            INNER JOIN {cv} CV      ON CV.cv_id = CVT.cv_id 
+          WHERE CV.name = 'sequence' and CVTS.synonym = :synonym
+        ";
+        $synonym = chado_query($sql, array(':synonym' => $gff_target_type))->fetchObject();
+        if ($synonym) {
+          $t_type_id = $synonym->cvterm_id;
+        }
+        else {
+          watchdog('T_gff3_loader', "The target_type attribute does not exist in the sequence ontology: %type. ", 
+            array('%type' => $gff_target_type), WATCHDOG_WARNING);
+          $t_type_id = '';
+        }
       }
     }                       
     

+ 142 - 236
tripal_feature/includes/tripal_feature.sync_features.inc

@@ -5,41 +5,13 @@
  * @todo Add file header description
  */
 
-
-# This script can be run as a stand-alone script to sync all the features from chado to drupal
-// Parameter f specifies the feature_id to sync
-// -f 0 will sync all features
-
-$arguments = getopt("f:t:");
-
-if (isset($arguments['f']) and isset($arguments['t']) and $arguments['t'] == 'chado_feature') {
-  $drupal_base_url = parse_url('http://www.example.com');
-  $_SERVER['HTTP_HOST'] = $drupal_base_url['host'];
-  $_SERVER['REQUEST_URI'] = $_SERVER['SCRIPT_NAME'] = $_SERVER['PHP_SELF'];
-  $_SERVER['REMOTE_ADDR'] = NULL;
-  $_SERVER['REQUEST_METHOD'] = NULL;
-
-  require_once 'includes/bootstrap.inc';
-  drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
-
-  $feature_id = $arguments['f'];
-
-  if ($feature_id > 0) {
-    tripal_feature_sync_feature($feature_id);
-  }
-  else {
-    print "syncing all features...\n";
-    tripal_feature_sync_features();
-  }
-}
 /**
  *
  */
 function tripal_feature_sync_form() {
 
   $form['description'] = array(
-  '#type' => 'item',
-  '#value' => t("Add feature types, optionally select an organism and " .
+  '#markup' => 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 " .
@@ -57,7 +29,7 @@ function tripal_feature_sync_form() {
        "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_sync_feature_types', 'gene contig'),
+    '#default_value' => variable_get('chado_sync_feature_types', 'gene mRNA'),
   );
 
   // get the list of organisms
@@ -80,17 +52,49 @@ function tripal_feature_sync_form() {
     '#value' => t('Sync all Features'),
     '#weight' => 3,
   );
+  
+  get_tripal_feature_admin_form_cleanup_set($form);
 
   return $form;
 }
+
+/**
+ *
+ *
+ * @ingroup tripal_feature
+ */
+function get_tripal_feature_admin_form_cleanup_set(&$form) {
+  $form['cleanup'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Clean Up'),
+    '#collapsible' => FALSE,
+    '#collapsed' => FALSE,
+  );
+  $form['cleanup']['description'] = array(
+    '#markup' => t("With Drupal and chado residing in different databases " .
+        "it is possible that nodes in Drupal and features in Chado become " .
+        "\"orphaned\".  This can occur if a feature node in Drupal is " .
+        "deleted but the corresponding chado feature is not and/or vice " .
+        "versa.  The Cleanup function will also remove nodes for features " .
+        "that are not in the list of allowed feature types as specified " .
+        "above.  This is helpful when a feature type needs to be " .
+        "removed but was previously present as Drupal nodes. " .
+        "Click the button below to resolve these discrepancies."),
+    '#weight' => 1,
+  );
+  $form['cleanup']['button'] = array(
+    '#type' => 'submit',
+    '#value' => t('Clean up orphaned features'),
+    '#weight' => 2,
+  );
+}
+
 /**
  *
  */
 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
 }
 /**
  *
@@ -101,20 +105,27 @@ function tripal_feature_sync_form_submit($form, &$form_state) {
 
   $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');
+  
+  switch ($form_state['values']['op']) {
+    case  t('Sync all Features') :
+      $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_set('chado_sync_feature_types', $feature_types);    
+      tripal_add_job($title, 'tripal_feature', 'tripal_feature_sync_features', $job_args, $user->uid);
+      break;
+      
+    case t('Clean up orphaned features') :
+      $job_args = array();
+      tripal_add_job('Cleanup orphaned features', 'tripal_feature',
+      'tripal_features_cleanup', $job_args, $user->uid);
+      break;
   }
-
-  variable_set('chado_sync_feature_types', $feature_types);
-
-  tripal_add_job($title, 'tripal_feature', 'tripal_feature_sync_features', $job_args, $user->uid);
 }
 /**
  *  
@@ -300,13 +311,13 @@ function tripal_feature_get_feature_url($node, $url_alias = NULL) {
 function tripal_feature_sync_features($max_sync = 0, $organism_id = NULL,
   $feature_types = NULL, $job_id = NULL) {
   
-  $i = 0;
-
+  global $user;
+    
   // 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.
   if (!$feature_types) {
-    $allowed_types = variable_get('chado_sync_feature_types', 'gene contig');
+    $allowed_types = variable_get('chado_sync_feature_types', 'gene mRNA');
   }
   else {
     $allowed_types = $feature_types;
@@ -315,11 +326,14 @@ function tripal_feature_sync_features($max_sync = 0, $organism_id = NULL,
 
   print "Looking for features of type: $allowed_types\n";
 
-  # TODO: fix the hard-coding of variables in this SQL statement
   $so_terms = split(' ', $allowed_types);
   $where_cvt = "";
+  $args = array();
+  $i = 0;
   foreach ($so_terms as $term) {
-    $where_cvt .= "CVT.name = '$term' OR ";
+    $where_cvt .= "CVT.name = :term$i OR ";
+    $args[":term$i"] = $term;
+    $i++;
   }
   $where_cvt = drupal_substr($where_cvt, 0, drupal_strlen($where_cvt)-3);  # strip trailing 'OR'
 
@@ -327,218 +341,110 @@ function tripal_feature_sync_features($max_sync = 0, $organism_id = NULL,
   // those organisms
   $orgs = tripal_organism_get_synced();
   $where_org = "";
+  $i = 0;
   foreach ($orgs as $org) {
     if ($organism_id) {
       if ($org->organism_id and $org->organism_id == $organism_id) {
-        $where_org .= "F.organism_id = $org->organism_id OR ";
+        $where_org .= "F.organism_id = :org_id$i OR ";
+        $args[":org_id$i"] = $org->organism_id;
       }
     }
     else {
-    if ($org->organism_id) {
-      $where_org .= "F.organism_id = $org->organism_id OR ";
-    }
+      if ($org->organism_id) {
+        $where_org .= "F.organism_id = :org_id$i OR ";
+        $args[":org_id$i"] = $org->organism_id;
+      }
     }
+    $i++;
   }
   $where_org = drupal_substr($where_org, 0, drupal_strlen($where_org)-3);  # strip trailing 'OR'
 
-  // use this SQL statement to get the features that we're going to upload
+  // get the list of features that we will sync
   $sql = "
-    SELECT feature_id 
-    FROM {FEATURE} F 
-      INNER JOIN {Cvterm} CVT ON F.type_id = CVT.cvterm_id 
-      INNER JOIN {CV} on CV.cv_id = CVT.cv_id 
-    WHERE ($where_cvt) AND ($where_org) AND CV.name = 'sequence' 
+    SELECT F.*, CVT.name as cvtname, O.genus, O.species 
+    FROM {feature} F 
+      INNER JOIN {cvterm} CVT ON F.type_id     = CVT.cvterm_id 
+      INNER JOIN {cv} CV      ON CV.cv_id      = CVT.cv_id
+      INNER JOIN {organism} O ON O.organism_id = F.organism_id 
+      LEFT JOIN public.chado_feature CF ON CF.feature_id = F.feature_ID
+    WHERE 
+     ($where_cvt) AND ($where_org) AND CV.name = 'sequence' AND
+     CF.feature_id IS NULL
     ORDER BY feature_id";
-
-  // get the list of features
-  $results = chado_query($sql);
-
-  // load into ids array
-  $count = 0;
-  $ids = array();
-  while ($id = $results->fetchObject()) {
-    $ids[$count] = $id->feature_id;
-    $count++;
-  }
-
-  // make sure our vocabularies are set before proceeding
-  tripal_feature_set_vocabulary();
-
-  // pre-create the SQL statement that will be used to check
-  // if a feature has already been synced.  We skip features
-  // that have been synced
-  $sql = "SELECT * FROM {chado_feature} WHERE feature_id = :feature_id";
+  
+  print_r($sql);
+  print_r($args);
+  $results = chado_query($sql, $args);
+  
 
   // Iterate through features that need to be synced
+  $count = $results->rowCount();
   $interval = intval($count * 0.01);
   if ($interval < 1) {
     $interval = 1;
   }
-  $num_ids = sizeof($ids);
-  $i = 0;
-  foreach ($ids as $feature_id) {
-    // update the job status every 1% features
-    if ($job_id and $i % $interval == 0) {
-      tripal_job_set_progress($job_id, intval(($i/$count)*100));
-    }
-    // if we have a maximum number to sync then stop when we get there
-    // if not then just continue on
-    if ($max_sync and $i == $max_sync) {
-      return '';
-    }
-    if (!db_query($sql, array(':feature_id' => $feature_id))->fetchObject()) {
-
-      # parsing all the features can cause memory overruns
-      # we are not sure why PHP does not clean up the memory as it goes
-      # to avoid this problem we will call this script through an
-      # independent system call
-      print "$i of $num_ids Syncing feature id: $feature_id\n";
-      $cmd = "php " . drupal_get_path('module', 'tripal_feature') . "/includes/tripal_feature.sync_features.inc -f $feature_id -t chado_feature";
-      system($cmd);
-
+  $i = 0;  
+  $transaction = db_transaction();
+  try {
+    //  tripal_feature_set_vocabulary();
+    print "Loading feature $i of $count (0.00%). Memory: " . number_format(memory_get_usage()) . " bytes\r";
+    foreach ($results as $feature) {
+      // update the job status every 1% features
+      if ($job_id and $i % $interval == 0) {
+        $percent = sprintf("%.2f", ($i / $count) * 100);        
+        print "Parsing Line $line_num (" . $percent . "%). Memory: " . number_format(memory_get_usage()) . " bytes.\r";
+        tripal_job_set_progress($job_id, intval(($i/$count)*100));
+      }
+      $new_node = new stdClass();
+      $new_node->type = 'chado_feature';
+      $new_node->uid = $user->uid;
+      $new_node->feature_id = $feature->feature_id;
+      
+      // set these values as they are needed for constructing the title and
+      // the match the names of the fields in the feature form
+      $new_node->organism_id = $feature->organism_id;
+      $new_node->fname = $feature->name;
+      $new_node->uniquename = $feature->uniquename;
+      $new_node->feature_type = $feature->cvtname;
+      
+      node_validate($new_node, $form, $form_state);
+      if (!form_get_errors()) {
+        $node = node_submit($new_node);
+        node_save($node);
+      }
+      else {
+        watchdog('trp-fsync', "Failed to insert feature: %title", array('%title' => $new_node->title), WATCHDOG_ERROR);
+      }
+      
+      // set the taxonomy for this node
+      //  tripal_feature_set_taxonomy($node, $feature_id);
+      
+      $i++;
     }
-    $i++;
   }
-
-  return '';
+  catch (Exception $e) {
+    print "\n"; // make sure we start errors on new line
+    watchdog_exception('trp-fsync', $e);
+    $transaction->rollback();
+    print "FAILED: Rolling back database changes...\n";
+  }
 }
 
+
+
 /**
  *
+ * Remove orphaned drupal nodes
+ *
+ * @param $dummy
+ *   Not Used -kept for backwards compatibility
+ * @param $job_id
+ *   The id of the tripal job executing this function
  *
  * @ingroup tripal_feature
  */
-function tripal_feature_sync_feature($feature_id) {
-  //print "\tSyncing feature $feature_id\n";
+function tripal_features_cleanup($dummy = NULL, $job_id = NULL) {
 
-  global $user;
-  $create_node = 1;   // set to 0 if the node exists and we just sync and not create
-
-  // get the accession prefix
-  $aprefix = variable_get('chado_feature_accession_prefix', 'FID');
-
-  // if we don't have a feature_id then return
-  if (!$feature_id) {
-    drupal_set_message(t("Please provide a feature_id to sync"));
-    return '';
-  }
-
-  // get information about this feature
-  $fsql = "
-    SELECT F.feature_id, F.name, F.uniquename,O.genus, 
-      O.species,CVT.name as cvname,F.residues,F.organism_id 
-    FROM {FEATURE} F 
-      INNER JOIN {Cvterm} CVT ON F.type_id = CVT.cvterm_id 
-      INNER JOIN {Organism} O ON F.organism_id = O.organism_ID 
-    WHERE F.feature_id = :feature_id
-  ";
-  $feature = chado_query($fsql, array(':feature_id' => $feature_id))->fetchObject();
-
-  // get the synonyms for this feature
-  $synsql = "
-    SELECT S.name 
-    FROM {feature_synonym} FS 
-      INNER JOIN {synonym} S on FS.synonym_id = S.synonym_id 
-    WHERE FS.feature_id = :feature_id
-  ";
-  $synonyms = chado_query($synsql, array(':feature_id' => $feature_id));
-
-  // now add these synonyms to the feature object as a single string
-  $synstring = '';
-  while ($synonym = $synonyms->fetchObject()) {
-    $synstring .= "$synonym->name\n";
-  }
-  $feature->synonyms = $synstring;
-
-  // check to make sure that we don't have any nodes with this feature name as a title
-  // but without a corresponding entry in the chado_feature table if so then we want to
-  // clean up that node.  (If a node is found we don't know if it belongs to our feature or
-  // not since features can have the same name/title.)
-  $tsql =  "SELECT * FROM {node} N WHERE title = :title";
-  $cnsql = "SELECT * FROM {chado_feature} WHERE nid = :nid";
-  $nodes = db_query($tsql, array(':title' => $feature->name));
-  // cycle through all nodes that may have this title
-  while ($node = $nodes->fetchObject()) {
-    $feature_nid = db_query($cnsql, array(':nid' => $node->nid))->fetchObject();
-    if (!$feature_nid) {
-      drupal_set_message(t("%feature_id: A node is present but the chado_feature entry is missing... correcting", array('%feature_id' => $feature_id)));
-      node_delete($node->nid);
-    }
-  }
-
-  // check if this feature already exists in the chado_feature table.
-  // if we have a chado feature, we want to check to see if we have a node
-  $cfsql = "SELECT * FROM {chado_feature} WHERE feature_id = :feature_id";
-  // @coder-ignore: don't need to use db_rewrite_sql() since need all nodes regardless of access control
-  $nsql =  "SELECT * FROM {node} N WHERE nid = :nid";
-  $chado_feature = db_query($cfsql, array(':feature_id' => $feature->feature_id))->fetchObject();
-  if ($chado_feature) {
-    drupal_set_message(t("%feature_id: A chado_feature entry exists", array('%feature_id' => $feature_id)));
-    $node = db_query($nsql, array(':nid' => $chado_feature->nid))->fetchObject();
-    if (!$node) {
-      // if we have a chado_feature but not a node then we have a problem and
-      // need to cleanup
-      drupal_set_message(t("%feature_id: The node is missing, but has a chado_feature entry... correcting", array('%feature_id' => $feature_id)));
-      $df_sql = "DELETE FROM {chado_feature} WHERE feature_id = :feature_id";
-      db_query($df_sql, array(':feature_id' => $feature_id));
-    }
-    else {
-      drupal_set_message(t("%feature_id: A corresponding node exists", array('%feature_id' => $feature_id)));
-      $create_node = 0;
-    }
-  }
-
-  // if we've encountered an error then just return.
-  if ($error_msg = db_error()) {
-    //print "$error_msg\n";
-    return '';
-  }
-
-  // if a drupal node does not exist for this feature then we want to
-  // create one.  Note that the node_save call in this block
-  // will call the hook_submit function which
-  if ($create_node) {
-    // get the organism for this feature
-    $sql = "SELECT * FROM {organism} WHERE organism_id = :organism_id";
-    $organism = chado_query($sql, array(':organism_id' => $feature->organism_id))->fetchObject();
-
-    drupal_set_message(t("%feature_id: Creating node $feature->name", array('%feature_id' => $feature_id)));
-    $new_node = new stdClass();
-    $new_node->type = 'chado_feature';
-    $new_node->uid = $user->uid;
-    $new_node->title = "$feature->name, $feature->uniquename ($feature->cvname) $organism->genus $organism->species";
-    $new_node->fname = "$feature->name";
-    $new_node->uniquename = "$feature->uniquename";
-    $new_node->feature_id = $feature->feature_id;
-    $new_node->residues = $feature->residues;
-    $new_node->organism_id = $feature->organism_id;
-    $new_node->feature_type = $feature->cvname;
-    $new_node->synonyms = $feature->synonyms;
-
-    // validate the node and if okay then submit
-    node_validate($new_node);
-    if ($errors = form_get_errors()) {
-      print "Error encountered validating new node. Cannot sync\n";
-      foreach ($errors as $key => $msg) {        
-        watchdog('trp-fsync', "%msg", array('%msg' => $msg), 'error');
-      }
-      exit;
-    }
-    else {
-      $node = node_submit($new_node);
-      node_save($node);
-    }
-  }
-  else {
-    $node = $chado_feature;
-  }
-
-
-  // set the taxonomy for this node
-  drupal_set_message(t("%feature_id ($node->nid): setting taxonomy", array('%feature_id' => $feature_id)));
-  tripal_feature_set_taxonomy($node, $feature_id);
-
-
-  return '';
-}
+  return tripal_core_clean_orphaned_nodes('feature', $job_id);
 
+}

+ 67 - 51
tripal_feature/theme/tripal_feature/tripal_feature_alignments.tpl.php

@@ -60,57 +60,73 @@ $alignments = $feature->all_featurelocs;
 if(count($alignments) > 0){ ?>
   <div id="tripal_feature-alignments-box" class="tripal_feature-info-box tripal-info-box">
     <div class="tripal_feature-info-box-title tripal-info-box-title">Alignments</div>
-    <div class="tripal_feature-info-box-desc tripal-info-box-desc">The following features are aligned to this <b><?php print $feature->type_id->name;?></b></div>
-    <table id="tripal_feature-featurelocs_as_child-table" class="tripal_feature-table tripal-table tripal-table-horz">
-      <tr>
-        <th>Aligned Feature</th>
-        <th>Feature Type</th>
-        <th>Alignment Location</th>
-      </tr><?php
-      $i = 0; 
-      foreach ($alignments as $alignment){
-        $class = 'tripal_feature-table-odd-row tripal-table-odd-row';
-        if ($i % 2 == 0 ) {
-          $class = 'tripal_feature-table-odd-row tripal-table-even-row';
-        } ?>
-        <tr class="<?php print $class ?>">
-          <td><?php 
-            if ($alignment->nid) {
-              print "<a href=\"" . url("node/".$alignment->nid) . "\">".$alignment->name."</a>";
-            } else {
-              print $alignment->name;
-            }?>
-          </td>
-          <td><?php print $alignment->type ?></td>
-          <td><?php  
-            $strand = '.';
-            if ($alignment->strand == -1) {
-              $strand = '-';
-            } 
-            elseif ($alignment->strand == 1) {
-               $strand = '+';
-            } 
-              
-            // if this is a match then make the other location 
-            if($alignment->right_feature){
-              $rstrand = '.';
-              if ($alignment->right_strand == -1) {
-                   $rstrand = '-';
-              } 
-              elseif ($alignment->right_strand == 1) {
-                   $rstrand = '+';
-              }
-              print $feature->name .":". ($alignment->fmin + 1) . ".." . $alignment->fmax . " " . $strand; 
-              print "<br>" . $alignment->name .":". ($alignment->right_fmin + 1) . ".." . $alignment->right_fmax . " " . $rstrand; 
-            }
-            else {
-              print $alignment->name .":". ($alignment->fmin + 1) . ".." . $alignment->fmax . " " . $strand; 
-            }?>
-          </td>
-        </tr> <?php
-        $i++;  
-      } ?>
-    </table>
+    <div class="tripal_feature-info-box-desc tripal-info-box-desc">The following features are aligned</div><?php
+    // the $headers array is an array of fields to use as the colum headers.
+    // additional documentation can be found here
+    // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
+    $headers = array('Aligned Feature' ,'Feature Type', 'Alignment Location');
+    
+    // the $rows array contains an array of rows where each row is an array
+    // of values for each column of the table in that row.  Additional documentation
+    // can be found here:
+    // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
+    $rows = array();
+    
+    foreach ($alignments as $alignment){
+      $feature_name = $alignment->name;
+      if (property_exists($alignment, 'nid')) {
+        $feature_name = l($feature_name, "node/" . $alignment->nid);
+      }
+      $feature_loc = '';
+      $strand = '.';
+      if ($alignment->strand == -1) {
+        $strand = '-';
+      } 
+      elseif ($alignment->strand == 1) {
+         $strand = '+';
+      } 
+      // if this is a match then make the other location 
+      if(property_exists($alignment, 'right_feature')){
+        $rstrand = '.';
+        if ($alignment->right_strand == -1) {
+          $rstrand = '-';
+        } 
+        elseif ($alignment->right_strand == 1) {
+          $rstrand = '+';
+        }
+        $feature_loc = $feature->name .":". ($alignment->fmin + 1) . ".." . $alignment->fmax . " " . $strand; 
+        $feature_loc .= "<br>" . $alignment->name .":". ($alignment->right_fmin + 1) . ".." . $alignment->right_fmax . " " . $rstrand; 
+      }
+      else {
+        $feature_loc = $alignment->name .":". ($alignment->fmin + 1) . ".." . $alignment->fmax . " " . $strand; 
+      }
+      
+      $rows[] = array(
+        $feature_name,
+        $alignment->type,
+        $feature_loc
+      );
+    } 
+    
+    // the $table array contains the headers and rows array as well as other
+    // options for controlling the display of the table.  Additional
+    // documentation can be found here:
+    // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
+    $table = array(
+      'header' => $headers,
+      'rows' => $rows,
+      'attributes' => array(
+        'id' => 'tripal_feature-table-alignments',
+      ),
+      'sticky' => FALSE,
+      'caption' => '',
+      'colgroups' => array(),
+      'empty' => '',
+    );
+    
+    // once we have our table array structure defined, we call Drupal's theme_table()
+    // function to generate the table.
+    print theme_table($table); ?>
   </div><?php
 }
 

+ 46 - 41
tripal_feature/theme/tripal_feature/tripal_feature_analyses.tpl.php

@@ -1,51 +1,56 @@
 <?php
 $feature = $variables['node']->feature;
-
-// expand the feature object to include the libraries from the library_feature
-// table in chado.
-$feature = tripal_core_expand_chado_vars($feature,'table','analysisfeature');
-
-// get the references. if only one reference exists then we want to convert
-// the object into an array, otherwise the value is an array
+$options = array('return_array' => 1);
+$feature = tripal_core_expand_chado_vars($feature, 'table', 'analysisfeature', $options);
 $analyses = $feature->analysisfeature;
-if (!$analyses) {
-   $analyses = array();
-} 
-elseif (!is_array($analyses)) { 
-   $analyses = array($analyses); 
-}
 
-// don't show this page if there are no libraries
+// don't show this page if there are no analyses
 if (count($analyses) > 0) { ?>
   <div id="tripal_feature-analyses-box" class="tripal_feature-info-box tripal-info-box">
     <div class="tripal_feature-info-box-title tripal-info-box-title">Analyses</div>
-    <div class="tripal_feature-info-box-desc tripal-info-box-desc">This <?php print $feature->type_id->name ?> is derived from or has results from the following analyses</div>
-    <table id="tripal_feature-analyses-table" class="tripal_feature-table tripal-table tripal-table-horz">
-      <tr>
-        <th>Analysis Name</th>
-        <th>Date Performed</th>
-      </tr> <?php
-      $i = 0; 
-      foreach ($analyses as $analysis) {
-        $class = 'tripal-table-odd-row';
-        if ($i % 2 == 0 ) {
-           $class = 'tripal-table-even-row';
-        } ?>
-        <tr class="<?php print $class ?>">
-          <td><?php 
-            $nid = chado_get_node_id('analysis', $analysis->analysis_id->analysis_id);
-            if ($nid) {
-               print "<a href=\"". url("node/".$nid) . "\">".$analysis->analysis_id->name."</a>";
-            } else {
-               print $analysis->analysis_id->name;
-            } ?>
-          </td>
-          <td> <?php print preg_replace('/\d\d:\d\d:\d\d/', '',  $analysis->analysis_id->timeexecuted) ?>
-          </td>
-        </tr> <?php
-        $i++;  
-      } ?>
-    </table> 
+    <div class="tripal_feature-info-box-desc tripal-info-box-desc">This <?php print $feature->type_id->name ?> is derived from or has results from the following analyses</div> <?php
+    
+    // the $headers array is an array of fields to use as the colum headers.
+    // additional documentation can be found here
+    // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
+    $headers = array('Analysis Name' ,'Date Performed');
+    
+    // the $rows array contains an array of rows where each row is an array
+    // of values for each column of the table in that row.  Additional documentation
+    // can be found here:
+    // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
+    $rows = array();
+    
+    foreach ($analyses as $analysis) {
+      $analysis_name = $analysis->analysis_id->name;
+      if (property_exists($analysis->analysis_id, 'nid')) {
+        $analysis_name = l($analysis_name, "node/" . $analysis->analysis_id->nid);
+      } 
+      $rows[] = array(
+        $analysis_name,
+        preg_replace('/\d\d:\d\d:\d\d/', '',  $analysis->analysis_id->timeexecuted),
+      );
+    }
+     
+    // the $table array contains the headers and rows array as well as other
+    // options for controlling the display of the table.  Additional
+    // documentation can be found here:
+    // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
+    $table = array(
+      'header' => $headers,
+      'rows' => $rows,
+      'attributes' => array(
+        'id' => 'tripal_feature-table-analyses',
+      ),
+      'sticky' => FALSE,
+      'caption' => '',
+      'colgroups' => array(),
+      'empty' => '',
+    );
+    
+    // once we have our table array structure defined, we call Drupal's theme_table()
+    // function to generate the table.
+    print theme_table($table); ?>
   </div><?php 
 } 
 

+ 1 - 3
tripal_feature/theme/tripal_feature/tripal_feature_base.tpl.php

@@ -43,12 +43,10 @@ $feature  = $variables['node']->feature;  ?>
     $feature->type_id->name
   );
   // Organism row
+  $organism = $feature->organism_id->genus ." " . $feature->organism_id->species ." (" .$feature->organism_id->common_name .")";
   if ($feature->organism_id->nid) {
     $organism = l("<i>" . $feature->organism_id->genus . " " . $feature->organism_id->species . "</i> (" .$feature->organism_id->common_name .")", "node/".$feature->organism_id->nid, array('html' => TRUE));
   } 
-  else {
-    $organism = $feature->organism_id->genus ." " . $feature->organism_id->species ." (" .$feature->organism_id->common_name .")";
-  }
   $rows[] = array(
     array(
       'data' => 'Organism',

+ 0 - 28
tripal_feature/theme/tripal_feature/tripal_feature_featureloc_sequences.tpl.php

@@ -1,28 +0,0 @@
-<?php
-// get the featurelocs for this feature. If the variable is not already 
-// expanded then do so
-$feature = $variables['node']->feature;
-
-$feature = tripal_core_expand_chado_vars($feature, 'table', 'featureloc');
-$featurelocs = $feature->featureloc;
-
-// get the featurelocs. if only one featureloc exists then we want to convert
-// the object into an array, otherwise the value is an array
-$ffeaturelocs = $feature->featureloc->feature_id;
-if (!$ffeaturelocs) {
-   $ffeaturelocs = array();
-} elseif (!is_array($ffeaturelocs)) { 
-   $ffeaturelocs = array($ffeaturelocs); 
-}
-$featureloc_sequences = tripal_feature_load_featureloc_sequences ($feature->feature_id,$ffeaturelocs);
-
-if(count($featureloc_sequences) > 0){
-   foreach($featureloc_sequences as $src => $attrs){ ?>
-       <div id="tripal_feature-<?php print $attrs['type']?>-box" class="tripal_feature-info-box tripal-info-box">
-         <div class="tripal_feature-info-box-title tripal-info-box-title">Annotated Sequence</div>
-         <div class="tripal_feature-info-box-desc tripal-info-box-desc"></div>
-            <?php print $attrs['formatted_seq'] ?>
-       </div>
-   <?php } 
-}?>
-

+ 1 - 2
tripal_feature/theme/tripal_feature/tripal_feature_featurepos.tpl.php

@@ -1,6 +1,4 @@
 <?php
-$feature = $variables['node']->feature;
-$map_positions = array();
 
 // expand the feature object to include the records from the featurepos table
 // specify the number of features to show by default and the unique pager ID
@@ -8,6 +6,7 @@ $num_results_per_page = 25;
 $featurepos_pager_id = 0;
 
 // get the maps associated with this feature
+$feature = $variables['node']->feature;
 $options = array(  
   'return_array' => 1,
   'order_by' => array('map_feature_id' => 'ASC'),

+ 48 - 35
tripal_feature/theme/tripal_feature/tripal_feature_phenotypes.tpl.php

@@ -1,8 +1,6 @@
 <?php
+// expand the feature object to include the phenotypes from the feature_phenotypes table in chado.
 $feature = $variables['node']->feature;
-
-// expand the feature object to include the phenotypes from the feature_phenotypes 
-// table in chado.
 $options = array(
   'return_array' => 1,
   'include_fk' => array(
@@ -17,40 +15,55 @@ $options = array(
 $feature = tripal_core_expand_chado_vars($feature, 'table', 'feature_phenotype', $options);
 $feature_phenotypes = $feature->feature_phenotype;
 
-// expand the text fields
-$options = array('return_array' => 1);
-$feature = tripal_core_expand_chado_vars($feature, 'field', 'phenotype.value', $options);
-$feature = tripal_core_expand_chado_vars($feature, 'field', 'phenotype.uniquename', $options);
-$feature = tripal_core_expand_chado_vars($feature, 'field', 'phenotype.name', $options);
-
+if(count($feature_phenotypes) > 0){ 
+  
+  // expand the text fields
+  $options = array('return_array' => 1);
+  $feature = tripal_core_expand_chado_vars($feature, 'field', 'phenotype.value', $options);
+  $feature = tripal_core_expand_chado_vars($feature, 'field', 'phenotype.uniquename', $options);
+  $feature = tripal_core_expand_chado_vars($feature, 'field', 'phenotype.name', $options); ?>
 
-if(count($feature_phenotypes) > 0){ ?>
   <div id="tripal_feature-phenotypes-box" class="tripal_feature-info-box tripal-info-box">
     <div class="tripal_feature-info-box-title tripal-info-box-title">Phenotypes</div>
-    <div class="tripal_feature-info-box-desc tripal-info-box-desc">The feature is associated with the following phenotypes</div>
+    <div class="tripal_feature-info-box-desc tripal-info-box-desc">The feature is associated with the following phenotypes</div><?php
 
-    <table id="tripal_feature-phenotypes-table" class="tripal_feature-table tripal-table tripal-table-horz">
-      <tr>   
-        <th>Attribute</th>     
-        <th>Observed Unit</th>               
-        <th>Value</th>
-        <th>Evidence Type</th>
-      </tr> <?php
-      $i = 0; 
-      foreach ($feature_phenotypes as $index => $feature_phenotype){
-        $phenotype = $feature_phenotype->phenotype_id;
-        $class = 'tripal-table-odd-row';
-        if($i % 2 == 0 ){
-           $class = 'tripal-table-even-row';
-        } ?>
-        <tr class="<?php print $class ?>">
-          <td><?php print $phenotype->attr_id->name?></td>
-          <td><?php print $phenotype->observable_id->name?></td>          
-          <td><?php print $phenotype->cvalue_id ? $phenotype->cvalue_id->name : $phenotype->value ?></td>
-          <td><?php print $phenotype->assay_id ?></td>
-        </tr> <?php
-        $i++;  
-      } ?>
-    </table>
-  </div><?php
+    // the $headers array is an array of fields to use as the colum headers.
+    // additional documentation can be found here
+    // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
+    $headers = array('Attribute', 'Observed Unit', 'Value', 'Evidence Type');
+    
+    // the $rows array contains an array of rows where each row is an array
+    // of values for each column of the table in that row.  Additional documentation
+    // can be found here:
+    // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
+    $rows = array();
+    foreach ($feature_phenotypes as $index => $feature_phenotype){
+      $phenotype = $feature_phenotype->phenotype_id;
+      $rows[] = array(
+        $phenotype->attr_id->name,
+        $phenotype->observable_id->name,
+        $phenotype->cvalue_id ? $phenotype->cvalue_id->name : $phenotype->value,
+        $phenotype->assay_id
+      );
+    } 
+    // the $table array contains the headers and rows array as well as other
+    // options for controlling the display of the table.  Additional
+    // documentation can be found here:
+    // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
+    $table = array(
+      'header' => $headers,
+      'rows' => $rows,
+      'attributes' => array(
+        'id' => 'tripal_feature-table-phenotypes',
+      ),
+      'sticky' => FALSE,
+      'caption' => '',
+      'colgroups' => array(),
+      'empty' => '',
+    );
+    
+    // once we have our table array structure defined, we call Drupal's theme_table()
+    // function to generate the table.
+    print theme_table($table); ?>
+  </div> <?php
 }

+ 40 - 24
tripal_feature/theme/tripal_feature/tripal_feature_properties.tpl.php

@@ -1,36 +1,52 @@
 <?php
 
-$feature = $node->feature;
+$feature = $variables['node']->feature;
 $options = array('return_array' => 1);
 $feature = tripal_core_expand_chado_vars($feature, 'table', 'featureprop', $options);
 $properties = $feature->featureprop;
 
-
 if(count($properties) > 0){ ?>
 
   <div id="tripal_feature-properties-box" class="tripal_feature-info-box tripal-info-box">
-    <div class="tripal_feature-info-box-title tripal-info-box-title">Properties</div>
-    <div class="tripal_feature-info-box-desc tripal-info-box-desc">Properties for the feature '<?php print $node->feature->name ?>' include:</div>
+    <div class="tripal_feature-info-box-title tripal-info-box-title">Properties</div> <?php
 
-    <table class="tripal_feature-table tripal-table tripal-table-horz">
-    <tr>
-      <th>Property Name</th>
-      <th>Value</th>
-    </tr>
-	  <?php	// iterate through each property
-		  $i = 0;
-		  foreach ($properties as $result){
-		    $result = tripal_core_expand_chado_vars($result,'field','featureprop.value');
-		    $class = 'tripal_feature-table-odd-row tripal-table-odd-row';
-        if($i % 2 == 0 ){
-           $class = 'tripal_feature-table-odd-row tripal-table-even-row';
-        } ?>
-			  <tr class="<?php print $class ?>">
-  			  <td><?php print ucfirst(preg_replace('/_/', ' ', $result->type_id->name)) ?></td>
-  			  <td><?php print urldecode($result->value) ?></td>
-  			</tr> <?php
-			  $i++;
-		  } ?>
-		</table>
+    // the $headers array is an array of fields to use as the colum headers.
+    // additional documentation can be found here
+    // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
+    $headers = array('Property Name', 'Value');
+    
+    // the $rows array contains an array of rows where each row is an array
+    // of values for each column of the table in that row.  Additional documentation
+    // can be found here:
+    // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
+    $rows = array();
+    
+    foreach ($properties as $property){
+      $property = tripal_core_expand_chado_vars($property,'field','featureprop.value');
+      $rows[] = array(
+        ucfirst(preg_replace('/_/', ' ', $property->type_id->name)),
+        urldecode($property->value)
+      );
+    }
+     
+    // the $table array contains the headers and rows array as well as other
+    // options for controlling the display of the table.  Additional
+    // documentation can be found here:
+    // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
+    $table = array(
+      'header' => $headers,
+      'rows' => $rows,
+      'attributes' => array(
+        'id' => 'tripal_feature-table-properties',
+      ),
+      'sticky' => FALSE,
+      'caption' => '',
+      'colgroups' => array(),
+      'empty' => '',
+    );
+    
+    // once we have our table array structure defined, we call Drupal's theme_table()
+    // function to generate the table.
+    print theme_table($table); ?>
   </div> <?php
 }

+ 57 - 40
tripal_feature/theme/tripal_feature/tripal_feature_references.tpl.php

@@ -2,7 +2,7 @@
 $feature = $variables['node']->feature;
 $references = array();
 
-// First, get the dbxref record from feature recrod itself if one exists
+// First, get the dbxref record from feature record itself if one exists
 if ($feature->dbxref_id) {
   $feature->dbxref_id->is_primary = 1;  // add this new property so we know it's the primary reference
   $references[] = $feature->dbxref_id;
@@ -28,45 +28,62 @@ if (count($feature_dbxrefs) > 0 ) {
 if(count($references) > 0){ ?>
   <div id="tripal_feature-references-box" class="tripal_feature-info-box tripal-info-box">
     <div class="tripal_feature-info-box-title tripal-info-box-title">Cross References</div>
-    <div class="tripal_feature-info-box-desc tripal-info-box-desc">External references for this <?php print $feature->type_id->name ?></div>
-    <table id="tripal_feature-references-table" class="tripal_feature-table tripal-table tripal-table-horz">
-      <tr>
-        <th>Dababase</th>
-        <th>Accession</th>
-      </tr> <?php
-      $i = 0; 
-      foreach ($references as $dbxref){ 
-        if($dbxref_id->db_id->name == 'GFF_source'){
-           continue;  // skip the GFF_source entry as this is just needed for the GBrowse chado adapter
-        }
-        $class = 'tripal_feature-table-odd-row tripal-table-odd-row';
-        if($i % 2 == 0 ){
-           $class = 'tripal_feature-table-even-row tripal-table-even-row';
-        } ?>
-        <tr class="<?php print $class ?>">
-          <td> <?php 
-            if ($dbxref->db_id->url) { 
-              print l($dbxref->db_id->name, $dbxref->db_id->url);
-            } 
-            else { 
-              print $dbxref->db_id->name; 
-            } ?>
-          </td>
-          <td> <?php 
-            if ($dbxref->db_id->urlprefix) { 
-              print l($dbxref->accession, $dbxref->db_id->urlprefix.$dbxref->accession);
-            } 
-            else { 
-              print $dbxref->accession; 
-            }
-            if ($dbxref->is_primary) {
-              print " <i>(primary cross-reference)</i>";
-            } ?>
-          </td>
-        </tr> <?php
-        $i++;  
-      } ?>
-    </table>
+    <div class="tripal_feature-info-box-desc tripal-info-box-desc">External references for this <?php print $feature->type_id->name ?></div><?php
+     
+    // the $headers array is an array of fields to use as the colum headers.
+    // additional documentation can be found here
+    // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
+    $headers = array('Dababase', 'Accession');
+    
+    // the $rows array contains an array of rows where each row is an array
+    // of values for each column of the table in that row.  Additional documentation
+    // can be found here:
+    // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
+    $rows = array();
+ 
+    foreach ($references as $dbxref){
+    
+      // skip the GFF_source entry as this is just needed for the GBrowse chado adapter 
+      if ($dbxref->db_id->name == 'GFF_source'){
+         continue;  
+      } 
+      $dbname = $dbxref->db_id->name; 
+      if ($dbxref->db_id->url) { 
+        $dbname = l($dbname, $dbxref->db_id->url, array('attributes' => array('target' => '_blank')));
+      } 
+      
+      $accession = $dbxref->accession; 
+      if ($dbxref->db_id->urlprefix) { 
+        $accession = l($accession, $dbxref->db_id->urlprefix . $dbxref->accession, array('attributes' => array('target' => '_blank')));
+      } 
+      if (property_exists($dbxref, 'is_primary')) {
+        $accession .= " <i>(primary cross-reference)</i>";
+      }
+      $rows[] = array(
+        $dbname,
+        $accession
+      );
+    } 
+    
+    // the $table array contains the headers and rows array as well as other
+    // options for controlling the display of the table.  Additional
+    // documentation can be found here:
+    // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
+    $table = array(
+      'header' => $headers,
+      'rows' => $rows,
+      'attributes' => array(
+        'id' => 'tripal_feature-table-references',
+      ),
+      'sticky' => FALSE,
+      'caption' => '',
+      'colgroups' => array(),
+      'empty' => '',
+    );
+    
+    // once we have our table array structure defined, we call Drupal's theme_table()
+    // function to generate the table.
+    print theme_table($table); ?>
   </div><?php 
 }?>
 

+ 116 - 64
tripal_feature/theme/tripal_feature/tripal_feature_relationships.tpl.php

@@ -22,73 +22,125 @@ $all_relationships = $feature->all_relationships;
 $object_rels = $all_relationships['object'];
 $subject_rels = $all_relationships['subject'];
 
-if (count($object_rels) > 0 or count($subject_rels) > 0) {
-?>
+if (count($object_rels) > 0 or count($subject_rels) > 0) { ?>
   <div id="tripal_feature-relationships-box" class="tripal_feature-info-box tripal-info-box">
     <div class="tripal_feature-info-box-title tripal-info-box-title">Relationships</div>
     <div class="tripal_feature-info-box-desc tripal-info-box-desc"></div> <?php
+    // first add in the subject relationships.  
+    foreach ($subject_rels as $rel_type => $rels){
+      foreach ($rels as $obj_type => $objects){ ?>
+        <p>This <?php print $feature->type_id->name;?> is <?php print $rel_type ?> the following <b><?php print $obj_type ?></b> feature(s): <?php
+         
+        // the $headers array is an array of fields to use as the colum headers.
+        // additional documentation can be found here
+        // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
+        $headers = array('Feature Name' ,'Unique Name', 'Species', 'Type');
+        
+        // the $rows array contains an array of rows where each row is an array
+        // of values for each column of the table in that row.  Additional documentation
+        // can be found here:
+        // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
+        $rows = array();
+        
+        foreach ($objects as $object){
+          // link the feature to it's node
+          $feature_name = $object->record->object_id->name;
+          if (property_exists($object->record, 'nid')) {
+            $feature_name = "<a href=\"" . url("node/" . $object->record->nid) . "\" target=\"_blank\">" . $object->record->object_id->name . "</a>";
+          }
+          // link the organism to it's node
+          $organism = $object->record->object_id->organism_id;
+          $organism_name = $organism->genus ." " . $organism->species;
+          if (property_exists($organism, 'nid')) {
+            $organism_name = l("<i>" . $organism->genus . " " . $organism->species . "</i>", "node/" . $organism->nid, array('html' => TRUE));
+          }
+          $rows[] = array(
+            $feature_name, 
+            $object->record->object_id->uniquename,
+            $organism_name,
+            $object->record->object_id->type_id->name,
+          ); 
+         } 
+         // the $table array contains the headers and rows array as well as other
+         // options for controlling the display of the table.  Additional
+         // documentation can be found here:
+         // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
+         $table = array(
+           'header' => $headers,
+           'rows' => $rows,
+           'attributes' => array(
+             'id' => 'tripal_feature-table-relationship-object',
+           ),
+           'sticky' => FALSE,
+           'caption' => '',
+           'colgroups' => array(),
+           'empty' => '',
+         );
+         
+         // once we have our table array structure defined, we call Drupal's theme_table()
+         // function to generate the table.
+         print theme_table($table); ?>
+         </p>
+         <br><?php
+       }
+    }
     
-      // first add in the subject relationships.  
-      foreach ($subject_rels as $rel_type => $rels){
-         foreach ($rels as $obj_type => $objects){?>           
-           <p>This <?php print $feature->type_id->name;?> is <?php print $rel_type ?> the following <b><?php print $obj_type ?></b> feature(s):
-           <table id="tripal_feature-relationships_as_object-table" class="tripal_feature-table tripal-table tripal-table-horz">
-             <tr>
-               <th>Feature Name</th>
-               <th>Unique Name</th>
-               <th>Species</th>
-               <th>Type</th>
-             </tr> <?php
-             foreach ($objects as $object){ ?>
-               <tr>
-                 <td><?php 
-                    if ($object->record->nid) {
-                      print "<a href=\"" . url("node/" . $object->record->nid) . "\" target=\"_blank\">" . $object->record->object_id->name . "</a>";
-                    }
-                    else {
-                      print $object->record->object_id->name;
-                    } ?>
-                 </td>
-                 <td><?php print $object->record->object_id->uniquename ?></td>
-                 <td><?php print $object->record->object_id->organism_id->genus . " " . $object->record->object_id->organism_id->species; ?></td>
-                 <td><?php print $object->record->object_id->type_id->name ?></td>                 
-               </tr> <?php
-             } ?>
-             </table>
-             </p><br><?php
-         }
-      }
-      
-      // second add in the object relationships.  
-      foreach ($object_rels as $rel_type => $rels){
-         foreach ($rels as $subject_type => $subjects){?>
-           <p>The following <b><?php print $subjects[0]->record->subject_id->type_id->name ?></b> feature(s) are <?php print $rel_type ?> this <?php print $feature->type_id->name;?>:
-           <table id="tripal_feature-relationships_as_object-table" class="tripal_feature-table tripal-table tripal-table-horz">
-             <tr>
-               <th>Feature Name</th>
-               <th>Unique Name</th>
-               <th>Species</th>
-               <th>Type</th>
-             </tr> <?php
-             foreach ($subjects as $subject){ ?>
-               <tr>
-                 <td><?php 
-                    if ($subject->record->nid) {
-                      print "<a href=\"" . url("node/" . $subject->record->nid) . "\" target=\"_blank\">" . $subject->record->subject_id->name . "</a>";
-                    }
-                    else {
-                      print $subject->record->subject_id->name;
-                    } ?>
-                 </td>
-                 <td><?php print $subject->record->subject_id->uniquename ?></td>
-                 <td><?php print $subject->record->subject_id->organism_id->genus . " " . $subject->record->subject_id->organism_id->species; ?></td>
-                 <td><?php print $subject->record->subject_id->type_id->name ?></td>                 
-               </tr> <?php
-             } ?>
-             </table>
-             </p><br><?php
-         }
-      }
-    ?>
+    // second add in the object relationships.  
+    foreach ($object_rels as $rel_type => $rels){
+      foreach ($rels as $subject_type => $subjects){?>
+        <p>The following <b><?php print $subjects[0]->record->subject_id->type_id->name ?></b> feature(s) are <?php print $rel_type ?> this <?php print $feature->type_id->name;?>: <?php 
+        // the $headers array is an array of fields to use as the colum headers.
+        // additional documentation can be found here
+        // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
+        $headers = array('Feature Name' ,'Unique Name', 'Species', 'Type');
+        
+        // the $rows array contains an array of rows where each row is an array
+        // of values for each column of the table in that row.  Additional documentation
+        // can be found here:
+        // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
+        $rows = array();
+        
+        foreach ($subjects as $subject){
+          // link the feature to it's node
+          $feature_name = $subject->record->subject_id->name;
+          if (property_exists($subject->record, 'nid')) {
+            $feature_name = "<a href=\"" . url("node/" . $subject->record->nid) . "\" target=\"_blank\">" . $subject->record->subject_id->name . "</a>";
+          }
+          // link the organism to it's node
+          $organism = $subject->record->subject_id->organism_id;
+          $organism_name = $organism->genus ." " . $organism->species;
+          if (property_exists($organism, 'nid')) {
+            $organism_name = l("<i>" . $organism->genus . " " . $organism->species . "</i>", "node/" . $organism->nid, array('html' => TRUE));
+          }
+          $rows[] = array(
+            $feature_name, 
+            $subject->record->subject_id->uniquename,
+            $organism_name,
+            $subject->record->subject_id->type_id->name,
+          ); 
+         } 
+         // the $table array contains the headers and rows array as well as other
+         // options for controlling the display of the table.  Additional
+         // documentation can be found here:
+         // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
+         $table = array(
+           'header' => $headers,
+           'rows' => $rows,
+           'attributes' => array(
+             'id' => 'tripal_feature-table-relationship-subject',
+           ),
+           'sticky' => FALSE,
+           'caption' => '',
+           'colgroups' => array(),
+           'empty' => '',
+         );
+         
+         // once we have our table array structure defined, we call Drupal's theme_table()
+         // function to generate the table.
+         print theme_table($table); ?>
+         </p>
+         <br><?php
+       }
+    }?>
   </div> <?php
 }

+ 42 - 7
tripal_feature/theme/tripal_feature/tripal_feature_sequence.tpl.php

@@ -1,4 +1,25 @@
 <?php
+/*
+ * There are two ways that sequences can be displayed.  They can come from the 
+ * feature.residues column or they can come from an alignment with another feature.  
+ * This template will show both or one or the other depending on the data available.
+ * 
+ * For retreiving the sequence from an alignment we would typically make a call to
+ * tripal_core_expand_chado_vars function.  For example, to retrieve all
+ * of the featurelocs in order to get the sequences needed for this template, the
+ * following function call would be made:
+ *
+ *   $feature = tripal_core_expand_chado_vars($feature,'table','featureloc');
+ *
+ * Then all of the sequences would need to be retreived from the alignments and
+ * formatted for display below.  However, to simplify this template, this has already
+ * been done by the tripal_feature module and the sequences are made available in
+ * the variable:
+ *
+ *   $feature->featureloc_sequences
+ *
+ */
+
 $feature = $variables['node']->feature;
 
 // we don't want to get the sequence for traditionally large types. They are
@@ -13,14 +34,28 @@ if(strcmp($feature->type_id->name,'scaffold') !=0 and
   $residues = $feature->residues;
 } 
 
-if ($residues) { ?>
+// get the sequence derived from alignments
+$feature = $variables['node']->feature;
+$featureloc_sequences = $feature->featureloc_sequences;
+
+if ($residues or count($featureloc_sequences) > 0) { ?>
   <div id="tripal_feature-sequence-box" class="tripal_feature-info-box tripal-info-box">
-    <div class="tripal_feature-info-box-title tripal-info-box-title">Sequence</div>
-    <div class="tripal_feature-info-box-desc tripal-info-box-desc">The sequence for this <?php print $feature->type_id->name; ?> </div>
+  <div class="tripal_feature-info-box-title tripal-info-box-title">Sequence</div>
+  <div class="tripal_feature-info-box-desc tripal-info-box-desc"></div> <?php
+  
+  // show the alignment sequences first as they are colored with child features
+  if(count($featureloc_sequences) > 0){
+    foreach($featureloc_sequences as $src => $attrs){ 
+      print $attrs['formatted_seq'];
+    } 
+  }
+  
+  // add in the residues if they are present
+  if ($residues) { ?>
     <pre id="tripal_feature-sequence-residues"><?php 
       // format the sequence to break every 100 residues
       print preg_replace("/(.{50})/","\\1<br>",$feature->residues); ?>  
-    </pre>
-  </div> <?php
-}
-
+    </pre> <?php 
+  } ?>
+  </div> <?php 
+}

+ 11 - 43
tripal_feature/theme/tripal_feature/tripal_feature_teaser.tpl.php

@@ -1,45 +1,13 @@
 <?php
+$node = $variables['node'];
+$feature = $variables['node']->feature; ?>
 
-$feature  = $variables['node']->feature;
-
-?>
-<div id="tripal_feature-base-box" class="tripal_feature-info-box tripal-info-box">
-  <div class="tripal_feature-info-box-title tripal-info-box-title">Feature Details</div>
-  <div class="tripal_feature-info-box-desc tripal-info-box-desc"></div>
-
-   <?php if(strcmp($feature->is_obsolete,'t')==0){ ?>
-      <div class="tripal_feature-obsolete">This feature is obsolete</div>
-   <?php }?>
-   <table id="tripal_feature-base-table" class="tripal_feature-table tripal-table tripal-table-vert">
-      <tr class="tripal_feature-table-odd-row tripal-table-even-row">
-        <th>Name</th>
-        <td><?php print $feature->name; ?></td>
-      </tr>
-      <tr class="tripal_feature-table-odd-row tripal-table-odd-row">
-        <th nowrap>Unique Name</th>
-        <td><?php print $feature->uniquename; ?></td>
-      </tr>
-      <tr class="tripal_feature-table-odd-row tripal-table-even-row">
-        <th>Internal ID</th>
-        <td><?php print $feature->feature_id; ?></td>
-      </tr>
-      <tr class="tripal_feature-table-odd-row tripal-table-odd-row">
-        <th>Length</th>
-        <td><?php print $feature->seqlen ?></td>
-      </tr>
-      <tr class="tripal_feature-table-odd-row tripal-table-even-row">
-        <th>Type</th>
-        <td><?php print $feature->type_id->name; ?></td>
-      </tr>
-      <tr class="tripal_feature-table-odd-row tripal-table-odd-row">
-        <th>Organism</th>
-        <td>
-          <?php if ($feature->organism_id->nid) { 
-      	   print "<a href=\"".url("node/".$feature->organism_id->nid)."\">".$feature->organism_id->genus ." " . $feature->organism_id->species ." (" .$feature->organism_id->common_name ." )</a>";      	 
-          } else { 
-            print $feature->organism_id->genus ." " . $feature->organism_id->species ." (" .$feature->organism_id->common_name .")";
-          } ?>
-        </td>
-     	</tr>           	                                
-   </table>
-</div>
+<div class="tripal_feature-teaser tripal-teaser"> 
+  <div class="tripal-feature-teaser-title tripal-teaser-title"><?php 
+    print l($node->title, "node/$node->nid", array('html' => TRUE));?>
+  </div>
+  <div class="tripal-feature-teaser-text tripal-teaser-text"><?php 
+    print $node->title;
+    print "... " . l("[more]", "node/$node->nid"); ?>
+  </div>
+</div>

+ 52 - 34
tripal_feature/theme/tripal_feature/tripal_feature_terms.tpl.php

@@ -1,14 +1,9 @@
 <?php
 
 $feature = $node->feature;
-$feature = tripal_core_expand_chado_vars($feature, 'table', 'feature_cvterm');
-
+$options = array('return_array' => 1);
+$feature = tripal_core_expand_chado_vars($feature, 'table', 'feature_cvterm', $options);
 $terms = $feature->feature_cvterm;
-if (!$terms) {
-  $terms = array();
-} elseif (!is_array($terms)) { 
-  $terms = array($terms); 
-}
 
 // order the terms by CV
 $s_terms = array();
@@ -20,33 +15,56 @@ if (count($s_terms) > 0) { ?>
   <div id="tripal_feature-terms-box" class="tripal_feature-info-box tripal-info-box">
     <div class="tripal_feature-info-box-title tripal-info-box-title">Annotated Terms</div>
     <div class="tripal_feature-info-box-desc tripal-info-box-desc">The following terms have been associated with this <?php print $node->feature->type_id->name ?>:</div>  <?php
+    
     // iterate through each term
-    foreach ($s_terms as $cv => $terms) {  ?>
-      <p><?php print ucwords(preg_replace('/_/', ' ', $cv)) ?></p>
-      <table class="tripal_feature-table tripal-table tripal-table-horz">
-        <tr>
-          <th>Term</th>
-          <th>Definition</th>
-        </tr> <?php
-        $i = 0;
-        foreach ($terms as $term) { 
-          $class = 'tripal_feature-table-odd-row tripal-table-odd-row';
-          if($i % 2 == 0 ){
-            $class = 'tripal_feature-table-even-row tripal-table-even-row';
-          }
-          $accession = $term->cvterm_id->dbxref_id->accession;
-          if (is_numeric($term->cvterm_id->dbxref_id->accession)) {
-            $accession = $term->cvterm_id->dbxref_id->db_id->name . ":" . $term->cvterm_id->dbxref_id->accession;
-          }
-          if ($term->cvterm_id->dbxref_id->db_id->urlprefix) {
-            $accession =  "<a href=\"" . $term->cvterm_id->dbxref_id->db_id->urlprefix . "$accession\" target=\"_blank\">$accession</a>";
-          } ?>
-          <tr class="<?php print $class ?>">
-            <td><?php print $accession ?></td>
-            <td><?php print $term->cvterm_id->name ?></td>
-          </tr> <?php
-        } ?>
-      </table> <?php
-  } ?>
+    $i = 0;
+    foreach ($s_terms as $cv => $terms) {  
+      // the $headers array is an array of fields to use as the colum headers.
+      // additional documentation can be found here
+      // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
+      $headers = array('Term', 'Definition');
+      
+      // the $rows array contains an array of rows where each row is an array
+      // of values for each column of the table in that row.  Additional documentation
+      // can be found here:
+      // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
+      $rows = array();
+      
+      foreach ($terms as $term) { 
+
+        $accession = $term->cvterm_id->dbxref_id->accession;
+        if (is_numeric($term->cvterm_id->dbxref_id->accession)) {
+          $accession = $term->cvterm_id->dbxref_id->db_id->name . ":" . $term->cvterm_id->dbxref_id->accession;
+        }
+        if ($term->cvterm_id->dbxref_id->db_id->urlprefix) {
+          $accession = l($accession, $term->cvterm_id->dbxref_id->db_id->urlprefix . $accession, array('attributes' => array("target" => '_blank')));
+        } 
+        
+        $rows[] = array(
+          $accession,
+          $term->cvterm_id->name
+        );
+      } 
+      // the $table array contains the headers and rows array as well as other
+      // options for controlling the display of the table.  Additional
+      // documentation can be found here:
+      // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
+      $table = array(
+        'header' => $headers,
+        'rows' => $rows,
+        'attributes' => array(
+          'id' => "tripal_feature-table-terms-$i",
+        ),
+        'sticky' => FALSE,
+        'caption' => ucwords(preg_replace('/_/', ' ', $cv)),
+        'colgroups' => array(),
+        'empty' => '',
+      );
+      
+      // once we have our table array structure defined, we call Drupal's theme_table()
+      // function to generate the table.
+      print theme_table($table);
+      $i++;
+    } ?>
   </div> <?php
 } ?>

+ 1 - 0
tripal_feature/theme/tripal_organism/tripal_organism_feature_counts.tpl.php

@@ -9,6 +9,7 @@ if(property_exists($organism, 'feature_counts')) {
   $names    = $organism->feature_counts['names'];
   $enabled  = $organism->feature_counts['enabled'];
 }
+dpm($organism);
 
 // only show this block if it is enabled
 if ($enabled) { 

+ 208 - 139
tripal_feature/tripal_feature.module

@@ -29,8 +29,7 @@ require_once "includes/tripal_feature.form.inc";
  *
  * @ingroup tripal_feature
  */
-function tripal_feature_init() {
-
+function tripal_feature_init() { 
   drupal_add_css(drupal_get_path('module', 'tripal_feature') . '/theme/css/tripal_feature.css');
   drupal_add_js(drupal_get_path('module', 'tripal_feature') . '/theme/js/tripal_feature.js');
 }
@@ -301,21 +300,26 @@ function tripal_feature_theme($existing, $type, $theme, $path) {
       'base hook' => 'node',
       'path' => "$core_path/theme",
     ),
-    'tripal_organism_feature_browser' => array(
+    'tripal_feature_alignments' => array(
       'variables' => array('node' => NULL),
-      'template' => 'tripal_organism_feature_browser',
-      'path' => "$path/theme/tripal_organism",
+      'template' => 'tripal_feature_alignments',
+      'path' => "$path/theme/tripal_feature",
     ),
-    'tripal_organism_feature_counts' => array(
+    'tripal_feature_analyses' => array(
       'variables' => array('node' => NULL),
-      'template' => 'tripal_organism_feature_counts',
-      'path' => "$path/theme/tripal_organism",
+      'template' => 'tripal_feature_analyses',
+      'path' => "$path/theme/tripal_feature",
     ),
     'tripal_feature_base' => array(
       'variables' => array('node' => NULL),
       'template' => 'tripal_feature_base',
       'path' => "$path/theme/tripal_feature",
     ),
+    'tripal_feature_featurepos' => array(
+      'arguments' => array('node' => NULL),
+      'template' => 'tripal_feature_featurepos',
+      'path' => "$path/theme/tripal_feature",
+    ),
     'tripal_feature_sequence' => array(
       'variables' => array('node' => NULL),
       'template' => 'tripal_feature_sequence',
@@ -336,16 +340,6 @@ function tripal_feature_theme($existing, $type, $theme, $path) {
       'template' => 'tripal_feature_phenotypes',
       'path' => "$path/theme/tripal_feature",
     ),
-    'tripal_feature_featurepos' => array(
-      'arguments' => array('node' => NULL),
-      'template' => 'tripal_feature_featurepos',
-      'path' => "$path/theme/tripal_feature",
-    ),
-    'tripal_feature_featureloc_sequences' => array(
-      'variables' => array('node' => NULL),
-      'template' => 'tripal_feature_featureloc_sequences',
-      'path' => "$path/theme/tripal_feature",
-    ),
     'tripal_feature_references' => array(
       'variables' => array('node' => NULL),
       'template' => 'tripal_feature_references',
@@ -361,11 +355,6 @@ function tripal_feature_theme($existing, $type, $theme, $path) {
       'template' => 'tripal_feature_terms',
       'path' => "$path/theme/tripal_feature",
     ),
-    'tripal_feature_alignments' => array(
-      'variables' => array('node' => NULL),
-      'template' => 'tripal_feature_alignments',
-      'path' => "$path/theme/tripal_feature",
-    ),
     'tripal_feature_relationships' => array(
       'variables' => array('node' => NULL),
       'template' => 'tripal_feature_relationships',
@@ -377,10 +366,29 @@ function tripal_feature_theme($existing, $type, $theme, $path) {
       'path' => drupal_get_path('module', 'tripal_feature') . '/theme'
     ),
 
+    // template for the organism page
+    'tripal_organism_feature_browser' => array(
+      'variables' => array('node' => NULL),
+      'template' => 'tripal_organism_feature_browser',
+      'path' => "$path/theme/tripal_organism",
+    ),
+    'tripal_organism_feature_counts' => array(
+      'variables' => array('node' => NULL),
+      'template' => 'tripal_organism_feature_counts',
+      'path' => "$path/theme/tripal_organism",
+    ),
+    
     // themed forms
     'tripal_feature_seq_extract_form' => array(
        'arguments' => array('form'),
-    )
+    ),
+    
+    // themed teaser
+    'tripal_feature_teaser' => array(
+      'variables' => array('node' => NULL),
+      'template' => 'tripal_feature_teaser',
+      'path' => "$path/theme/tripal_feature",
+    ),
   );
   
   return $items;
@@ -505,70 +513,60 @@ function tripal_feature_block_view($delta = '') {
  * @ingroup tripal_feature
  */
 function chado_feature_insert($node) {
+  
+  $node->uniquename   = trim($node->uniquename);
+  $node->fname        = trim($node->fname);
+  $node->feature_type = trim($node->feature_type);
+  $node->residues     = trim($node->residues);
+  
   // remove spaces, newlines from residues
   $residues = preg_replace("/[\n\r\s]/", "", $node->residues);
   $obsolete = 'FALSE';
   if ($node->is_obsolete) {
     $obsolete = 'TRUE';
   }
+  
+  $feature_id = '';
 
-  // check to see if we are inserting a duplicate record.
-  $values = array(
-    'cv_id' => array(
-      'name' => 'sequence'
-    ),
-    'name' => $node->feature_type
-  );
-  $type = tripal_core_chado_select('cvterm', array('cvterm_id'), $values);
-  $values = array(
-    'organism_id' => $node->organism_id,
-    'name' => $node->fname,
-    'uniquename' => $node->uniquename,
-    'residues' => $residues,
-    'seqlen' => drupal_strlen($residues),
-    'is_obsolete' => $obsolete,
-    'type_id' => $type[0]->cvterm_id,
-    'md5checksum' => md5($residues)
-  );
-  $options = array('is_duplicate' => TRUE, 'has_record' => TRUE);
-  $exists = tripal_core_chado_select('feature', array('*'), $values, $options);
-
-  // if the record is not a duplicate then add it
-  if (!$exists) {
-    $istatus = tripal_core_chado_insert('feature', $values);
-    if (!$istatus) {
+  // if there is an feature_id in the $node object then this must be a sync so
+  // we can skip adding the feature as it is already there, although
+  // we do need to proceed with the rest of the insert
+  if (!property_exists($node, 'feature_id')) {
+    $values = array(
+      'organism_id' => $node->organism_id,
+      'name' => $node->fname,
+      'uniquename' => $node->uniquename,
+      'residues' => $residues,
+      'seqlen' => drupal_strlen($residues),
+      'is_obsolete' => $obsolete,
+      'type_id' => $type[0]->cvterm_id,
+      'md5checksum' => md5($residues)
+    );
+    $feature = tripal_core_chado_select('feature', array('*'), $values);
+    if (!$feature) {
       drupal_set_message(t('Unable to add feature.'), 'warning');
       watchdog('tripal_feature', 'Insert feature: Unable to create feature where values: %values',
         array('%values' => print_r($values, TRUE)), WATCHDOG_WARNING);
+      return;
     }
+    $feature_id = $feature->feature_id;
+    
+    // add the genbank accession and synonyms
+    chado_feature_add_synonyms($node->synonyms, $node->feature_id);
+  }
+  else {
+    $feature_id = $node->feature_id;
   }
 
-  // now get the newly added record
-  $values = array(
-    'organism_id' => $node->organism_id,
-    'uniquename' => $node->uniquename,
-    'type_id' => $type[0]->cvterm_id,
-  );
-  $feature = tripal_core_chado_select('feature', array('feature_id'), $values);
-
-  // add the genbank accession and synonyms
-  chado_feature_add_synonyms($node->synonyms, $feature[0]->feature_id);
-
-  // make sure the entry for this feature doesn't already exist in the chado_feature table
-  // if it doesn't exist then we want to add it.
-  $node_check_sql = "
-    SELECT * FROM {chado_feature}
-    WHERE feature_id = :feature_id
-  ";
-  $node_check = db_query($node_check_sql, array(':feature_id' => $feature[0]->feature_id))->fetchObject();
-  if (!$node_check) {
-    // next add the item to the drupal table
-    $sql = "
-      INSERT INTO {chado_feature} (nid, vid, feature_id, sync_date)
-      VALUES (:nid, :vid, :feature_id, :time)
-    ";
-    db_query($sql, array(':nid' => $node->nid, ':vid' => $node->vid,
-      ':feature_id' => $feature[0]->feature_id, ':time' => REQUEST_TIME));
+  // Make sure the entry for this feature doesn't already exist in the
+  // chado_feature table if it doesn't exist then we want to add it.
+  $check_org_id = chado_get_id_for_node('feature', $node->nid);
+  if (!$check_org_id) {
+    $record = new stdClass();
+    $record->nid = $node->nid;
+    $record->vid = $node->vid;
+    $record->feature_id = $feature_id;
+    drupal_write_record('chado_feature', $record);
   }
 }
 
@@ -578,6 +576,12 @@ function chado_feature_insert($node) {
  * @ingroup tripal_feature
  */
 function chado_feature_update($node) {
+  
+  $node->uniquename   = trim($node->uniquename);
+  $node->fname        = trim($node->fname);
+  $node->feature_type = trim($node->feature_type);
+  $node->residues     = trim($node->residues);
+  
   if ($node->revision) {
     // there is no way to handle revisions in Chado but leave
     // this here just to make not we've addressed it.
@@ -956,12 +960,8 @@ function tripal_feature_load_featurelocs($feature_id, $side = 'as_parent', $aggr
   while ($loc = $flresults->fetchObject()) {
     // if a drupal node exists for this feature then add the nid to the
     // results object
-    $sql = 'SELECT nid FROM {chado_feature} WHERE feature_id = :feature_id';
-
-    $ffeature = db_query($sql, array(':feature_id' => $loc->feature_id))->fetchObject();
-    $sfeature = db_query($sql, array(':feature_id' => $loc->src_feature_id))->fetchObject();
-    $loc->fnid = $ffeature->nid;
-    $loc->snid = $sfeature->nid;
+    $loc->fnid = chado_get_node_id('feature', $loc->feature_id);
+    $loc->snid = chado_get_node_id('feature', $loc->src_feature_id);
     // add the result to the array
     $featurelocs[$i++] = $loc;
   }
@@ -1118,11 +1118,6 @@ function tripal_feature_load_featureloc_sequences($feature_id, $featurelocs) {
   // where this feature is found.   We want to get the sequence for each
   // location and then annotate it with the parts found from the relationships
   // locations determiend above.
-  $sql = "
-    SELECT substring(residues from :start for :size) as residues
-    FROM {feature}
-    WHERE feature_id = :feature_id
-  ";
   $floc_sequences = array();
   foreach ($featurelocs as $featureloc) {
 
@@ -1171,7 +1166,18 @@ function tripal_feature_load_featureloc_sequences($feature_id, $featurelocs) {
 
       $floc_sequences[$src]['src'] = $src;
       $floc_sequences[$src]['type'] = $featureloc->feature_id->type_id->name;
-      $args = array(':start' => $featureloc->fmin + 1, ':size' => ($featureloc->fmax - $featureloc->fmin), ':feature_id' => $featureloc->srcfeature_id->feature_id);
+      $args = array(':feature_id' => $featureloc->srcfeature_id->feature_id);
+      $start = $featureloc->fmin + 1;
+      $size = $featureloc->fmax - $featureloc->fmin;
+      // TODO: fix the hard coded $start and $size
+      // the $start and $size variables are hard-coded in the SQL statement
+      // because the db_query function places quotes around all placeholders
+      // (e.g. :start & :size) and screws up the substring function
+      $sql = "
+        SELECT substring(residues from $start for $size) as residues
+        FROM {feature}
+        WHERE feature_id = :feature_id
+      ";
       $sequence = chado_query($sql, $args)->fetchObject();
       $residues = $sequence->residues;
       if ($featureloc->strand < 0) {
@@ -1588,7 +1594,7 @@ function tripal_feature_color_sequence($sequence, $parts, $defline) {
     }
   }
 
-  $newseq .= "<div id=\"tripal_feature-featureloc_sequence-legend\">Legend: ";
+  $newseq = "<div id=\"tripal_feature-featureloc_sequence-legend\">Legend: ";
   foreach ($types as $type_name => $present) {
     $newseq .= "<span id=\"tripal_feature-legend-$type_name\" class=\"tripal_feature-legend-item tripal_feature-featureloc_sequence-$type_name\" script=\"\">$type_name</span>";
   }
@@ -1602,6 +1608,7 @@ function tripal_feature_color_sequence($sequence, $parts, $defline) {
 
   // iterate through the parts. They should be in order.
   $ends = array();
+  $seqcount = 0;
   foreach ($parts as $index => $types) {
 
     // get the start for this part.  All types in this part start at the
@@ -1641,7 +1648,7 @@ function tripal_feature_color_sequence($sequence, $parts, $defline) {
   }
 
   // add in rest of the sequence
-  for ($i = $pos; $i <= strlen($sequence); $i++) {
+  for ($i = $pos; $i < strlen($sequence); $i++) {
     $newseq .= $sequence{$pos};
     $seqcount++;
     if ($seqcount % 50 == 0) {
@@ -1668,7 +1675,6 @@ function tripal_feature_node_presave($node) {
   // set the title to ensure it is always unique
   switch ($node->type) {
     case 'chado_feature':
-
       $values = array('organism_id' => $node->organism_id);
       $organism = tripal_core_chado_select('organism', array('genus', 'species'), $values);
       $node->title = $node->fname . ', ' . $node->uniquename . ' (' . $node->feature_type . ') ' . $organism[0]->genus . ' ' . $organism[0]->species;
@@ -1711,15 +1717,36 @@ function tripal_feature_node_view($node, $view_mode, $langcode) {
     case 'chado_feature':
       // Show feature browser and counts
       if ($view_mode == 'full') {
+        $node->content['tripal_feature_alignments'] = array(
+          '#value' => theme('tripal_feature_alignments', array('node' => $node)),
+        );
+        $node->content['tripal_feature_analyses'] = array(
+          '#value' => theme('tripal_feature_analyses', array('node' => $node)),
+        );
         $node->content['tripal_feature_base'] = array(
           '#value' => theme('tripal_feature_base', array('node' => $node)),
         );
+        $node->content['tripal_feature_phenotypes'] = array(
+          '#value' => theme('tripal_feature_phenotypes', array('node' => $node)),
+        );
+        $node->content['tripal_feature_properties'] = array(
+          '#value' => theme('tripal_feature_properties', array('node' => $node)),
+        );
+        $node->content['tripal_feature_references'] = array(
+          '#value' => theme('tripal_feature_references', array('node' => $node)),
+        );
+        $node->content['tripal_feature_relationships'] = array(
+          '#value' => theme('tripal_feature_relationships', array('node' => $node)),
+        );
         $node->content['tripal_feature_seqence'] = array(
           '#value' => theme('tripal_feature_sequence', array('node' => $node)),
         );
         $node->content['tripal_feature_synonyms'] = array(
           '#value' => theme('tripal_feature_synonyms', array('node' => $node)),
         );
+        $node->content['tripal_feature_terms'] = array(
+          '#value' => theme('tripal_feature_terms', array('node' => $node)),
+        );
       }
       if ($view_mode == 'teaser') {
         $node->content['tripal_feature_teaser'] = array(
@@ -1767,7 +1794,33 @@ function tripal_feature_node_update($node) {
   }
 }
 
+/**
+ * @ingroup tripal_feature
+ */
+function tripal_feature_preprocess_tripal_feature_sequence(&$variables) {
+  // we want to provide a new variable that contains the matched features.
+  $feature = $variables['node']->feature;
+  
+  // get the featureloc src features
+  $options = array(
+    'return_array' => 1,
+    'include_fk' => array(
+      'srcfeature_id' => array(
+        'type_id' => 1
+      ),
+    ),
+  );
 
+  $feature = tripal_core_expand_chado_vars($feature, 'table', 'featureloc', $options);
+  
+  // because there are two foriegn keys in the featureloc table with the feature table
+  // we have to access the records for each by specifying the field name after the table name:
+  $ffeaturelocs = $feature->featureloc->feature_id;
+  
+  // now extract the sequences
+  $featureloc_sequences = tripal_feature_load_featureloc_sequences($feature->feature_id, $ffeaturelocs);
+  $feature->featureloc_sequences = $featureloc_sequences;
+}
 /**
  *
  *
@@ -1777,7 +1830,7 @@ function tripal_feature_preprocess_tripal_feature_relationships(&$variables) {
   // we want to provide a new variable that contains the matched features.
   $feature = $variables['node']->feature;
 
-  if (!$feature->all_relationships) {
+  if (!property_exists($feature, 'all_relationships')) {
     $feature->all_relationships = tripal_feature_get_feature_relationships($feature);
   }
 }
@@ -1791,7 +1844,7 @@ function tripal_feature_preprocess_tripal_feature_proteins(&$variables) {
   // we want to provide a new variable that contains the matched features.
   $feature = $variables['node']->feature;
 
-  if (!$feature->all_relationships) {
+  if (!property_exists($feature, 'all_relationships')) {
     $feature->all_relationships = tripal_feature_get_feature_relationships($feature);
   }
 }
@@ -1804,65 +1857,74 @@ function tripal_feature_preprocess_tripal_feature_alignments(&$variables) {
 
   // we want to provide a new variable that contains the matched features.
   $feature = $variables['node']->feature;
-  $feature = tripal_core_expand_chado_vars($feature, 'table', 'featureloc');
+  $options = array(
+    'return_array' => 1,
+    'include_fk' => array(
+      'srcfeature_id' => array(
+        'type_id' => 1,
+      ),
+      'feature_id' => array(
+        'type_id' => 1
+      ),
+    )
+  );
+  $feature = tripal_core_expand_chado_vars($feature, 'table', 'featureloc', $options);
 
   // get alignments as child
   $cfeaturelocs = $feature->featureloc->feature_id;
   if (!$cfeaturelocs) {
-     $cfeaturelocs = array();
-  }
-  elseif (!is_array($cfeaturelocs)) {
-     $cfeaturelocs = array($cfeaturelocs);
+    $cfeaturelocs = array();
   }
   // get alignment as parent
   $pfeaturelocs = $feature->featureloc->srcfeature_id;
   if (!$pfeaturelocs) {
-     $pfeaturelocs = array();
-  }
-  elseif (!is_array($pfeaturelocs)) {
-     $pfeaturelocs = array($pfeaturelocs);
+    $pfeaturelocs = array();
   }
 
   // get matched alignments (those with an itermediate 'match' or 'EST_match', etc
   $mfeaturelocs = tripal_feature_get_matched_alignments($feature);
-  $feature->matched_featurelocs = mfeaturelocs;
+  $feature->matched_featurelocs = $mfeaturelocs;
 
   // combine all three alignments into a single array for printing together in
   // a single list
   $alignments = array();
   foreach ($pfeaturelocs as $featureloc) {
-     // if type is a 'match' then ignore it. We will handle those below
-     if (preg_match('/(^match$|^.*?_match|match_part)$/', $featureloc->feature_id->type_id->name)) {
-        continue;
-     }
-     $alignment = new stdClass();
-     $alignment->record = $featureloc;
-     $alignment->name = $featureloc->feature_id->name;
-     $alignment->nid = $featureloc->feature_id->nid;
-     $alignment->type = $featureloc->feature_id->type_id->name;
-     $alignment->fmin = $featureloc->fmin;
-     $alignment->fmax = $featureloc->fmax;
-     $alignment->phase = $featureloc->phase;
-     $alignment->strand = $featureloc->strand;
-     $alignments[] = $alignment;
+    // if type is a 'match' then ignore it. We will handle those below
+    if (preg_match('/(^match$|^.*?_match|match_part)$/', $featureloc->feature_id->type_id->name)) {
+       continue;
+    }
+    $alignment = new stdClass();
+    $alignment->record = $featureloc;
+    $alignment->name = $featureloc->feature_id->name;
+    $alignment->type = $featureloc->feature_id->type_id->name;
+    $alignment->fmin = $featureloc->fmin;
+    $alignment->fmax = $featureloc->fmax;
+    $alignment->phase = $featureloc->phase;
+    $alignment->strand = $featureloc->strand;
+    $alignments[] = $alignment;
+    if (property_exists($featureloc->feature_id, 'nid')) {
+      $alignment->nid = $featureloc->feature_id->nid;
+    }
   }
   foreach ($cfeaturelocs as $featureloc) {
-     // if type is a 'match' then ignore it. We will handle those below
-     if (preg_match('/(^match$|^.*?_match|match_part)$/', $featureloc->feature_id->type_id->name)) {
-        continue;
-     }
-     $alignment = new stdClass();
-     $alignment->record = $featureloc;
-     $alignment->name = $featureloc->srcfeature_id->name;
-     $alignment->nid = $featureloc->srcfeature_id->nid;
-     $alignment->type = $featureloc->srcfeature_id->type_id->name;
-     $alignment->fmin = $featureloc->fmin;
-     $alignment->is_fmin_partial = $featureloc->is_fmin_partial;
-     $alignment->fmax = $featureloc->fmax;
-     $alignment->is_fmax_partial = $featureloc->is_fmax_partial;
-     $alignment->phase = $featureloc->phase;
-     $alignment->strand = $featureloc->strand;
-     $alignments[] = $alignment;
+    // if type is a 'match' then ignore it. We will handle those below
+    if (preg_match('/(^match$|^.*?_match|match_part)$/', $featureloc->feature_id->type_id->name)) {
+      continue;
+    }
+    $alignment = new stdClass();
+    $alignment->record = $featureloc;
+    $alignment->name = $featureloc->srcfeature_id->name;    
+    $alignment->type = $featureloc->srcfeature_id->type_id->name;
+    $alignment->fmin = $featureloc->fmin;
+    $alignment->is_fmin_partial = $featureloc->is_fmin_partial;
+    $alignment->fmax = $featureloc->fmax;
+    $alignment->is_fmax_partial = $featureloc->is_fmax_partial;
+    $alignment->phase = $featureloc->phase;
+    $alignment->strand = $featureloc->strand;
+    $alignments[] = $alignment;
+    if (property_exists($featureloc->srcfeature_id, 'nid')) {
+      $alignment->nid = $featureloc->srcfeature_id->nid;
+    }
   }
   // in matching features, the left feature is always the feature
   // provided to this function.
@@ -1875,7 +1937,6 @@ function tripal_feature_preprocess_tripal_feature_alignments(&$variables) {
      $alignment->record = $featureloc;
      $alignment->right_feature = $rfeature;
      $alignment->name = $rfeature->name;
-     $alignment->nid = $rfeature->nid;
      $alignment->type = $rfeature->type_id->name;
      $alignment->fmin = $featureloc->left_fmin;
      $alignment->is_fmin_partial = $featureloc->left_is_fmin_partial;
@@ -1890,6 +1951,9 @@ function tripal_feature_preprocess_tripal_feature_alignments(&$variables) {
      $alignment->right_phase = $featureloc->right_phase;
      $alignment->right_strand = $featureloc->right_strand;
      $alignments[] = $alignment;
+     if (property_exists($rfeature, 'nid')) {
+       $alignment->nid = $rfeature->nid;
+     }
   }
   $feature->all_featurelocs = $alignments;
 }
@@ -1899,8 +1963,8 @@ function tripal_feature_preprocess_tripal_feature_alignments(&$variables) {
  * @ingroup tripal_feature
  */
 function tripal_feature_preprocess_tripal_organism_feature_counts(&$variables, $hook) {
- // $organism = $variables['node']->organism;
-  //$organism->feature_counts = tripal_feature_load_organism_feature_counts($organism);
+  $organism = $variables['node']->organism;
+  $organism->feature_counts = tripal_feature_load_organism_feature_counts($organism);
 }
 
 /**
@@ -1909,8 +1973,8 @@ function tripal_feature_preprocess_tripal_organism_feature_counts(&$variables, $
  * @ingroup tripal_feature
  */
 function tripal_feature_preprocess_tripal_organism_feature_browser(&$variables, $hook) {
-  //$organism = $variables['node']->organism;
-  //$organism->feature_browser = tripal_feature_load_organism_feature_browser($organism);
+  $organism = $variables['node']->organism;
+  $organism->feature_browser = tripal_feature_load_organism_feature_browser($organism);
 }
 
 /**
@@ -2117,8 +2181,13 @@ function tripal_feature_job_describe_args($callback, $args) {
     $new_args['Import all and update'] = ($args[4] == 1) ? "Yes" : "No";
     $new_args['Import all and replace'] = ($args[5] == 1) ? "Yes" : "No";
     $new_args['Delete features'] = ($args[6] == 1) ? "Yes" : "No";
-    $target_organism = tripal_core_chado_select('organism', array('genus', 'species'), array('organism_id' => $args[8]));
-    $new_args['Target organism'] = $target_organism[0]->genus . " " . $target_organism[0]->species;
+    if ($args[8]) {
+      $target_organism = tripal_core_chado_select('organism', array('genus', 'species'), array('organism_id' => $args[8]));
+      $new_args['Target organism'] = $target_organism[0]->genus . " " . $target_organism[0]->species;
+    }
+    else {
+      $new_args['Target organism'] = '';
+    }
     $new_args['Target type'] = $args[9];
     $new_args['Create target'] = ($args[10] == 1) ? "Yes" : "No";
     $new_args['Starting line'] = $args[11];

+ 0 - 10
tripal_organism/tripal_organism.install

@@ -78,16 +78,6 @@ function tripal_organism_schema() {
  */
 function tripal_organism_uninstall() {
 
-  // Get the list of nodes to remove
-  $sql_lib_id = "
-    SELECT nid, vid
-    FROM {node}
-    WHERE type='chado_organism'
-  ";
-  $result = db_query($sql_lib_id);
-  foreach ($result as $node) {
-    node_delete($node->nid);
-  }
 }
 
 /**

+ 1 - 1
tripal_views/views/handlers/tripal_views_handler_filter_select_string.inc

@@ -143,7 +143,7 @@ class tripal_views_handler_filter_select_string extends views_handler_filter_str
   /**
    * Set values for my options
    */
-  function expose_submit(&$form, &$form_state) {
+  function expose_submit($form, &$form_state) {
     $this->options['expose']['values_form_type'] = $form_state['values']['options']['expose']['values_form_type'];
     $this->options['expose']['select_multiple'] = $form_state['values']['options']['expose']['select_multiple'];
     $this->options['expose']['select_optional'] = $form_state['values']['options']['expose']['select_optional'];