Browse Source

Fixed merge conflicts

Chun-Huai Cheng 8 years ago
parent
commit
5718f9eff4
32 changed files with 1314 additions and 1019 deletions
  1. 2 3
      tripal/api/tripal.entities.api.inc
  2. 4 6
      tripal/includes/TripalEntityUIController.inc
  3. 4 1
      tripal/includes/tripal.entity.inc
  4. 1 1
      tripal/tripal.module
  5. 326 1
      tripal_chado/api/modules/tripal_chado.feature.api.inc
  6. 1 1
      tripal_chado/api/tripal_chado.mviews.api.inc
  7. 2 2
      tripal_chado/api/tripal_chado.query.api.inc
  8. 39 9
      tripal_chado/api/tripal_chado.schema.api.inc
  9. 4 1
      tripal_chado/api/tripal_chado.variables.api.inc
  10. 4 4
      tripal_chado/includes/TripalFields.old/chado_linker__expression.inc
  11. 13 12
      tripal_chado/includes/TripalFields/chado_linker__contact_widget.inc
  12. 81 0
      tripal_chado/includes/TripalFields/data__protein_sequence.inc
  13. 50 0
      tripal_chado/includes/TripalFields/data__protein_sequence_formatter.inc
  14. 43 0
      tripal_chado/includes/TripalFields/data__protein_sequence_widget.inc
  15. 90 477
      tripal_chado/includes/TripalFields/data__sequence.inc
  16. 0 7
      tripal_chado/includes/TripalFields/data__sequence_checksum.inc
  17. 5 16
      tripal_chado/includes/TripalFields/data__sequence_formatter.inc
  18. 0 7
      tripal_chado/includes/TripalFields/data__sequence_length.inc
  19. 10 11
      tripal_chado/includes/TripalFields/go__gene_expression.inc
  20. 16 16
      tripal_chado/includes/TripalFields/sbo__database_cross_reference_widget.inc
  21. 48 52
      tripal_chado/includes/TripalFields/sbo__relationship.inc
  22. 134 114
      tripal_chado/includes/TripalFields/sbo__relationship_widget.inc
  23. 16 16
      tripal_chado/includes/TripalFields/schema__alternate_name_widget.inc
  24. 96 0
      tripal_chado/includes/TripalFields/so__cds.inc
  25. 44 0
      tripal_chado/includes/TripalFields/so__cds_formatter.inc
  26. 43 0
      tripal_chado/includes/TripalFields/so__cds_widget.inc
  27. 45 53
      tripal_chado/includes/TripalFields/so__transcript.inc
  28. 1 1
      tripal_chado/includes/tripal_chado.custom_tables.inc
  29. 89 105
      tripal_chado/includes/tripal_chado.field_storage.inc
  30. 78 79
      tripal_chado/includes/tripal_chado.fields.inc
  31. 20 20
      tripal_chado/includes/tripal_chado.mapping.inc
  32. 5 4
      tripal_chado/includes/tripal_chado.migrate.inc

+ 2 - 3
tripal/api/tripal.entities.api.inc

@@ -16,7 +16,7 @@
  * @param $ids
  *   An array of entity IDs, or FALSE to load all entities.
  * @param $reset: Whether to reset the internal cache for the requested entity
- *   type. Unlike the entity_load() function this defaults to TRUE.
+ *   type. Defaults to FALSE.
  * @param $field_ids
  *   A list of numeric feild IDs that should be loaded.  The
  *   TripalField named 'content_type' is always automatically added.
@@ -25,7 +25,7 @@
  *   An array of entity objects indexed by their ids. When no results are
  *   found, an empty array is returned.
  */
-function tripal_load_entity($entity_type, $ids = FALSE, $reset = TRUE,
+function tripal_load_entity($entity_type, $ids = FALSE, $reset = FALSE,
     $field_ids = array()) {
 
   // The $conditions is deprecated in the funtion arguments of entity_load
@@ -45,7 +45,6 @@ function tripal_load_entity($entity_type, $ids = FALSE, $reset = TRUE,
   if ($reset) {
     $ec->resetCache();
   }
-
   return $ec->load($ids, $conditions, $field_ids);
 }
 /**

+ 4 - 6
tripal/includes/TripalEntityUIController.inc

@@ -435,13 +435,11 @@ function tripal_entity_form_ajax_callback($form, $form_state) {
          if (!preg_match('/^\d+$/', $delta)) {
            continue;
          }
-         if (array_key_exists('#field', $field_form)) {
+         $widget_type = $instance['widget']['type'];
+         if (tripal_load_include_field_class($widget_type)) {
            $field = $field_form['#field'];
-           $field_type = $field['type'];
-           if (class_exists($field_type)) {
-             $tfield = new $field_type($field, $instance);
-             $tfield->widgetFormSubmit($form, $form_state, $entity_type, $entity, $langcode, $delta);
-           }
+           $widget = new $widget_type($field, $instance);
+           $widget->submit($form, $form_state, $entity_type, $entity, $langcode, $delta);
          }
        }
      }

+ 4 - 1
tripal/includes/tripal.entity.inc

@@ -159,7 +159,10 @@ function tripal_entity_info() {
     'access callback' => 'tripal_entity_access',
 
     // FALSE disables caching. Caching functionality is handled by Drupal core.
-    'static cache' => FALSE,
+    'static cache' => TRUE,
+
+    // Caching of fields
+    'field cache' => TRUE,
 
     // Bundles are added dynamically below.
     'bundles' => array (),

+ 1 - 1
tripal/tripal.module

@@ -521,7 +521,7 @@ function TripalBundle_load($bundle_type, $reset = FALSE) {
  *
  * @see tripal_entity_load_multiple()
  */
-function TripalEntity_load($id, $reset = TRUE) {
+function TripalEntity_load($id, $reset = FALSE) {
   // $entity = entity_load('TripalEntity', array($id), array(), $reset);
   $entity = tripal_load_entity('TripalEntity', array($id), $reset);
   return reset($entity);

+ 326 - 1
tripal_chado/api/modules/tripal_chado.feature.api.inc

@@ -915,4 +915,329 @@ function tripal_get_feature_relationships($feature) {
     }
   }
   return $relationships;
-}
+}
+
+/**
+ *
+ * @param unknown $feature_id
+ * @param unknown $featurelocs
+ * @return multitype:|Ambigous <multitype:, an>
+ */
+function chado_get_featureloc_sequences($feature_id, $featurelocs) {
+
+  // if we don't have any featurelocs then no point in continuing
+  if (!$featurelocs) {
+    return array();
+  }
+
+  // get the list of relationships (including any aggregators) and iterate
+  // through each one to find information needed to color-code the reference sequence
+  $relationships = chado_get_feature_aggregate_relationships($feature_id);
+  if (!$relationships) {
+    return array();
+  }
+
+
+  // iterate through each of the realtionships features and get their
+  // locations
+  foreach ($relationships as $rindex => $rel) {
+    // get the featurelocs for each of the relationship features
+    $rel_featurelocs = chado_get_featurelocs($rel->subject_id, 'as_child', 0);
+    foreach ($rel_featurelocs as $rfindex => $rel_featureloc) {
+      // keep track of this unique source feature
+      $src = $rel_featureloc->src_feature_id . "-" . $rel_featureloc->src_cvterm_id;
+
+      // copy over the results to the relationship object.  Since there can
+      // be more than one feature location for each relationship feature we
+      // use the '$src' variable to keep track of these.
+      $rel->featurelocs = new stdClass();
+      $rel->featurelocs->$src = new stdClass();
+      $rel->featurelocs->$src->src_uniquename = $rel_featureloc->src_uniquename;
+      $rel->featurelocs->$src->src_cvterm_id  = $rel_featureloc->src_cvterm_id;
+      $rel->featurelocs->$src->src_cvname     = $rel_featureloc->src_cvname;
+      $rel->featurelocs->$src->fmin           = $rel_featureloc->fmin;
+      $rel->featurelocs->$src->fmax           = $rel_featureloc->fmax;
+      $rel->featurelocs->$src->src_name       = $rel_featureloc->src_name;
+
+      // keep track of the individual parts for each relationship
+      $start = $rel->featurelocs->$src->fmin;
+      $end   = $rel->featurelocs->$src->fmax;
+      $type  = $rel->subject_type;
+      $rel_locs[$src]['parts'][$start][$type]['start'] = $start;
+      $rel_locs[$src]['parts'][$start][$type]['end']   = $end;
+      $rel_locs[$src]['parts'][$start][$type]['type']  = $type;
+    }
+  }
+
+  // the featurelocs array provided to the function contains the locations
+  // 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.
+  $floc_sequences = array();
+  foreach ($featurelocs as $featureloc) {
+
+    // build the src name so we can keep track of the different parts for each feature
+    $src = $featureloc->srcfeature_id->feature_id . "-" . $featureloc->srcfeature_id->type_id->cvterm_id;
+
+    // orient the parts to the beginning of the feature sequence
+    if (!empty($rel_locs[$src]['parts'])) {
+      $parts = $rel_locs[$src]['parts'];
+      $rparts = array();  // we will fill this up if we're on the reverse strand
+
+      foreach ($parts as $start => $types) {
+        foreach ($types as $type_name => $type) {
+          if ($featureloc->strand >= 0) {
+            // this is on the forward strand.  We need to convert the start on the src feature to the
+            // start on this feature's sequence
+            $parts[$start][$type_name]['start'] = $parts[$start][$type_name]['start'] - $featureloc->fmin;
+            $parts[$start][$type_name]['end']   = $parts[$start][$type_name]['end'] - $featureloc->fmin;
+            $parts[$start][$type_name]['type']  = $type_name;
+          }
+          else {
+            // this is on the reverse strand.  We need to swap the start and stop and calculate from the
+            // begining of the reverse sequence
+            $size = ($featureloc->fmax - $featureloc->fmin);
+            $start_orig = $parts[$start][$type_name]['start'];
+            $end_orig = $parts[$start][$type_name]['end'];
+            $new_start = $size - ($end_orig - $featureloc->fmin);
+            $new_end = $size - ($start_orig - $featureloc->fmin);
+
+            $rparts[$new_start][$type_name]['start'] = $new_start;
+            $rparts[$new_start][$type_name]['end']   = $new_end;
+            $rparts[$new_start][$type_name]['type']  = $type_name;
+          }
+        }
+      }
+
+      // now sort the parts
+      // if we're on the reverse strand we need to resort
+      if ($featureloc->strand >= 0) {
+        usort($parts, 'chado_feature__residues_sort_rel_parts_by_start');
+      }
+      else {
+        usort($rparts, 'chado_feature__residues_sort_rel_parts_by_start');
+        $parts = $rparts;
+      }
+
+      $floc_sequences[$src]['id'] = $src;
+      $floc_sequences[$src]['type'] = $featureloc->feature_id->type_id->name;
+      $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) {
+        $residues = tripal_reverse_compliment_sequence($residues);
+      }
+      $strand = '.';
+      if ($featureloc->strand == 1) {
+        $strand = '+';
+      }
+      elseif ($featureloc->strand == -1) {
+        $strand = '-';
+      }
+      $floc_sequences[$src]['location'] = tripal_get_location_string($featureloc);
+      $floc_sequences[$src]['defline'] = tripal_get_fasta_defline($featureloc->feature_id, '', $featureloc, '', strlen($residues));
+      $floc_sequences[$src]['featureloc'] = $featureloc;
+      $floc_sequences[$src]['residues'] = $residues;
+      //$floc_sequences[$src]['formatted_seq'] =  tripal_feature_color_sequence($residues, $parts, $floc_sequences[$src]['defline']);
+    }
+  }
+  return $floc_sequences;
+}
+
+/**
+ * Get features related to the current feature to a given depth. Recursive function.
+ *
+ * @param $feature_id
+ * @param $substitute
+ * @param $levels
+ * @param $base_type_id
+ * @param $depth
+ *
+ */
+function chado_get_aggregate_feature_relationships($feature_id, $substitute=1,
+  $levels=0, $base_type_id=NULL, $depth=0) {
+
+  // we only want to recurse to as many levels deep as indicated by the
+  // $levels variable, but only if this variable is > 0. If 0 then we
+  // recurse until we reach the end of the relationships tree.
+  if ($levels > 0 and $levels == $depth) {
+    return NULL;
+  }
+
+  // first get the relationships for this feature
+  return chado_get_feature_relationships($feature_id, 'as_object');
+
+}
+
+/**
+ * Get the relationships for a feature.
+ *
+ * @param $feature_id
+ *   The feature to get relationships for
+ * @param $side
+ *   The side of the relationship this feature is (ie: 'as_subject' or 'as_object')
+ *
+ */
+function chado_get_feature_relationships($feature_id, $side = 'as_subject') {
+  // get the relationships for this feature.  The query below is used for both
+  // querying the object and subject relationships
+  $sql = "
+    SELECT
+    FS.name as subject_name, FS.uniquename as subject_uniquename,
+      CVTS.name as subject_type, CVTS.cvterm_id as subject_type_id,
+      FR.subject_id, FR.type_id as relationship_type_id, FR.object_id, FR.rank,
+      CVT.name as rel_type,
+      FO.name as object_name, FO.uniquename as object_uniquename,
+      CVTO.name as object_type, CVTO.cvterm_id as object_type_id
+    FROM {feature_relationship} FR
+     INNER JOIN {cvterm} CVT  ON FR.type_id    = CVT.cvterm_id
+     INNER JOIN {feature} FS  ON FS.feature_id = FR.subject_id
+     INNER JOIN {feature} FO  ON FO.feature_id = FR.object_id
+     INNER JOIN {cvterm} CVTO ON FO.type_id    = CVTO.cvterm_id
+     INNER JOIN {cvterm} CVTS ON FS.type_id    = CVTS.cvterm_id
+  ";
+  if (strcmp($side, 'as_object')==0) {
+    $sql .= " WHERE FR.object_id = :feature_id";
+  }
+  if (strcmp($side, 'as_subject')==0) {
+    $sql .= " WHERE FR.subject_id = :feature_id";
+  }
+  $sql .= " ORDER BY FR.rank";
+
+  // get the relationships
+  $results = chado_query($sql, array(':feature_id' => $feature_id));
+
+  // iterate through the relationships, put these in an array and add
+  // in the Drupal node id if one exists
+  $i=0;
+  $esql = "
+    SELECT entity_id
+    FROM {chado_entity}
+    WHERE data_table = 'feature' AND record_id = :feature_id";
+  $relationships = array();
+  while ($rel = $results->fetchObject()) {
+    $entity = db_query($esql, array(':feature_id' => $rel->subject_id))->fetchObject();
+    if ($entity) {
+      $rel->subject_entity_id = $entity->entity_id;
+    }
+    $entity = db_query($esql, array(':feature_id' => $rel->object_id))->fetchObject();
+    if ($entity) {
+      $rel->object_entity_id = $entity->entity_id;
+    }
+    $relationships[$i++] = $rel;
+  }
+  return $relationships;
+}
+
+/**
+ * Load the locations for a given feature
+ *
+ * @param $feature_id
+ *   The feature to look up locations for
+ * @param $side
+ *   Whether the feature is the scrfeature, 'as_parent', or feature, 'as_child'
+ * @param $aggregate
+ *   Whether or not to get the locations for related features
+ *
+ * @ingroup tripal_feature
+ */
+function chado_get_featurelocs($feature_id, $side = 'as_parent', $aggregate = 1) {
+
+  $sql = "
+    SELECT
+       F.name, F.feature_id, F.uniquename,
+       FS.name as src_name, FS.feature_id as src_feature_id, FS.uniquename as src_uniquename,
+       CVT.name as cvname, CVT.cvterm_id,
+       CVTS.name as src_cvname, CVTS.cvterm_id as src_cvterm_id,
+       FL.fmin, FL.fmax, FL.is_fmin_partial, FL.is_fmax_partial,FL.strand, FL.phase
+     FROM {featureloc} FL
+       INNER JOIN {feature} F   ON FL.feature_id = F.feature_id
+       INNER JOIN {feature} FS  ON FS.feature_id = FL.srcfeature_id
+       INNER JOIN {cvterm} CVT  ON F.type_id     = CVT.cvterm_id
+       INNER JOIN {cvterm} CVTS ON FS.type_id    = CVTS.cvterm_id
+       ";
+  if (strcmp($side, 'as_parent')==0) {
+    $sql .= "WHERE FL.srcfeature_id = :feature_id ";
+  }
+  if (strcmp($side, 'as_child')==0) {
+    $sql .= "WHERE FL.feature_id = :feature_id ";
+  }
+
+  $flresults = chado_query($sql, array(':feature_id' => $feature_id));
+
+  // copy the results into an array
+  $i=0;
+  $featurelocs = array();
+  while ($loc = $flresults->fetchObject()) {
+    // if a drupal node exists for this feature then add the nid to the
+    // results object
+
+    $loc->feid = tripal_get_chado_entity_id('feature', $loc->feature_id);
+    $loc->seid = tripal_get_chado_entity_id('feature', $loc->src_feature_id);
+    // add the result to the array
+    $featurelocs[$i++] = $loc;
+  }
+
+  // Add the relationship feature locs if aggregate is turned on
+  if ($aggregate and strcmp($side, 'as_parent')==0) {
+  // get the relationships for this feature without substituting any children
+  // for the parent. We want all relationships
+  $relationships = tripal_feature_get_aggregate_relationships($feature_id, 0);
+  foreach ($relationships as $rindex => $rel) {
+    // get the featurelocs for each of the relationship features
+    $rel_featurelocs = tripal_feature_load_featurelocs($rel->subject_id, 'as_child', 0);
+      foreach ($rel_featurelocs as $findex => $rfloc) {
+        $featurelocs[$i++] = $rfloc;
+      }
+    }
+  }
+
+  usort($featurelocs, 'chado_feature__residues_sort_locations');
+  return $featurelocs;
+}
+
+/**
+  * Used to sort the list of relationship parts by start position
+  *
+  * @ingroup tripal_feature
+  */
+function chado_feature__residues_sort_rel_parts_by_start($a, $b) {
+  foreach ($a as $type_name => $details) {
+    $astart = $a[$type_name]['start'];
+    break;
+  }
+  foreach ($b as $type_name => $details) {
+    $bstart = $b[$type_name]['start'];
+    break;
+  }
+  return strnatcmp($astart, $bstart);
+}
+/**
+ * Used to sort the feature locs by start position
+ *
+ * @param $a
+ *   One featureloc record (as an object)
+ * @param $b
+ *   The other featureloc record (as an object)
+ *
+ * @return
+ *   Which feature location comes first
+ *
+ * @ingroup tripal_feature
+ */
+function chado_feature__residues_sort_locations($a, $b) {
+  return strnatcmp($a->fmin, $b->fmin);
+}
+

+ 1 - 1
tripal_chado/api/tripal_chado.mviews.api.inc

@@ -397,7 +397,7 @@ function tripal_delete_mview($mview_id) {
   db_query($sql);
 
   // does the table already exist?
-  $mview_exists = db_table_exists('chado.' . $mview->mv_table);
+  $mview_exists = chado_table_exists($mview->mv_table);
 
   // drop the table from chado if it exists
   if ($mview_exists) {

+ 2 - 2
tripal_chado/api/tripal_chado.query.api.inc

@@ -1394,9 +1394,9 @@ function chado_select_record($table, $columns, $values, $options = NULL) {
           // Ensure that there were results returned.
           elseif (count($results)==0) {
             tripal_report_error('tripal_chado', TRIPAL_ERROR,
-              'chado_select_record: the foreign key definition for \'%field\' '.
+              'chado_select_record: the foreign key definition for \'%field\' on table \'%table\' '.
               'returned no results where the definition supplied was %value',
-              array('%field' => $field, '%value' => print_r($value, TRUE))
+              array('%field' => $field, '%table' => $table, '%value' => print_r($value, TRUE))
             );
             return array();
           }

+ 39 - 9
tripal_chado/api/tripal_chado.schema.api.inc

@@ -38,22 +38,34 @@
  */
 function chado_table_exists($table) {
   global $databases;
-
   $default_db = $databases['default']['default']['database'];
-
+  $cached_obj = cache_get('chado_tables', 'cache');
+  $cached_tables = $cached_obj->data;
+  if (is_array($cached_tables) and array_key_exists($table, $cached_tables)) {
+    return $cached_tables[$table]['exists'];
+  }
   $sql = "
     SELECT 1
     FROM information_schema.tables
     WHERE
       table_name = :table_name AND
-      table_schema = 'chado' AND
-      table_catalog = '$default_db'
+      table_schema = :chado AND
+      table_catalog = :default_db
   ";
-  $results = db_query($sql, array(':table_name' => $table));
+  $args = array(
+    ':table_name' => $table,
+    ':chado' => tripal_get_schema_name('chado'),
+    ':default_db' => $default_db
+  );
+  $results = db_query($sql, $args);
   $exists = $results->fetchObject();
   if (!$exists) {
+    $cached_tables[$table]['exists'] = FALSE;
+    cache_set('chado_tables', $cached_tables, 'cache', CACHE_TEMPORARY);
     return FALSE;
   }
+  $cached_tables[$table]['exists'] = TRUE;
+  cache_set('chado_tables', $cached_tables, 'cache', CACHE_TEMPORARY);
   return TRUE;
 }
 /**
@@ -77,7 +89,13 @@ function chado_column_exists($table, $column) {
   global $databases;
 
   $default_db = $databases['default']['default']['database'];
-
+  $cached_obj = cache_get('chado_table_columns', 'cache');
+  $cached_cols = $cached_obj->data;
+  if (is_array($cached_cols) and
+      array_key_exists($table, $cached_cols) and
+      array_key_Exists($column, $cached_cols[$table])) {
+    return $cached_cols[$table][$column]['exists'];
+  }
   $sql = "
     SELECT 1
     FROM information_schema.columns
@@ -96,8 +114,12 @@ function chado_column_exists($table, $column) {
   $results = db_query($sql, $args);
   $exists = $results->fetchField();
   if (!$exists) {
+    $cached_cols[$table][$column]['exists'] = FALSE;
+    cache_set('chado_table_columns', $cached_cols, 'cache', CACHE_TEMPORARY);
     return FALSE;
   }
+  $cached_cols[$table][$column]['exists'] = TRUE;
+  cache_set('chado_table_columns', $cached_cols, 'cache', CACHE_TEMPORARY);
   return TRUE;
 }
 
@@ -118,7 +140,11 @@ function chado_sequence_exists($sequence) {
   global $databases;
 
   $default_db = $databases['default']['default']['database'];
-
+  $cached_obj = cache_get('chado_sequences', 'cache');
+  $cached_seqs = $cached_obj->data;
+  if (is_array($cached_seqs) and array_key_exists($sequence, $cached_seqs)) {
+    return $cached_seqs[$sequence]['exists'];
+  }
   $sql = "
     SELECT 1
     FROM information_schema.sequences
@@ -135,8 +161,12 @@ function chado_sequence_exists($sequence) {
   $results = db_query($sql, $args);
   $exists = $results->fetchField();
   if (!$exists) {
+    $cached_seqs[$sequence]['exists'] = FALSE;
+    cache_set('chado_sequences', $cached_seqs, 'cache', CACHE_TEMPORARY);
     return FALSE;
   }
+  $cached_seqs[$sequence]['exists'] = FALSE;
+  cache_set('chado_sequences', $cached_seqs, 'cache', CACHE_TEMPORARY);
   return TRUE;
 }
 /**
@@ -314,12 +344,12 @@ function chado_get_version($exact = FALSE, $warn_if_unsupported = FALSE) {
     }
     $is_local = 0;
     $previous_db = chado_set_active('chado');
-    $prop_exists = db_table_exists('chadoprop');
+    $prop_exists = chado_table_exists('chadoprop');
     chado_set_active($previous_db);
   }
   else {
     $is_local = 1;
-    $prop_exists = db_table_exists('chado.chadoprop');
+    $prop_exists = chado_table_exists('chadoprop');
   }
 
   // if the table doesn't exist then we don't know what version but we know

+ 4 - 1
tripal_chado/api/tripal_chado.variables.api.inc

@@ -278,7 +278,10 @@ function chado_generate_var($table, $values, $base_options = array()) {
   $results = chado_select_record($table, $table_columns, $values, $base_options);
 
   if ($results) {
+
+    // Iterate through each result.
     foreach ($results as $key => $object) {
+
       // Add empty expandable_x arrays
       $object->expandable_fields = $all->expandable_fields;
       $object->expandable_foreign_keys = $all->expandable_foreign_keys;
@@ -290,7 +293,7 @@ function chado_generate_var($table, $values, $base_options = array()) {
       // For Tripal v2 compatibility
       // check if the current table maps to a node type-----------------------------------------------
       // if this table is connected to a node there will be a chado_tablename table in drupal
-      if (db_table_exists('chado_' . $table)) {
+      if (module_exists('tripal_core') and db_table_exists('chado_' . $table)) {
         // that has a foreign key to this one ($table_desc['primary key'][0]
         // and to the node table (nid)
         $sql = "

+ 4 - 4
tripal_chado/includes/TripalFields.old/chado_linker__expression.inc

@@ -22,7 +22,7 @@ class chado_linker__expression extends TripalField {
   // Set this to the name of the storage backend that by default will support
   // this field.
   public static $default_storage = 'field_chado_storage';
-  
+
   /**
    * @see TripalField::formatterView()
    */
@@ -154,7 +154,7 @@ class chado_linker__expression extends TripalField {
 
         // Add the linker_expressionprop
         $linkerprop_table =  $linker_table . 'prop';
-        if (db_table_exists('chado.' . $linkerprop_table)) {
+        if (chado_table_exists($linkerprop_table)) {
           $exp_linker = chado_expand_var($exp_linker, 'table', $linkerprop_table, $options);
           $exp_linkerprops = $exp_linker->feature_expressionprop;
           if ($exp_linkerprops) {
@@ -174,12 +174,12 @@ class chado_linker__expression extends TripalField {
       }
     }
   }
-  
+
   /**
    * We don't want a widget so override this function.
    */
   public static function widgetInfo() {
     return array();
   }
-  
+
 }

+ 13 - 12
tripal_chado/includes/TripalFields/chado_linker__contact_widget.inc

@@ -13,9 +13,10 @@ class chado_linker__contact_widget extends TripalFieldWidget {
    */
   public function form(&$widget, &$form, &$form_state, $langcode, $items, $delta, $element) {
     parent::form($widget, $form, $form_state, $langcode, $items, $delta, $element);
+
     $entity = $form['#entity'];
     $field_name = $this->field['field_name'];
-    
+
     // Get the FK column that links to the base table.
     $table_name = $this->field['settings']['chado_table'];
     $base_table = $this->field['settings']['base_table'];
@@ -23,13 +24,13 @@ class chado_linker__contact_widget extends TripalFieldWidget {
     $pkey = $schema['primary key'][0];
     $fkeys = array_values($schema['foreign keys'][$base_table]['columns']);
     $fkey = $fkeys[0];
-    
+
     // Get the field defaults.
     $record_id = '';
     $fkey_value = $element['#entity']->chado_record_id;
     $contact_id = '';
     $name = '';
-    
+
     // If the field already has a value then it will come through the $items
     // array.  This happens when editing an existing record.
     if (count($items) > 0 and array_key_exists($delta, $items)) {
@@ -40,20 +41,20 @@ class chado_linker__contact_widget extends TripalFieldWidget {
         $name = $contact->name;
       }
     }
-    
+
     $schema = chado_get_schema('contact');
-    
+
     $widget['#table_name'] = $table_name;
     $widget['#fkey_field'] = $fkey;
     $widget['#theme'] = 'chado_linker__contact_widget';
     $widget['#prefix'] =  "<span id='$table_name-$delta'>";
     $widget['#suffix'] =  "</span>";
-    
+
     $widget['value'] = array(
       '#type' => 'value',
       '#value' => array_key_exists($delta, $items) ? $items[$delta]['value'] : '',
     );
-    
+
     $widget['chado-' . $table_name . '__' . $pkey] = array(
       '#type' => 'value',
       '#default_value' => $record_id,
@@ -66,7 +67,7 @@ class chado_linker__contact_widget extends TripalFieldWidget {
       '#type' => 'value',
       '#default_value' => $contact_id,
     );
-    
+
     $widget['name'] = array(
       '#type' => 'textfield',
       '#title' => t('Contact'),
@@ -110,19 +111,19 @@ class chado_linker__contact_widget extends TripalFieldWidget {
     $fkeys = array_values($schema['foreign keys'][$base_table]['columns']);
     $fkey = $fkeys[0];
     $field_name = $this->field['field_name'];
-    
+
     // Get the field values.
     $fkey_value = isset($form_state['values'][$field_name][$langcode][$delta]['value']) ? $form_state['values'][$field_name][$langcode][$delta]['value'] : '';
     $contact_id = isset($form_state['values'][$field_name][$langcode][$delta]['chado-' . $table_name . '__contact_id']) ? $form_state['values'][$field_name][$langcode][$delta]['chado-' . $table_name . '__contact_id'] : '';
     $name = isset($form_state['values'][$field_name][$langcode][$delta]['name']) ? $form_state['values'][$field_name][$langcode][$delta]['name'] : '';
-    
+
     // If the user provided a name then we want to set the foreign key
     // value to be the chado_record_id
     if ($name and !$contact_id) {
       $contact = chado_generate_var('contact', array('name' => $name));
       $form_state['values'][$field_name][$langcode][$delta]['chado-' . $table_name . '__contact_id'] = $contact->contact_id;
     }
-    
+
     // In the widgetForm function we automatically add the foreign key
     // record.  But if the user did not provide a contact we want to take
     // it out so that the Chado field_storage infrastructure won't try to
@@ -130,7 +131,7 @@ class chado_linker__contact_widget extends TripalFieldWidget {
     if (!$name and !$contact_id) {
       $form_state['values'][$field_name][$langcode][$delta]['chado-' . $table_name . '__' . $fkey] = '';
     }
-    
+
     // If the user removed the contact from the contact_name field
     // then we want to clear out the rest of the hidden values.
     // Leave the primary key so the record can be deleted.

+ 81 - 0
tripal_chado/includes/TripalFields/data__protein_sequence.inc

@@ -0,0 +1,81 @@
+<?php
+
+class data__protein_sequence extends TripalField {
+
+
+  // --------------------------------------------------------------------------
+  //                     EDITABLE STATIC CONSTANTS
+  //
+  // The following constants SHOULD be set for each descendent class.  They are
+  // used by the static functions to provide information to Drupal about
+  // the field and it's default widget and formatter.
+  // --------------------------------------------------------------------------
+
+  // The term that this field maps to.  The format for the term should be:
+  // [vocab]:[accession] where [vocab] is the short name of the vocabulary
+  // and [acession] is the unique accession number for the term.  This term
+  // must already exist in the vocabulary storage backend. This
+  // value should never be changed once fields exist for this type.
+  public static $term = 'data:2976';
+
+  // The default lable for this field.
+  public static $label = 'Protein Sequence';
+
+  // The default description for this field.
+  public static $description = 'polypeptide sequences.';
+
+  // Provide a list of global settings. These can be accessed witihn the
+  // globalSettingsForm.  When the globalSettingsForm is submitted then
+  // Drupal will automatically change these settings for all fields.
+  public static $settings = array(
+    'chado_table' => '',
+    'chado_column' => '',
+    'base_table' => '',
+  );
+
+  // Provide a list of instance specific settings. These can be access within
+  // the instanceSettingsForm.  When the instanceSettingsForm is submitted
+  // then Drupal with automatically change these settings for the instnace.
+  // It is recommended to put settings at the instance level whenever possible.
+  public static $instance_settings  = array();
+
+  // Set this to the name of the storage backend that by default will support
+  // this field.
+  public static $storage = 'tripal_no_storage';
+
+  // The default widget for this field.
+  public static $default_widget = 'data__protein_sequence_widget';
+
+  // The default formatter for this field.
+  public static $default_formatter = 'data__protein_sequence_formatter';
+
+
+  /**
+   * @see TripalField::load()
+   */
+  public function load($entity, $details = array()) {
+    $field_name = $this->field['field_name'];
+    $feature = $details['record'];
+    $num_seqs = 0;
+
+    // Look for Protein sequences
+    $sql = "
+      SELECT F.*
+      FROM {feature_relationship} FR
+        INNER JOIN {feature} F on FR.subject_id = F.feature_id
+        INNER JOIN {cvterm} CVT on CVT.cvterm_id = F.type_id
+        INNER JOIN {cvterm} RCVT on RCVT.cvterm_id = FR.type_id
+      WHERE
+        FR.object_id = :feature_id and
+        CVT.name = 'polypeptide' and
+        RCVT.name = 'derives_from'
+      ORDER BY FR.rank ASC
+    ";
+    $results = chado_query($sql, array(':feature_id' => $feature->feature_id));
+    while ($protein = $results->fetchObject()) {
+      if ($protein->residues) {
+        $entity->{$field_name}['und'][$num_seqs++]['value'] = $protein->residues;
+      }
+    }
+  }
+}

+ 50 - 0
tripal_chado/includes/TripalFields/data__protein_sequence_formatter.inc

@@ -0,0 +1,50 @@
+<?php
+
+class data__protein_sequence_formatter extends TripalFieldFormatter {
+  // The default lable for this field.
+  public static $label = 'Protein Sequence';
+
+  // The list of field types for which this formatter is appropriate.
+  public static $field_types = array('data__protein_sequence');
+
+  // The list of default settings for this formatter.
+  public static $settings = array();
+
+  /**
+   *
+   * @param unknown $element
+   * @param unknown $entity_type
+   * @param unknown $entity
+   * @param unknown $langcode
+   * @param unknown $items
+   * @param unknown $display
+   */
+  public function view(&$element, $entity_type, $entity, $langcode, $items, $display) {
+    $element[0] = array(
+      // We create a render array to produce the desired markup,
+      '#type' => 'markup',
+      '#markup' => '',
+    );
+
+    $num_bases = 50;
+    foreach ($items as $delta => $item) {
+      // If there are no residues then skip this one.
+      if (!is_array($item['value']) or !array_key_exists('residues', $item['value'])) {
+        continue;
+      }
+
+      $residues = $item['value']['residues'];
+
+      $content .= '<pre class="residues-formatter">';
+      $content .= '>' . $defline . "<br>";
+      $content .= wordwrap($residues, $num_bases, "<br>", TRUE);
+      $content .= '</pre>';
+
+      $element[$delta] = array(
+        // We create a render array to produce the desired markup,
+        '#type' => 'markup',
+        '#markup' => $content,
+      );
+    }
+  }
+}

+ 43 - 0
tripal_chado/includes/TripalFields/data__protein_sequence_widget.inc

@@ -0,0 +1,43 @@
+<?php
+
+class data__protein_sequence_widget extends TripalFieldWidget {
+  // The default lable for this field.
+  public static $label = 'Protein Sequence';
+
+  // The list of field types for which this formatter is appropriate.
+  public static $field_types = array('data__protein_sequence');
+
+  /**
+   *
+   * @see TripalFieldWidget::form()
+   */
+  public function form(&$widget, &$form, &$form_state, $langcode, $items, $delta, $element) {
+    parent::form($widget, $form, $form_state, $langcode, $items, $delta, $element);
+
+    // TODO: add the form for setting a protein sequence.
+  }
+
+  /**
+   * Performs validation of the widgetForm.
+   *
+   * Use this validate to ensure that form values are entered correctly.  Note
+   * this is different from the validate() function which ensures that the
+   * field data meets expectations.
+   *
+   * @param $form
+   * @param $form_state
+   */
+  public function validate($form, &$form_state, $entity_type, $entity, $langcode, $delta) {
+
+  }
+
+
+  /**
+   *
+   * @see TripalFieldWidget::submit()
+   */
+  public function submit($form, &$form_state, $entity_type, $entity, $langcode, $delta) {
+    $field_name = $this->field['field_name'];
+
+  }
+}

+ 90 - 477
tripal_chado/includes/TripalFields/data__sequence.inc

@@ -49,103 +49,42 @@ class data__sequence extends TripalField {
   // The default formatter for this field.
   public static $default_formatter = 'data__sequence_formatter';
 
-  // --------------------------------------------------------------------------
-  //              PROTECTED CLASS MEMBERS -- DO NOT OVERRIDE
-  // --------------------------------------------------------------------------
-  // An array containing details about the field. The format of this array
-  // is the same as that returned by field_info_fields()
-  protected $field;
-  // An array containing details about an instance of the field. A field does
-  // not have to have an instance.  But if dealing with an instance (such as
-  // when using the widgetForm, formatterSettingsForm, etc.) it should be set.
-  protected $instance;
-
+  /**
+   * @see TripalField::load()
+   */
   public function load($entity, $details = array()) {
     $field_name = $this->field['field_name'];
     $feature = $details['record'];
-    $num_seqs = 0;
-    
+
     // We don't want to get the sequence for traditionally large types. They are
     // too big,  bog down the web browser, take longer to load and it's not
     // reasonable to print them on a page.
-    if(strcmp($feature->type_id->name,'scaffold') == 0 or
-        strcmp($feature->type_id->name,'chromosome') == 0 or
-        strcmp($feature->type_id->name,'supercontig') == 0 or
-        strcmp($feature->type_id->name,'pseudomolecule') == 0) {
-          $entity->{$field_name}['und'][$num_seqs]['value'] = array(
-            '@type' => 'SO:0000110',
-            'type' => 'sequence_feature',
-            'label' => 'Residues',
-            'defline' => ">This sequence is too large for this display.",
-            'residues' => '',
-          );
-          $entity->{$field_name}['und'][$num_seqs]['chado-feature__residues'] = '';
-        }
-        else {
-          $feature = chado_expand_var($feature,'field','feature.residues');
-          if ($feature->residues) {
-            $entity->{$field_name}['und'][$num_seqs]['value'] = array(
-              '@type' => 'SO:0000110',
-              'type' => 'sequence_feature',
-              'label' => 'Raw Sequence',
-              'defline' => tripal_get_fasta_defline($feature, '', NULL, '', strlen($feature->residues)),
-              'residues' => $feature->residues,
-            );
-            $entity->{$field_name}['und'][$num_seqs]['chado-feature__residues'] = $feature->residues;
-          }
-          else {
-            $entity->{$field_name}['und'][$num_seqs]['value'] = array();
-            $entity->{$field_name}['und'][$num_seqs]['chado-feature__residues'] = '';
-          }
-        }
-        $num_seqs++;
-    
-        // Add in the protein sequences. It's faster to provide the SQL rather than
-        // to use chado_generate_var based on the type.
-        $sql = "
-      SELECT F.*
-      FROM {feature_relationship} FR
-        INNER JOIN {feature} F on FR.subject_id = F.feature_id
-        INNER JOIN {cvterm} CVT on CVT.cvterm_id = F.type_id
-        INNER JOIN {cvterm} RCVT on RCVT.cvterm_id = FR.type_id
-      WHERE
-        FR.object_id = :feature_id and
-        CVT.name = 'polypeptide' and
-        RCVT.name = 'derives_from'
-      ORDER BY FR.rank ASC
-    ";
-        $results = chado_query($sql, array(':feature_id' => $feature->feature_id));
-        while ($protein = $results->fetchObject()) {
-          if ($protein->residues) {
-            $entity->{$field_name}['und'][$num_seqs++]['value'] = array(
-              '@type' => 'SO:0000104',
-              'type' => 'polypeptide',
-              'label' => 'Protein Sequence',
-              'defline' => tripal_get_fasta_defline($protein, '', NULL, '', strlen($protein->residues)),
-              'residues' => $protein->residues,
-            );
-          }
-        }
-    
-    
-        // Add in sequences from alignments.
-        $options = array(
-          'return_array' => 1,
-          'include_fk' => array(
-            'srcfeature_id' => array(
-              'type_id' => 1
-            ),
-            'feature_id' => array(
-              'type_id' => 1
-            ),
-          ),
-        );
-        $feature = chado_expand_var($feature, 'table', 'featureloc', $options);
-        $featureloc_sequences = $this->get_featureloc_sequences($feature->feature_id, $feature->featureloc->feature_id);
-    
-        // Add in the coding sequences. It's faster to provide the SQL rather than
-        // to use chado_generate_var based on the type.
-        $sql = "
+    if(strcmp($feature->type_id->name,'scaffold') != 0 and
+       strcmp($feature->type_id->name,'chromosome') != 0 and
+       strcmp($feature->type_id->name,'supercontig') != 0 and
+       strcmp($feature->type_id->name,'pseudomolecule') != 0) {
+      $feature = chado_expand_var($feature,'field','feature.residues');
+      $entity->{$field_name}['und'][0]['value'] = $feature->residues;
+    }
+
+ /*    // Add in sequences from alignments.
+    $options = array(
+      'return_array' => 1,
+      'include_fk' => array(
+        'srcfeature_id' => array(
+          'type_id' => 1
+        ),
+        'feature_id' => array(
+          'type_id' => 1
+        ),
+      ),
+    );
+    $feature = chado_expand_var($feature, 'table', 'featureloc', $options);
+    $featureloc_sequences = $this->get_featureloc_sequences($feature->feature_id, $feature->featureloc->feature_id);
+
+    // Add in the coding sequences. It's faster to provide the SQL rather than
+    // to use chado_generate_var based on the type.
+    $sql = "
       SELECT F.*
       FROM {feature_relationship} FR
         INNER JOIN {feature} F on FR.subject_id = F.feature_id
@@ -158,398 +97,72 @@ class data__sequence extends TripalField {
         RCVT.name = 'part_of'
       ORDER BY FR.rank ASC
     ";
-        $results = chado_query($sql, array(':feature_id' => $feature->feature_id));
-        $coding_seq = '';
-        while ($CDS = $results->fetchObject()) {
-          if ($CDS->residues) {
-            $coding_seq .= $CDS->residues;
-          }
-        }
-        if ($coding_seq) {
+    $results = chado_query($sql, array(':feature_id' => $feature->feature_id));
+    $coding_seq = '';
+    while ($CDS = $results->fetchObject()) {
+      if ($CDS->residues) {
+        $coding_seq .= $CDS->residues;
+      }
+    }
+    if ($coding_seq) {
+      $entity->{$field_name}['und'][$num_seqs++]['value'] = array(
+        '@type' => 'SO:0000316',
+        'type' => 'coding_sequence',
+        'label' => 'Coding sequence (CDS)',
+        'defline' => tripal_get_fasta_defline($feature, 'CDS', NULL, '', strlen($coding_seq)),
+        'residues' => $coding_seq,
+      );
+    }
+
+    foreach($featureloc_sequences as $src => $attrs){
+      // the $attrs array has the following keys
+      //   * id:  a unique identifier combining the feature id with the cvterm id
+      //   * type: the type of sequence (e.g. mRNA, etc)
+      //   * location:  the alignment location
+      //   * defline: the definition line
+      //   * formatted_seq: the formatted sequences
+      //   * featureloc:  the feature object aligned to
+      $entity->{$field_name}['und'][$num_seqs++]['value'] = array(
+        'residues' => $attrs['residues'],
+        '@type' => 'SO:0000110',
+        'type' => 'sequence_feature',
+        'defline' => tripal_get_fasta_defline($feature, '', $attrs['featureloc'], 'CDS', strlen($attrs['residues'])),
+        'label' => 'Sequence from alignment at ' . $attrs['location'],
+      );
+
+
+      // check to see if this alignment has any CDS. If so, generate a CDS sequence
+      $cds_sequence = tripal_get_feature_sequences(
+          array(
+            'feature_id' => $feature->feature_id,
+            'parent_id' => $attrs['featureloc']->srcfeature_id->feature_id,
+            'name' => $feature->name,
+            'featureloc_id' => $attrs['featureloc']->featureloc_id,
+          ),
+          array(
+            'derive_from_parent' => 1, // CDS are in parent-child relationships so we want to use the sequence from the parent
+            'aggregate' => 1, // we want to combine all CDS for this feature into a single sequence
+            'sub_feature_types' => array('CDS'), // we're looking for CDS features
+            'is_html' => 0
+          )
+          );
+
+      if (count($cds_sequence) > 0) {
+        // the tripal_get_feature_sequences() function can return multiple sequences
+        // if a feature is aligned to multiple places. In the case of CDSs we expect
+        // that one mRNA is only aligned to a single location on the assembly so we
+        // can access the CDS sequence with index 0.
+        if ($cds_sequence[0]['residues']) {
           $entity->{$field_name}['und'][$num_seqs++]['value'] = array(
+            'residues' => $cds_sequence[0]['residues'],
             '@type' => 'SO:0000316',
             'type' => 'coding_sequence',
-            'label' => 'Coding sequence (CDS)',
-            'defline' => tripal_get_fasta_defline($feature, 'CDS', NULL, '', strlen($coding_seq)),
-            'residues' => $coding_seq,
+            'defline' => tripal_get_fasta_defline($feature, '', $attrs['featureloc'], 'CDS', $cds_sequence[0]['length']),
+            'label' => 'Coding sequence (CDS) from alignment at  ' . $attrs['location'],
           );
         }
-    
-        foreach($featureloc_sequences as $src => $attrs){
-          // the $attrs array has the following keys
-          //   * id:  a unique identifier combining the feature id with the cvterm id
-          //   * type: the type of sequence (e.g. mRNA, etc)
-          //   * location:  the alignment location
-          //   * defline: the definition line
-          //   * formatted_seq: the formatted sequences
-          //   * featureloc:  the feature object aligned to
-          $entity->{$field_name}['und'][$num_seqs++]['value'] = array(
-            'residues' => $attrs['residues'],
-            '@type' => 'SO:0000110',
-            'type' => 'sequence_feature',
-            'defline' => tripal_get_fasta_defline($feature, '', $attrs['featureloc'], 'CDS', strlen($attrs['residues'])),
-            'label' => 'Sequence from alignment at ' . $attrs['location'],
-          );
-    
-    
-          // check to see if this alignment has any CDS. If so, generate a CDS sequence
-          $cds_sequence = tripal_get_feature_sequences(
-              array(
-                'feature_id' => $feature->feature_id,
-                'parent_id' => $attrs['featureloc']->srcfeature_id->feature_id,
-                'name' => $feature->name,
-                'featureloc_id' => $attrs['featureloc']->featureloc_id,
-              ),
-              array(
-                'derive_from_parent' => 1, // CDS are in parent-child relationships so we want to use the sequence from the parent
-                'aggregate' => 1, // we want to combine all CDS for this feature into a single sequence
-                'sub_feature_types' => array('CDS'), // we're looking for CDS features
-                'is_html' => 0
-              )
-              );
-    
-          if (count($cds_sequence) > 0) {
-            // the tripal_get_feature_sequences() function can return multiple sequences
-            // if a feature is aligned to multiple places. In the case of CDSs we expect
-            // that one mRNA is only aligned to a single location on the assembly so we
-            // can access the CDS sequence with index 0.
-            if ($cds_sequence[0]['residues']) {
-              $entity->{$field_name}['und'][$num_seqs++]['value'] = array(
-                'residues' => $cds_sequence[0]['residues'],
-                '@type' => 'SO:0000316',
-                'type' => 'coding_sequence',
-                'defline' => tripal_get_fasta_defline($feature, '', $attrs['featureloc'], 'CDS', $cds_sequence[0]['length']),
-                'label' => 'Coding sequence (CDS) from alignment at  ' . $attrs['location'],
-              );
-            }
-          }
-        }
-  }
-  
-  /**
-   *
-   * @param unknown $feature_id
-   * @param unknown $featurelocs
-   * @return multitype:|Ambigous <multitype:, an>
-   */
-  private function get_featureloc_sequences($feature_id, $featurelocs) {
-  
-    // if we don't have any featurelocs then no point in continuing
-    if (!$featurelocs) {
-      return array();
-    }
-  
-    // get the list of relationships (including any aggregators) and iterate
-    // through each one to find information needed to color-code the reference sequence
-    $relationships = $this->get_aggregate_relationships($feature_id);
-    if (!$relationships) {
-      return array();
-    }
-  
-  
-    // iterate through each of the realtionships features and get their
-    // locations
-    foreach ($relationships as $rindex => $rel) {
-      // get the featurelocs for each of the relationship features
-      $rel_featurelocs = $this->get_featurelocs($rel->subject_id, 'as_child', 0);
-      foreach ($rel_featurelocs as $rfindex => $rel_featureloc) {
-        // keep track of this unique source feature
-        $src = $rel_featureloc->src_feature_id . "-" . $rel_featureloc->src_cvterm_id;
-  
-        // copy over the results to the relationship object.  Since there can
-        // be more than one feature location for each relationship feature we
-        // use the '$src' variable to keep track of these.
-        $rel->featurelocs = new stdClass();
-        $rel->featurelocs->$src = new stdClass();
-        $rel->featurelocs->$src->src_uniquename = $rel_featureloc->src_uniquename;
-        $rel->featurelocs->$src->src_cvterm_id  = $rel_featureloc->src_cvterm_id;
-        $rel->featurelocs->$src->src_cvname     = $rel_featureloc->src_cvname;
-        $rel->featurelocs->$src->fmin           = $rel_featureloc->fmin;
-        $rel->featurelocs->$src->fmax           = $rel_featureloc->fmax;
-        $rel->featurelocs->$src->src_name       = $rel_featureloc->src_name;
-  
-        // keep track of the individual parts for each relationship
-        $start = $rel->featurelocs->$src->fmin;
-        $end   = $rel->featurelocs->$src->fmax;
-        $type  = $rel->subject_type;
-        $rel_locs[$src]['parts'][$start][$type]['start'] = $start;
-        $rel_locs[$src]['parts'][$start][$type]['end']   = $end;
-        $rel_locs[$src]['parts'][$start][$type]['type']  = $type;
-      }
-    }
-  
-    // the featurelocs array provided to the function contains the locations
-    // 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.
-    $floc_sequences = array();
-    foreach ($featurelocs as $featureloc) {
-  
-      // build the src name so we can keep track of the different parts for each feature
-      $src = $featureloc->srcfeature_id->feature_id . "-" . $featureloc->srcfeature_id->type_id->cvterm_id;
-  
-      // orient the parts to the beginning of the feature sequence
-      if (!empty($rel_locs[$src]['parts'])) {
-        $parts = $rel_locs[$src]['parts'];
-        $rparts = array();  // we will fill this up if we're on the reverse strand
-  
-        foreach ($parts as $start => $types) {
-          foreach ($types as $type_name => $type) {
-            if ($featureloc->strand >= 0) {
-              // this is on the forward strand.  We need to convert the start on the src feature to the
-              // start on this feature's sequence
-              $parts[$start][$type_name]['start'] = $parts[$start][$type_name]['start'] - $featureloc->fmin;
-              $parts[$start][$type_name]['end']   = $parts[$start][$type_name]['end'] - $featureloc->fmin;
-              $parts[$start][$type_name]['type']  = $type_name;
-            }
-            else {
-              // this is on the reverse strand.  We need to swap the start and stop and calculate from the
-              // begining of the reverse sequence
-              $size = ($featureloc->fmax - $featureloc->fmin);
-              $start_orig = $parts[$start][$type_name]['start'];
-              $end_orig = $parts[$start][$type_name]['end'];
-              $new_start = $size - ($end_orig - $featureloc->fmin);
-              $new_end = $size - ($start_orig - $featureloc->fmin);
-  
-              $rparts[$new_start][$type_name]['start'] = $new_start;
-              $rparts[$new_start][$type_name]['end']   = $new_end;
-              $rparts[$new_start][$type_name]['type']  = $type_name;
-            }
-          }
-        }
-  
-        // now sort the parts
-        // if we're on the reverse strand we need to resort
-        if ($featureloc->strand >= 0) {
-          usort($parts, 'chado_feature__residues_sort_rel_parts_by_start');
-        }
-        else {
-          usort($rparts, 'chado_feature__residues_sort_rel_parts_by_start');
-          $parts = $rparts;
-        }
-  
-        $floc_sequences[$src]['id'] = $src;
-        $floc_sequences[$src]['type'] = $featureloc->feature_id->type_id->name;
-        $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) {
-          $residues = tripal_reverse_compliment_sequence($residues);
-        }
-        $strand = '.';
-        if ($featureloc->strand == 1) {
-          $strand = '+';
-        }
-        elseif ($featureloc->strand == -1) {
-          $strand = '-';
-        }
-        $floc_sequences[$src]['location'] = tripal_get_location_string($featureloc);
-        $floc_sequences[$src]['defline'] = tripal_get_fasta_defline($featureloc->feature_id, '', $featureloc, '', strlen($residues));
-        $floc_sequences[$src]['featureloc'] = $featureloc;
-        $floc_sequences[$src]['residues'] = $residues;
-        //$floc_sequences[$src]['formatted_seq'] =  tripal_feature_color_sequence($residues, $parts, $floc_sequences[$src]['defline']);
-      }
-    }
-    return $floc_sequences;
-  }
-  
-  /**
-   * Get features related to the current feature to a given depth. Recursive function.
-   *
-   * @param $feature_id
-   * @param $substitute
-   * @param $levels
-   * @param $base_type_id
-   * @param $depth
-   *
-   * @ingroup tripal_feature
-   */
-  private function get_aggregate_relationships($feature_id, $substitute=1,
-      $levels=0, $base_type_id=NULL, $depth=0) {
-  
-        // we only want to recurse to as many levels deep as indicated by the
-        // $levels variable, but only if this variable is > 0. If 0 then we
-        // recurse until we reach the end of the relationships tree.
-        if ($levels > 0 and $levels == $depth) {
-          return NULL;
-        }
-  
-        // first get the relationships for this feature
-        return $this->get_relationships($feature_id, 'as_object');
-  
-  }
-  
-  /**
-   * Get the relationships for a feature.
-   *
-   * @param $feature_id
-   *   The feature to get relationships for
-   * @param $side
-   *   The side of the relationship this feature is (ie: 'as_subject' or 'as_object')
-   *
-   * @ingroup tripal_feature
-   */
-  private function get_relationships($feature_id, $side = 'as_subject') {
-    // get the relationships for this feature.  The query below is used for both
-    // querying the object and subject relationships
-    $sql = "
-    SELECT
-      FS.name as subject_name, FS.uniquename as subject_uniquename,
-      CVTS.name as subject_type, CVTS.cvterm_id as subject_type_id,
-      FR.subject_id, FR.type_id as relationship_type_id, FR.object_id, FR.rank,
-      CVT.name as rel_type,
-      FO.name as object_name, FO.uniquename as object_uniquename,
-      CVTO.name as object_type, CVTO.cvterm_id as object_type_id
-    FROM {feature_relationship} FR
-     INNER JOIN {cvterm} CVT  ON FR.type_id    = CVT.cvterm_id
-     INNER JOIN {feature} FS  ON FS.feature_id = FR.subject_id
-     INNER JOIN {feature} FO  ON FO.feature_id = FR.object_id
-     INNER JOIN {cvterm} CVTO ON FO.type_id    = CVTO.cvterm_id
-     INNER JOIN {cvterm} CVTS ON FS.type_id    = CVTS.cvterm_id
-  ";
-    if (strcmp($side, 'as_object')==0) {
-      $sql .= " WHERE FR.object_id = :feature_id";
-    }
-    if (strcmp($side, 'as_subject')==0) {
-      $sql .= " WHERE FR.subject_id = :feature_id";
-    }
-    $sql .= " ORDER BY FR.rank";
-  
-    // get the relationships
-    $results = chado_query($sql, array(':feature_id' => $feature_id));
-  
-  
-    // iterate through the relationships, put these in an array and add
-    // in the Drupal node id if one exists
-    $i=0;
-    $esql = "
-        SELECT entity_id
-        FROM {chado_entity}
-        WHERE data_table = 'feature' AND record_id = :feature_id";
-    $relationships = array();
-    while ($rel = $results->fetchObject()) {
-      $entity = db_query($esql, array(':feature_id' => $rel->subject_id))->fetchObject();
-      if ($entity) {
-        $rel->subject_entity_id = $entity->entity_id;
-      }
-      $entity = db_query($esql, array(':feature_id' => $rel->object_id))->fetchObject();
-      if ($entity) {
-        $rel->object_entity_id = $entity->entity_id;
       }
-      $relationships[$i++] = $rel;
-    }
-    return $relationships;
-  }
-  
-  /**
-   * Load the locations for a given feature
-   *
-   * @param $feature_id
-   *   The feature to look up locations for
-   * @param $side
-   *   Whether the feature is the scrfeature, 'as_parent', or feature, 'as_child'
-   * @param $aggregate
-   *   Whether or not to get the locations for related features
-   *
-   * @ingroup tripal_feature
-   */
-  private function get_featurelocs($feature_id, $side = 'as_parent', $aggregate = 1) {
-  
-    $sql = "
-    SELECT
-       F.name, F.feature_id, F.uniquename,
-       FS.name as src_name, FS.feature_id as src_feature_id, FS.uniquename as src_uniquename,
-       CVT.name as cvname, CVT.cvterm_id,
-       CVTS.name as src_cvname, CVTS.cvterm_id as src_cvterm_id,
-       FL.fmin, FL.fmax, FL.is_fmin_partial, FL.is_fmax_partial,FL.strand, FL.phase
-     FROM {featureloc} FL
-       INNER JOIN {feature} F   ON FL.feature_id = F.feature_id
-       INNER JOIN {feature} FS  ON FS.feature_id = FL.srcfeature_id
-       INNER JOIN {cvterm} CVT  ON F.type_id     = CVT.cvterm_id
-       INNER JOIN {cvterm} CVTS ON FS.type_id    = CVTS.cvterm_id
-   ";
-    if (strcmp($side, 'as_parent')==0) {
-      $sql .= "WHERE FL.srcfeature_id = :feature_id ";
-    }
-    if (strcmp($side, 'as_child')==0) {
-      $sql .= "WHERE FL.feature_id = :feature_id ";
-    }
-  
-    $flresults = chado_query($sql, array(':feature_id' => $feature_id));
-  
-    // copy the results into an array
-    $i=0;
-    $featurelocs = array();
-    while ($loc = $flresults->fetchObject()) {
-      // if a drupal node exists for this feature then add the nid to the
-      // results object
-  
-      $loc->feid = tripal_get_chado_entity_id('feature', $loc->feature_id);
-      $loc->seid = tripal_get_chado_entity_id('feature', $loc->src_feature_id);
-      // add the result to the array
-      $featurelocs[$i++] = $loc;
-    }
-  
-    // Add the relationship feature locs if aggregate is turned on
-    if ($aggregate and strcmp($side, 'as_parent')==0) {
-      // get the relationships for this feature without substituting any children
-      // for the parent. We want all relationships
-      $relationships = tripal_feature_get_aggregate_relationships($feature_id, 0);
-      foreach ($relationships as $rindex => $rel) {
-        // get the featurelocs for each of the relationship features
-        $rel_featurelocs = tripal_feature_load_featurelocs($rel->subject_id, 'as_child', 0);
-        foreach ($rel_featurelocs as $findex => $rfloc) {
-          $featurelocs[$i++] = $rfloc;
-        }
-      }
-    }
-  
-    usort($featurelocs, 'chado_feature__residues_sort_locations');
-    return $featurelocs;
+    } */
   }
 }
 
-/**
- * Used to sort the list of relationship parts by start position
- *
- * @ingroup tripal_feature
- */
-function chado_feature__residues_sort_rel_parts_by_start($a, $b) {
-  foreach ($a as $type_name => $details) {
-    $astart = $a[$type_name]['start'];
-    break;
-  }
-  foreach ($b as $type_name => $details) {
-    $bstart = $b[$type_name]['start'];
-    break;
-  }
-  return strnatcmp($astart, $bstart);
-}
-/**
- * Used to sort the feature locs by start position
- *
- * @param $a
- *   One featureloc record (as an object)
- * @param $b
- *   The other featureloc record (as an object)
- *
- * @return
- *   Which feature location comes first
- *
- * @ingroup tripal_feature
- */
-function chado_feature__residues_sort_locations($a, $b) {
-  return strnatcmp($a->fmin, $b->fmin);
-}

+ 0 - 7
tripal_chado/includes/TripalFields/data__sequence_checksum.inc

@@ -61,11 +61,4 @@ class data__sequence_checksum extends TripalField {
   protected $instance;
 
 
-
-  /**
-   * @see TripalField::load()
-   */
-  public function load($entity, $details = array()) {
-
-  }
 }

+ 5 - 16
tripal_chado/includes/TripalFields/data__sequence_formatter.inc

@@ -11,7 +11,7 @@ class data__sequence_formatter extends TripalFieldFormatter {
   public static $settings = array();
 
   /**
-   * 
+   *
    * @param unknown $element
    * @param unknown $entity_type
    * @param unknown $entity
@@ -25,24 +25,13 @@ class data__sequence_formatter extends TripalFieldFormatter {
       '#type' => 'markup',
       '#markup' => '',
     );
-    
+
     $num_bases = 50;
     foreach ($items as $delta => $item) {
-      // If there are no residues then skip this one.
-      if (!is_array($item['value']) or !array_key_exists('residues', $item['value'])) {
-        continue;
-      }
-    
-      $residues = $item['value']['residues'];
-      $label = $item['value']['label'];
-      $defline = $item['value']['defline'];
-    
-      $content = '<p>' . $label . '<p>';
-      $content .= '<pre class="residues-formatter">';
-      $content .= '>' . $defline . "<br>";
-      $content .= wordwrap($residues, $num_bases, "<br>", TRUE);
+      $content = '<pre class="residues-formatter">';
+      $content .= wordwrap($item['value'], $num_bases, "<br>", TRUE);
       $content .= '</pre>';
-    
+
       $element[$delta] = array(
         // We create a render array to produce the desired markup,
         '#type' => 'markup',

+ 0 - 7
tripal_chado/includes/TripalFields/data__sequence_length.inc

@@ -60,11 +60,4 @@ class data__sequence_length extends TripalField {
   // when using the widgetForm, formatterSettingsForm, etc.) it should be set.
   protected $instance;
 
-  /**
-   * 
-   * @see TripalField::load()
-   */
-  public function load($entity, $details = array()) {
-
-  }
 }

+ 10 - 11
tripal_chado/includes/TripalFields/go__gene_expression.inc

@@ -81,24 +81,23 @@ class go__gene_expression extends TripalField {
    */
   public function load($entity, $details = array()) {
     $record = $details['record'];
-    
     $field_name = $this->field['field_name'];
     $field_type = $this->field['type'];
     $field_table = $this->field['settings']['chado_table'];
     $field_column = $this->field['settings']['chado_column'];
-    
+
     // Get the FK that links to the base record.
     $schema = chado_get_schema($field_table);
     $base_table = $details['record']->tablename;
     $pkey = $schema['primary key'][0];
     $fkey_lcolumn = key($schema['foreign keys'][$base_table]['columns']);
     $fkey_rcolumn = $schema['foreign keys'][$base_table]['columns'][$fkey_lcolumn];
-    
+
     // Set some defaults for the empty record.
     $entity->{$field_name}['und'][0] = array(
       'value' => array(),
     );
-    
+
     $linker_table = $base_table . '_expression';
     $options = array(
       'return_array' => 1,
@@ -107,11 +106,11 @@ class go__gene_expression extends TripalField {
     $exp_linkers = $record->$linker_table;
     if ($exp_linkers) {
       foreach ($exp_linkers as $i => $exp_linker) {
-    
+
         // Because the unqiuename is a text field we must expand it.
         $expression = $exp_linker->expression_id;
         $expression = chado_expand_var($expression, 'field', 'expression.uniquename', $options);
-    
+
         // Set the values that will be seen by the user on the page and in
         // web services, or anwhere this field is viewed.
         $entity->{$field_name}['und'][$i]['value'] = array(
@@ -119,22 +118,22 @@ class go__gene_expression extends TripalField {
           'description' => $expression->description,
           //'md5checksum' => $expression->md5checksum,
         );
-    
+
         // Add the pub information if a real pub is associated with the record.
         $pub = $exp_linker->pub_id;
         if ($pub->uniquename != 'null') {
           $pub_details = tripal_get_minimal_pub_info($pub);
-    
+
           $entity->{$field_name}['und'][$i]['value']['publication'] = $pub_details;
           $entity->{$field_name}['und'][$i]['value']['publication']['type'] = $pub->type_id->name;
           if (property_exists($pub, 'entity_id')) {
             $entity->{$field_name}['und'][$i]['publication'][0]['value']['entity'] = 'TripalEntity:' . $pub->entity_id;
           }
         }
-    
+
         // Add the linker_expressionprop
         $linkerprop_table =  $linker_table . 'prop';
-        if (db_table_exists('chado.' . $linkerprop_table)) {
+        if (chado_table_exists($linkerprop_table)) {
           $exp_linker = chado_expand_var($exp_linker, 'table', $linkerprop_table, $options);
           $exp_linkerprops = $exp_linker->feature_expressionprop;
           if ($exp_linkerprops) {
@@ -150,7 +149,7 @@ class go__gene_expression extends TripalField {
         $entity->{$field_name}['und'][$i][$linker_table . '__uniquename'] = $expression->uniquename;
         //$entity->{$field_name}['und'][$i][$linker_table . '__md5checksum'] = $expression->md5checksum;
         $entity->{$field_name}['und'][$i][$linker_table . '__description'] = $expression->description;
-    
+
       }
     }
   }

+ 16 - 16
tripal_chado/includes/TripalFields/sbo__database_cross_reference_widget.inc

@@ -17,7 +17,7 @@ class sbo__database_cross_reference_widget extends TripalFieldWidget {
     $field_type = $this->field['type'];
     $field_table = $this->field['settings']['chado_table'];
     $field_column = $this->field['settings']['chado_column'];
-    
+
     // Get the FK column that links to the base table.
     $chado_table = $this->field['settings']['chado_table'];
     $base_table = $this->field['settings']['base_table'];
@@ -25,16 +25,16 @@ class sbo__database_cross_reference_widget extends TripalFieldWidget {
     $pkey = $schema['primary key'][0];
     $fkeys = array_values($schema['foreign keys'][$base_table]['columns']);
     $fkey = $fkeys[0];
-    
+
     // Get the field defaults.
     $record_id = '';
-    $fkey_value = $element['#entity']->chado_record_id;
+    $fkey_value = $element['#entity'] ? $element['#entity']->chado_record_id : '';
     $dbxref_id = '';
     $db_id = '';
     $accession = '';
     $version = '';
     $description = '';
-    
+
     // If the field already has a value then it will come through the $items
     // array.  This happens when editing an existing record.
     if (count($items) > 0 and array_key_exists($delta, $items)) {
@@ -46,7 +46,7 @@ class sbo__database_cross_reference_widget extends TripalFieldWidget {
       $version = tripal_get_field_item_keyval($items, $delta, 'version', $version);
       $description = tripal_get_field_item_keyval($items, $delta, 'description', $description);
     }
-    
+
     // Check $form_state['values'] to see if an AJAX call set the values.
     if (array_key_exists('values', $form_state) and array_key_exists($delta, $form_state['values'])) {
       $record_id = $form_state['values'][$field_name]['und'][$delta][$field_table . '__' . $pkey];
@@ -57,23 +57,23 @@ class sbo__database_cross_reference_widget extends TripalFieldWidget {
       $version = $form_state['values'][$field_name]['und'][$delta]['version'];
       $description = $form_state['values'][$field_name]['und'][$delta]['description'];
     }
-    
+
     $schema = chado_get_schema('dbxref');
     $options = tripal_get_db_select_options();
-    
+
     $widget['#table_name'] = $chado_table;
     $widget['#fkey_field'] = $fkey;
     //$widget['#element_validate'] = array('sbo__database_cross_reference_widget_validate');
     $widget['#theme'] = 'sbo__database_cross_reference_widget';
     $widget['#prefix'] =  "<span id='$field_name-dbxref--db-id-$delta'>";
     $widget['#suffix'] =  "</span>";
-    
-    
+
+
     $widget['value'] = array(
       '#type' => 'value',
       '#value' => array_key_exists($delta, $items) ? $items[$delta]['value'] : '',
     );
-    
+
     $widget['chado-' . $field_table . '__' . $pkey] = array(
       '#type' => 'value',
       '#default_value' => $record_id,
@@ -163,18 +163,18 @@ class sbo__database_cross_reference_widget extends TripalFieldWidget {
     $pkey = $schema['primary key'][0];
     $fkeys = array_values($schema['foreign keys'][$base_table]['columns']);
     $fkey = $fkeys[0];
-    
-    
+
+
     // Get the field values.
     foreach ($items as $delta => $values) {
-    
+
       // Get the field values.
       $dbxref_id = $values['chado-' . $field_table . '__dbxref_id'];
       $db_id = $values['db_id'];
       $accession = $values['accession'];
       $version = $values['version'];
       $description = $values['description'];
-    
+
       // Make sure that if a database ID is provided that an accession is also
       // provided.  Here we use the form_set_error function rather than the
       // form_error function because the form_error will add a red_highlight
@@ -219,14 +219,14 @@ class sbo__database_cross_reference_widget extends TripalFieldWidget {
     $pkey = $schema['primary key'][0];
     $fkeys = array_values($schema['foreign keys'][$base_table]['columns']);
     $fkey = $fkeys[0];
-    
+
     // Get the field values.
     $dbxref_id = isset($form_state['values'][$field_name][$langcode][$delta]['chado-' . $field_table . '__dbxref_id']) ? $form_state['values'][$field_name][$langcode][$delta]['chado-' . $field_table . '__dbxref_id'] : '';
     $db_id = isset($form_state['values'][$field_name][$langcode][$delta]['db_id']) ? $form_state['values'][$field_name][$langcode][$delta]['db_id'] : '';
     $accession = isset($form_state['values'][$field_name][$langcode][$delta]['accession']) ? $form_state['values'][$field_name][$langcode][$delta]['accession'] : '';
     $version = isset($form_state['values'][$field_name][$langcode][$delta]['version']) ? $form_state['values'][$field_name][$langcode][$delta]['version'] : '';
     $description = isset($form_state['values'][$field_name][$langcode][$delta]['description']) ? $form_state['values'][$field_name][$langcode][$delta]['description'] : '';
-    
+
     // If the dbxref_id does not match the db_id + accession then the user
     // has selected a new dbxref record and we need to update the hidden
     // value accordingly.

+ 48 - 52
tripal_chado/includes/TripalFields/sbo__relationship.inc

@@ -76,19 +76,19 @@ class sbo__relationship extends TripalField {
    */
   public function load($entity, $details = array()) {
     $settings = $this->field['settings'];
-    
+
     $record = $details['record'];
-    
+
     $field_name = $this->field['field_name'];
     $field_type = $this->field['type'];
     $field_table = $this->field['settings']['chado_table'];
     $field_column = $this->field['settings']['chado_column'];
     $base_table = $this->field['settings']['base_table'];
-    
+
     // Get the PKey for this table
     $schema = chado_get_schema($field_table);
     $pkey = $schema['primary key'][0];
-    
+
     // Get the Pkeys for the subject and object tables
     $subject_fkey_table = '';
     $object_fkey_table = '';
@@ -107,19 +107,19 @@ class sbo__relationship extends TripalField {
     $object_schema = chado_get_schema($object_fkey_table);
     $subject_pkey = $subject_schema['primary key'][0];
     $object_pkey = $object_schema['primary key'][0];
-    
+
     // Get the FK that links to the base record.
     $schema = chado_get_schema($field_table);
     $fkey_lcolumn = key($schema['foreign keys'][$base_table]['columns']);
     $fkey_rcolumn = $schema['foreign keys'][$base_table]['columns'][$fkey_lcolumn];
-    
+
     // Set some defaults for the empty record.
     $entity->{$field_name}['und'][0] = array(
       'value' => array(),
-      $field_table . '__' . $pkey => '',
-      $field_table . '__subject_id' => '',
-      $field_table . '__object_id' => '',
-      $field_table . '__type_id' => '',
+      'chado-' . $field_table . '__' . $pkey => '',
+      'chado-' . $field_table . '__subject_id' => '',
+      'chado-' . $field_table . '__object_id' => '',
+      'chado-' . $field_table . '__type_id' => '',
       // These elements don't need to follow the naming scheme above
       // becasue we don't need the chado_field_storage to try and
       // save these values.
@@ -127,21 +127,21 @@ class sbo__relationship extends TripalField {
       'subject_name' => '',
       'type_name' => '',
     );
-    
+
     // If the table has rank and value fields then add those to the default
     // value array.
     if (array_key_exists('value', $schema['fields'])) {
-      $entity->{$field_name}['und'][0][$field_table . '__value'] = '';
+      $entity->{$field_name}['und'][0]['chado-' . $field_table . '__value'] = '';
     }
     if (array_key_exists('rank', $schema['fields'])) {
-      $entity->{$field_name}['und'][0][$field_table . '__rank'] = '';
+      $entity->{$field_name}['und'][0]['chado-' . $field_table . '__rank'] = '';
     }
-    
+
     // If we have no record then just return.
     if (!$record) {
       return;
     }
-    
+
     // Expand the object to include the relationships.
     $options = array(
       'return_array' => 1,
@@ -168,11 +168,7 @@ class sbo__relationship extends TripalField {
     }
     $srelationships = null;
     $orelationships = null;
-    if ($rel_table == 'organism_relationship') {
-      $srelationships = $record->$rel_table->subject_organism_id;
-      $orelationships = $record->$rel_table->object_organism_id;
-    }
-    else if ($rel_table == 'nd_reagent_relationship') {
+    if ($rel_table == 'nd_reagent_relationship') {
       $srelationships = $record->$rel_table->subject_reagent_id;
       $orelationships = $record->$rel_table->object_reagent_id;
     }
@@ -184,7 +180,7 @@ class sbo__relationship extends TripalField {
       $srelationships = $record->$rel_table->subject_id;
       $orelationships = $record->$rel_table->object_id;
     }
-    
+
     $i = 0;
     if ($orelationships) {
       foreach ($orelationships as $relationship) {
@@ -222,31 +218,31 @@ class sbo__relationship extends TripalField {
         $entity->{$field_name}['und'][$i]['value']['phrase'] = 'The ' . $subject_type . ', ' .
             $subject_name . ', ' . $verb . ' '  . $rel_type_clean . ' this '  .
             $object_type . '.';
-    
+
             $entity->{$field_name}['und'][$i]['semantic_web'] = array(
               'type' => $rel_acc,
               'subject' => $relationship->subject_id->type_id->dbxref_id->db_id->name . ':' . $relationship->subject_id->type_id->dbxref_id->accession,
               'object' => $relationship->object_id->type_id->dbxref_id->db_id->name . ':' . $relationship->object_id->type_id->dbxref_id->accession,
             );
-    
-            $entity->{$field_name}['und'][$i][$field_table . '__' . $pkey] = $relationship->$pkey;
-            $entity->{$field_name}['und'][$i][$field_table . '__subject_id'] = $relationship->subject_id->$subject_pkey;
-            $entity->{$field_name}['und'][$i][$field_table . '__type_id'] = $relationship->type_id->cvterm_id;
-            $entity->{$field_name}['und'][$i][$field_table . '__object_id'] = $relationship->object_id->$object_pkey;
-    
+
+            $entity->{$field_name}['und'][$i]['chado-' . $field_table . '__' . $pkey] = $relationship->$pkey;
+            $entity->{$field_name}['und'][$i]['chado-' . $field_table . '__subject_id'] = $relationship->subject_id->$subject_pkey;
+            $entity->{$field_name}['und'][$i]['chado-' . $field_table . '__type_id'] = $relationship->type_id->cvterm_id;
+            $entity->{$field_name}['und'][$i]['chado-' . $field_table . '__object_id'] = $relationship->object_id->$object_pkey;
+
             $entity->{$field_name}['und'][$i]['type_name'] = $relationship->type_id->name;
             $entity->{$field_name}['und'][$i]['subject_name'] = $relationship->subject_id->name . ' [id: ' . $relationship->subject_id->$fkey_rcolumn . ']';
             $entity->{$field_name}['und'][$i]['object_name'] = $relationship->object_id->name  . ' [id: ' . $relationship->object_id->$fkey_rcolumn . ']';
             if (array_key_exists('value', $schema['fields'])) {
-              $entity->{$field_name}['und'][$i][$field_table . '__value'] = $relationship->value;
+              $entity->{$field_name}['und'][$i]['chado-' . $field_table . '__value'] = $relationship->value;
             }
             if (array_key_exists('rank', $schema['fields'])) {
-              $entity->{$field_name}['und'][$i][$field_table . '__rank'] = $relationship->rank;
+              $entity->{$field_name}['und'][$i]['chado-' . $field_table . '__rank'] = $relationship->rank;
             }
             $i++;
       }
     }
-    
+
     if ($srelationships) {
       foreach ($srelationships as $relationship) {
         $rel_acc = $relationship->type_id->dbxref_id->db_id->name . ':' . $relationship->type_id->dbxref_id->accession;
@@ -283,29 +279,29 @@ class sbo__relationship extends TripalField {
         $entity->{$field_name}['und'][$i]['value']['phrase'] = 'This  ' .
             $subject_type . ' ' . $verb . ' '  . $rel_type_clean . ' the '  .
             $object_type . ', ' . $object_name . '.';
-    
-    
+
+
             $entity->{$field_name}['und'][$i]['semantic_web'] = array(
               'type' => $rel_acc,
               'subject' => $relationship->subject_id->type_id->dbxref_id->db_id->name . ':' . $relationship->subject_id->type_id->dbxref_id->accession,
               'object' => $relationship->object_id->type_id->dbxref_id->db_id->name . ':' . $relationship->object_id->type_id->dbxref_id->accession,
             );
-    
-    
-            $entity->{$field_name}['und'][$i][$field_table . '__' . $pkey] = $relationship->$pkey;
-            $entity->{$field_name}['und'][$i][$field_table . '__subject_id'] = $relationship->subject_id->$subject_pkey;
-            $entity->{$field_name}['und'][$i][$field_table . '__type_id'] = $relationship->type_id->cvterm_id;
-            $entity->{$field_name}['und'][$i][$field_table . '__object_id'] = $relationship->object_id->$object_pkey;
-    
+
+
+            $entity->{$field_name}['und'][$i]['chado-' . $field_table . '__' . $pkey] = $relationship->$pkey;
+            $entity->{$field_name}['und'][$i]['chado-' . $field_table . '__subject_id'] = $relationship->subject_id->$subject_pkey;
+            $entity->{$field_name}['und'][$i]['chado-' . $field_table . '__type_id'] = $relationship->type_id->cvterm_id;
+            $entity->{$field_name}['und'][$i]['chado-' . $field_table . '__object_id'] = $relationship->object_id->$object_pkey;
+
             $entity->{$field_name}['und'][$i]['type_name'] = $relationship->type_id->name;
             $entity->{$field_name}['und'][$i]['subject_name'] = $relationship->subject_id->name  . ' [id: ' . $relationship->subject_id->$fkey_rcolumn . ']';
             $entity->{$field_name}['und'][$i]['object_name'] = $relationship->object_id->name  . ' [id: ' . $relationship->object_id->$fkey_rcolumn . ']';
-    
+
             if (array_key_exists('value', $schema['fields'])) {
-              $entity->{$field_name}['und'][$i][$field_table . '__value'] = $relationship->value;
+              $entity->{$field_name}['und'][$i]['chado-' . $field_table . '__value'] = $relationship->value;
             }
             if (array_key_exists('rank', $schema['fields'])) {
-              $entity->{$field_name}['und'][$i][$field_table . '__rank'] = $relationship->rank;
+              $entity->{$field_name}['und'][$i]['chado-' . $field_table . '__rank'] = $relationship->rank;
             }
             $i++;
       }
@@ -355,17 +351,17 @@ class sbo__relationship extends TripalField {
       default:
         $verb = 'is';
     }
-  
+
     return $verb;
   }
-  
+
   /**
    *
    * @see TripalField::settingsForm()
    */
   public function settingsForm($has_data) {
     $element = parent::instanceSettingsForm();
-    
+
     //$element = parent::instanceSettingsForm();
     $element['relationships'] = array(
       '#type' => 'fieldset',
@@ -393,7 +389,7 @@ class sbo__relationship extends TripalField {
         could use to specify relationship types. With this option any term in .
         the vocabulary can be used for the relationship type. You may select
         more than one vocabulary.'),
-    
+
     );
     $element['relationships']['option1_vocabs'] = array(
       '#type' => 'select',
@@ -403,7 +399,7 @@ class sbo__relationship extends TripalField {
       '#default_value' => $this->instance['settings']['relationships']['option1_vocabs'],
       // TODO add ajax here so that the relationship autocomplete below works
     );
-    
+
     $element['relationships']['option2'] = array(
       '#type' => 'item',
       '#title' => '<b>Option #2</b>',
@@ -445,7 +441,7 @@ class sbo__relationship extends TripalField {
       '#type' => 'textarea',
       '#default_value' => $this->instance['settings']['relationships']['relationship_types'],
     );
-    
+
     return $element;
   }
   /**
@@ -457,7 +453,7 @@ class sbo__relationship extends TripalField {
     // Get relationships settings
     $settings = $form_state['values']['instance']['settings']['relationships'];
     $form_state['values']['instance']['settings']['relationships']['relationship_types']= trim($settings['relationship_types']);
-    
+
     // Make sure only one option is selected
     $option1test = $settings['option1_vocabs'];
     $option1 = isset($settings['option1_vocabs']) && array_pop($option1test);
@@ -473,7 +469,7 @@ class sbo__relationship extends TripalField {
               );
           return;
         }
-    
+
         // For option3, make sure the supplied types are valid cvterms
         if ($option3) {
           $rel_types = explode(PHP_EOL, $settings['relationship_types']);
@@ -546,7 +542,7 @@ class sbo__relationship extends TripalField {
             }
           }
         }
-    
+
         // For option2: Make sure the parent term is a valid cvterm
         if ($option2) {
           $cv_id = $settings['option2_vocab'];

+ 134 - 114
tripal_chado/includes/TripalFields/sbo__relationship_widget.inc

@@ -13,131 +13,145 @@ class sbo__relationship_widget extends TripalFieldWidget {
    */
   public function form(&$widget, &$form, &$form_state, $langcode, $items, $delta, $element) {
     parent::form($widget, $form, $form_state, $langcode, $items, $delta, $element);
+
+    // Get the field settings.
+    $entity = $form['#entity'];
     $field_name = $this->field['field_name'];
     $field_type = $this->field['type'];
     $field_table = $this->field['settings']['chado_table'];
     $field_column = $this->field['settings']['chado_column'];
-    
-    // Get the instance settings
-    $instance = $this->instance;
-    $settings = $instance['settings']['relationships'];
-    
-    $option1_vocabs = $settings['option1_vocabs'];
-    $option2_vocab  = $settings['option2_vocab'];
-    $option2_parent = $settings['option2_parent'];
-    $option3_rtypes = $settings['relationship_types'];
-    
-    // For testing if there are selected vocabs for option1 we'll copy the
-    // contents in a special variable for later.
-    $option1_test   = $option1_vocabs;
-    
+    $base_table = $this->field['settings']['base_table'];
+
     // Get the FK column that links to the base table.
-    $chado_table = $this->field['settings']['chado_table'];
     $base_table = $this->field['settings']['base_table'];
-    $schema = chado_get_schema($chado_table);
+    $schema = chado_get_schema($field_table);
     $pkey = $schema['primary key'][0];
     $fkeys = array_values($schema['foreign keys'][$base_table]['columns']);
     $fkey = $fkeys[0];
-    
+
+    // Get the instance settings. There are three options for how this widget
+    // will be displayed. Those are controlled in the instance settings
+    // of the field.
+    // Option 1:  relationship types are limited to a specific vocabulary.
+    // Option 2:  relationship types are limited to a subset of one vocabulary.
+    // Option 3:  relationship types are limited to a predefined set.
+    $instance = $this->instance;
+    $settings = '';
+    $option1_vocabs = '';
+    $option2_parent = '';
+    $option2_vocab = '';
+    $option3_rtypes  = '';
+    if (array_key_exists('relationships', $instance)) {
+      $settings = $instance['settings']['relationships'];
+      $option1_vocabs = $settings['option1_vocabs'];
+      $option2_vocab  = $settings['option2_vocab'];
+      $option2_parent = $settings['option2_parent'];
+      $option3_rtypes = $settings['relationship_types'];
+    }
+
+    // For testing if there are selected vocabs for option1 we'll copy the
+    // contents in a special variable for later.
+    $option1_test = $option1_vocabs;
+
     // Get the field defaults.
     $record_id = '';
-    $fkey_value = $element['#entity'] ? $element['#entity']->chado_record_id : '';
     $subject_id = '';
-    $subject_uniquename = '';
-    $type_id = '';
-    $type = '';
     $object_id = '';
-    $object_uniquename = '';
+    $type_id = '';
     $value = '';
     $rank = '';
-    
+    $subject_uniquename = '';
+    $object_uniquename = '';
+    $type = '';
+
     // Handle special cases
     $subject_id_key = 'subject_id';
     $object_id_key = 'object_id';
-    if ($chado_table == 'organism_relationship') {
-      $subject_id_key = 'subject_organism_id';
-      $object_id_key = 'object_organism_id';
-    }
-    else if ($chado_table == 'nd_reagent_relationship') {
+    if ($field_table == 'nd_reagent_relationship') {
       $subject_id_key = 'subject_reagent_id';
       $object_id_key = 'object_reagent_id';
     }
-    else if ($chado_table == 'project_relationship') {
+    else if ($field_table == 'project_relationship') {
       $subject_id_key = 'subject_project_id';
       $object_id_key = 'object_project_id';
     }
-    
+
     // If the field already has a value then it will come through the $items
     // array.  This happens when editing an existing record.
-    if (array_key_exists($delta, $items)) {
-      $record_id = isset($items[$delta][$field_table . '__' . $pkey]) ? $items[$delta][$field_table . '__' . $pkey] : '';
-      $subject_id = isset($items[$delta][$field_table . '__' . $subject_id_key]) ? $items[$delta][$field_table . '__' . $subject_id_key] : '';
-      $type_id = isset($items[$delta][$field_table . '__type_id']) ? $items[$delta][$field_table . '__type_id'] : '';
-      $object_id = isset($items[$delta][$field_table . '__' . $object_id_key]) ? $items[$delta][$field_table . '__' . $object_id_key] : '';
-    
-      if (isset($items[$delta][$field_table . '__value'])) {
-        $value = $items[$delta][$field_table . '__value'];
+    if (count($items) > 0 and array_key_exists($delta, $items)) {
+      // Check for element values that correspond to fields in the Chado table.
+      $record_id = tripal_get_field_item_keyval($items, $delta, 'chado-' . $field_table . '__' . $pkey, $record_id);
+      $subject_id = tripal_get_field_item_keyval($items, $delta, 'chado-' . $field_table . '__' . $subject_id_key, $subject_id);
+      $object_id = tripal_get_field_item_keyval($items, $delta, 'chado-' . $field_table . '__' . $object_id_key, $object_id);
+      $type_id = tripal_get_field_item_keyval($items, $delta, 'chado-' . $field_table . '__type_id', $type_id);
+      // Not all Chado tables have a value and rank.  So we'll only get
+      // those if applicable.
+      if (array_key_exists('value', $schema['fields'])) {
+        $value = tripal_get_field_item_keyval($items, $delta, 'chado-' . $field_table . '__value', $value);
       }
-      if (isset($items[$delta][$field_table . '__rank'])) {
-        $rank = $items[$delta][$field_table . '__rank'];
+      if (array_key_exists('rank', $schema['fields'])) {
+        $rank = tripal_get_field_item_keyval($items, $delta, 'chado-' . $field_table . '__rank', $rank);
       }
-    
-      $object_uniquename = isset($items[$delta]['object_name']) ? $items[$delta]['object_name'] : '';
-      $subject_uniquename = isset($items[$delta]['subject_name']) ? $items[$delta]['subject_name'] : '';
-      $type = isset($items[$delta]['type_name']) ? $items[$delta]['type_name'] : '';
+      // Get element values added to help support insert/updates.
+      $object_uniquename = tripal_get_field_item_keyval($items, $delta, 'object_name', $object_uniquename);
+      $subject_uniquename = tripal_get_field_item_keyval($items, $delta, 'subject_name', $subject_uniquename);
+      $type = tripal_get_field_item_keyval($items, $delta, 'type_name', $type);
     }
-    
+
     // Check $form_state['values'] to see if an AJAX call set the values.
     if (array_key_exists('values', $form_state) and array_key_exists($delta, $form_state['values'])) {
-      //       $record_id = tripal_chado_get_field_form_values($field_name, $form_state, $delta, $field_table . '__' . $pkey);
-      //       $subject_id = tripal_chado_get_field_form_values($field_name, $form_state, $delta, $field_table . '__subject_id');
-      //       $subject_uniquename = tripal_chado_get_field_form_values($field_name, $form_state, $delta, 'subject_name');
-      //       $type_id = tripal_chado_get_field_form_values($field_name, $form_state, $delta, $field_table . '__type_id');
-      //       $type = tripal_chado_get_field_form_values($field_name, $form_state, $delta, 'type_name');
-      //       $object_id = tripal_chado_get_field_form_values($field_name, $form_state, $delta, $field_table . '__object_id');
-      //       $object_uniquename = tripal_chado_get_field_form_values($field_name, $form_state, $delta, 'object_name');
-      //       $value = tripal_chado_get_field_form_values($field_name, $form_state, $delta, $field_table . '__value');
-      //       $rank = tripal_chado_get_field_form_values($field_name, $form_state, $delta, $field_table . '__rank');
+      $record_id = $form_state['values'][$field_name]['und'][$delta]['chado-' . $field_table . '__' . $pkey];
+      $subject_id = $form_state['values'][$field_name]['und'][$delta]['chado-' . $field_table . '__' . $subject_id_key];
+      $object_id = $form_state['values'][$field_name]['und'][$delta]['chado-' . $field_table . '__' . $object_id_key];
+      $type_id = $form_state['values'][$field_name]['und'][$delta]['chado-' . $field_table . '__type_id'];
+      if (array_key_exists('value', $schema['fields'])) {
+        $value = $form_state['values'][$field_name]['und'][$delta]['chado-' . $field_table . '__value'];
+      }
+      if (array_key_exists('rank', $schema['fields'])) {
+        $rank = $form_state['values'][$field_name]['und'][$delta]['chado-' . $field_table . '__rank'];
+      }
+      $object_uniquename = $form_state['values'][$field_name]['und'][$delta]['object_name'];
+      $subject_uniquename = $form_state['values'][$field_name]['und'][$delta]['subject_name'];
+      $type = $form_state['values'][$field_name]['und'][$delta]['type_name'];
     }
-    
-    $widget['#table_name'] = $chado_table;
+   $widget['#table_name'] = $chado_table;
     
     $widget['#fkeys'] = $schema['foreign keys'];
     $widget['#base_table'] = $base_table;
     $widget['#chado_record_id'] = isset($form['#entity']) ? $form['#entity']->chado_record_id : '';
     //$widget['#element_validate'] = array('sbo__relationship_validate');
     $widget['#theme'] = 'sbo__relationship_widget';
-    $widget['#prefix'] =  "<span id='$chado_table-$delta'>";
+    $widget['#prefix'] =  "<span id='$field_table-$delta'>";
     $widget['#suffix'] =  "</span>";
-    
+
     $widget['value'] = array(
       '#type' => 'value',
       '#value' => array_key_exists($delta, $items) ? $items[$delta]['value'] : '',
     );
-    $widget[$field_table . '__' . $pkey] = array(
+    $widget['chado-' . $field_table . '__' . $pkey] = array(
       '#type' => 'value',
       '#default_value' => $record_id,
     );
-    $widget[$field_table . '__' . $subject_id_key] = array(
+    $widget['chado-' . $field_table . '__' . $subject_id_key] = array(
       '#type' => 'value',
       '#default_value' => $subject_id,
     );
-    $widget[$field_table . '__type_id'] = array(
+    $widget['chado-' . $field_table . '__type_id'] = array(
       '#type' => 'value',
       '#default_value' => $type_id,
     );
-    $widget[$field_table . '__' . $object_id_key] = array(
+    $widget['chado-' . $field_table . '__' . $object_id_key] = array(
       '#type' => 'value',
       '#default_value' => $object_id,
     );
     if (array_key_exists('value', $schema['fields'])) {
-      $widget[$field_table . '__value'] = array(
+      $widget['chado-' . $field_table . '__value'] = array(
         '#type' => 'value',
         '#default_value' => $value,
       );
     }
     if (array_key_exists('rank', $schema['fields'])) {
-      $widget[$field_table . '__rank'] = array(
+      $widget['chado-' . $field_table . '__rank'] = array(
         '#type' => 'value',
         '#default_value' => $rank,
       );
@@ -151,8 +165,8 @@ class sbo__relationship_widget extends TripalFieldWidget {
       '#size' => 35,
       '#autocomplete_path' => "admin/tripal/storage/chado/auto_name/$base_table",
     );
-    
-    // Getting default values
+
+    // Getting default values for the relationship type element.
     $default_voc = '';
     if (isset($form_state['field'][$field_name]['und']['instance']['default_value'][0]['vocabulary'])) {
       $default_voc = $form_state['field'][$field_name]['und']['instance']['default_value'][0]['vocabulary'];
@@ -161,7 +175,7 @@ class sbo__relationship_widget extends TripalFieldWidget {
     if (isset($form_state['field'][$field_name]['und']['instance']['default_value'][0]['type_name'])) {
       $default_term = $form_state['field'][$field_name]['und']['instance']['default_value'][0]['type_name'];
     }
-    
+
     $default_type_id = $type_id;
     if (!$type_id && isset($form_state['field'][$field_name]['und']['instance']['default_value'][0]['type_id'])) {
       $default_type_id = $form_state['field'][$field_name]['und']['instance']['default_value'][0]['type_id'];
@@ -203,7 +217,7 @@ class sbo__relationship_widget extends TripalFieldWidget {
         'name' => $option2_parent
       );
       $parent_term = tripal_get_cvterm($values);
-    
+
       // If the term wasn't found then see if it's a synonym.
       if(!$parent_term) {
         $values = array(
@@ -217,16 +231,14 @@ class sbo__relationship_widget extends TripalFieldWidget {
         }
       }
       // Get the child terms of the parent term found above.
-      $sql =
-      "SELECT
-           subject_id,
-           (SELECT name from {cvterm} where cvterm_id = subject_id) AS name
-         FROM {cvtermpath}
-         WHERE
-           object_id = :parent_cvterm_id
-         AND
-           cv_id = :parent_cv_id
-         ORDER BY name
+      $sql = "
+        SELECT subject_id,
+          (SELECT name from {cvterm} where cvterm_id = subject_id) AS name
+        FROM {cvtermpath}
+        WHERE
+          object_id = :parent_cvterm_id AND
+          cv_id = :parent_cv_id
+        ORDER BY name
        ";
       $args = array(
         ':parent_cvterm_id' => $parent_term->cvterm_id,
@@ -288,7 +300,7 @@ class sbo__relationship_widget extends TripalFieldWidget {
         '#default_value' => $cv_id,
         '#ajax' => array(
           'callback' => "sbo__relationship_widget_form_ajax_callback",
-          'wrapper' => "$chado_table-$delta",
+          'wrapper' => "$field_table-$delta",
           'effect' => 'fade',
           'method' => 'replace'
         ),
@@ -304,7 +316,7 @@ class sbo__relationship_widget extends TripalFieldWidget {
         );
       }
     }
-    
+
     $widget['object_name'] = array(
       '#type' => 'textfield',
       '#title' => t('Object'),
@@ -332,18 +344,14 @@ class sbo__relationship_widget extends TripalFieldWidget {
     $field_table = $this->field['settings']['chado_table'];
     $field_column = $this->field['settings']['chado_column'];
     $base_table = $this->field['settings']['base_table'];
-    
+
     $schema = chado_get_schema($field_table);
     $fkeys = $schema['foreign keys'];
-    
+
     // Handle special cases
     $subject_id_key = 'subject_id';
     $object_id_key = 'object_id';
-    if ($field_table == 'organism_relationship') {
-      $subject_id_key = 'subject_organism_id';
-      $object_id_key = 'object_organism_id';
-    }
-    else if ($field_table == 'nd_reagent_relationship') {
+    if ($field_table == 'nd_reagent_relationship') {
       $subject_id_key = 'subject_reagent_id';
       $object_id_key = 'object_reagent_id';
     }
@@ -351,22 +359,22 @@ class sbo__relationship_widget extends TripalFieldWidget {
       $subject_id_key = 'subject_project_id';
       $object_id_key = 'object_project_id';
     }
-    
+
     foreach ($items as $delta => $item) {
-      $subject_id = $item[$field_table . '__' . $subject_id_key];
-      $object_id = $item[ $field_table . '__' . $object_id_key];
-      $type_id = $item[$field_table . '__type_id'];
-      $type_id = isset($item['type_id']) ? $item['type_id'] : $type_id;
+      $subject_id = $item['chado' . $field_table . '__' . $subject_id_key];
+      $object_id = $item['chado' . $field_table . '__' . $object_id_key];
+      $type_id = $item['chado' . $field_table . '__type_id'];
+      $type_id = isset($item['type_id']) ? $item['chado' . $field_table . '__type_id'] : $type_id;
       $type_name = isset($item['type_name']) ? $item['type_name'] : '';
       $subject_name = $item['subject_name'];
       $object_name = $item['object_name'];
-    
-    
+
+
       // If the row is empty then just continue, there's nothing to validate.
       if (!$type_id and !$type_name and !$subject_name and !$object_name) {
         continue;
       }
-    
+
       // Make sure we have values for all of the fields.
       $form_error = FALSE;
       if (!$type_name && !$type_id) {
@@ -390,9 +398,9 @@ class sbo__relationship_widget extends TripalFieldWidget {
       if ($form_error) {
         continue;
       }
-    
+
       // Before submitting this form we need to make sure that our subject_id and
-      // object_ids are real values.  There are two ways to get the value, either
+      // object_ids are real records.  There are two ways to get the record, either
       // just with the text value or with an [id: \d+] string embedded.  If the
       // later we will pull it out.
       $subject_id = '';
@@ -427,7 +435,7 @@ class sbo__relationship_widget extends TripalFieldWidget {
           }
         }
       }
-    
+
       // Now check for a matching object.
       $object_id = '';
       $fkey_rcolumn = $fkeys[$base_table]['columns'][$object_id_key];
@@ -461,7 +469,7 @@ class sbo__relationship_widget extends TripalFieldWidget {
           }
         }
       }
-    
+
       // Make sure that either our object or our subject refers to the base record.
       if ($entity) {
         $chado_record_id = $entity->chado_record_id;
@@ -471,7 +479,7 @@ class sbo__relationship_widget extends TripalFieldWidget {
             'message' =>  t("Either the subject or the object in the relationship must refer to this record."),
           );
         }
-    
+
         // Make sure that the object and subject are not both the same thing.
         if ($object_id == $subject_id) {
           $errors[$this->field['field_name']][$langcode][$delta][] = array(
@@ -495,23 +503,35 @@ class sbo__relationship_widget extends TripalFieldWidget {
     $field_column = $this->field['settings']['chado_column'];
     $base_table = $this->field['settings']['base_table'];
     $chado_record_id = $entity->chado_record_id;
-    
+
     $schema = chado_get_schema($field_table);
     $fkeys = $schema['foreign keys'];
-    
+
+    // Handle special cases
+    $subject_id_key = 'subject_id';
+    $object_id_key = 'object_id';
+    if ($field_table == 'nd_reagent_relationship') {
+      $subject_id_key = 'subject_reagent_id';
+      $object_id_key = 'object_reagent_id';
+    }
+    else if ($field_table == 'project_relationship') {
+      $subject_id_key = 'subject_project_id';
+      $object_id_key = 'object_project_id';
+    }
+
     $type_name = array_key_exists('type_name', $item) ? $item['type_name'] : '';
-    $subject_id = $form_state['values'][$field_name][$langcode][$delta][$field_table . '__subject_id'];
-    $object_id = $form_state['values'][$field_name][$langcode][$delta][ $field_table . '__object_id'];
-    $type_id = $form_state['values'][$field_name][$langcode][$delta][$field_table . '__type_id'];
-    
+    $subject_id = $form_state['values'][$field_name][$langcode][$delta]['chado' . $field_table . '__' . $subject_id_key];
+    $object_id = $form_state['values'][$field_name][$langcode][$delta]['chado' . $field_table . '__' . $object_id_key];
+    $type_id = $form_state['values'][$field_name][$langcode][$delta]['chado' . $field_table . '__type_id'];
+
     $subject_name = $form_state['values'][$field_name][$langcode][$delta]['subject_name'];
     $object_name = $form_state['values'][$field_name][$langcode][$delta]['object_name'];
-    
+
     // If the row is empty then skip this one, there's nothing to validate.
     if (!($type_id or !$type_name) and !$subject_name and !$object_name) {
       return;
     }
-    
+
     // Get the subject ID.
     $subject_id = '';
     $fkey_rcolumn = $fkeys[$base_table]['columns']['subject_id'];
@@ -524,7 +544,7 @@ class sbo__relationship_widget extends TripalFieldWidget {
       $subject = chado_select_record($base_table, array($fkey_rcolumn), $values);
       $subject_id = $subject[0]->$fkey_rcolumn;
     }
-    
+
     // Get the object ID.
     $object_id = '';
     $fkey_rcolumn = $fkeys[$base_table]['columns']['object_id'];
@@ -537,12 +557,12 @@ class sbo__relationship_widget extends TripalFieldWidget {
       $object = chado_select_record($base_table, array($fkey_rcolumn), $values);
       $object_id = $object[0]->$fkey_rcolumn;
     }
-    
+
     // Set the IDs according to the values that were determined above.
-    $form_state['values'][$field_name][$langcode][$delta][$field_table . '__subject_id'] = $subject_id;
-    $form_state['values'][$field_name][$langcode][$delta][$field_table . '__object_id'] = $object_id;
-    $form_state['values'][$field_name][$langcode][$delta][$field_table . '__type_id'] = $type_name;
-    $form_state['values'][$field_name][$langcode][$delta][$field_table . '__rank'] = $item['_weight'];
+    $form_state['values'][$field_name][$langcode][$delta]['chado' . $field_table . '__' . $subject_id_key] = $subject_id;
+    $form_state['values'][$field_name][$langcode][$delta]['chado' . $field_table . '__' . $object_id_key] = $object_id;
+    $form_state['values'][$field_name][$langcode][$delta]['chado' . $field_table . '__type_id'] = $type_name;
+    $form_state['values'][$field_name][$langcode][$delta]['chado' . $field_table . '__rank'] = $item['_weight'];
   }
 }
 

+ 16 - 16
tripal_chado/includes/TripalFields/schema__alternate_name_widget.inc

@@ -15,7 +15,7 @@ class schema__alternate_name_widget extends TripalFieldWidget {
     parent::form($widget, $form, $form_state, $langcode, $items, $delta, $element);
     $entity = $form['#entity'];
     $field_name = $this->field['field_name'];
-    
+
     // Get the FK column that links to the base table.
     $table_name = $this->field['settings']['chado_table'];
     $base_table = $this->field['settings']['base_table'];
@@ -23,7 +23,7 @@ class schema__alternate_name_widget extends TripalFieldWidget {
     $pkey = $schema['primary key'][0];
     $fkeys = array_values($schema['foreign keys'][$base_table]['columns']);
     $fkey = $fkeys[0];
-    
+
     // Get the field defaults.
     $record_id = '';
     $fkey_value = $element['#entity']->chado_record_id;
@@ -33,7 +33,7 @@ class schema__alternate_name_widget extends TripalFieldWidget {
     $is_internal = FALSE;
     $syn_name = '';
     $syn_type = '';
-    
+
     // If the field already has a value then it will come through the $items
     // array.  This happens when editing an existing record.
     if (array_key_exists($delta, $items)) {
@@ -45,7 +45,7 @@ class schema__alternate_name_widget extends TripalFieldWidget {
       $syn_name = $items[$delta]['name'];
       $syn_type = $items[$delta]['type_id'];
     }
-    
+
     // Check $form_state['values'] to see if an AJAX call set the values.
     if (array_key_exists('values', $form_state) and array_key_exists($delta, $form_state['values'])) {
       $record_id = $form_state['values'][$field_name]['und'][$delta]['chado-' . $table_name . '__' . $pkey];
@@ -56,7 +56,7 @@ class schema__alternate_name_widget extends TripalFieldWidget {
       $syn_name = $form_state['values'][$field_name]['und'][$delta]['name'];
       $syn_type = $form_state['values'][$field_name]['und'][$delta]['type_id'];
     }
-    
+
     $options = array();
     $value = array('cv_id' => array('name' => 'synonym_type'));
     $op = array('return_array' => 1);
@@ -66,22 +66,22 @@ class schema__alternate_name_widget extends TripalFieldWidget {
         $options[$type->cvterm_id] = $type->name;
       }
     }
-    
+
     // Get the schema for the synonym table so we can make sure we limit the
     // size of the name field to the proper size.
     $schema = chado_get_schema('synonym');
-    
+
     $widget['#table_name'] = $table_name;
     $widget['#fkey_field'] = $fkey;
     $widget['#theme'] = 'schema__alternate_name_widget';
     $widget['#prefix'] =  "<span id='$table_name-$delta'>";
     $widget['#suffix'] =  "</span>";
-    
+
     $widget['value'] = array(
       '#type' => 'value',
       '#value' => array_key_exists($delta, $items) ? $items[$delta]['value'] : '',
     );
-    
+
     $widget['chado-' . $table_name . '__' . $pkey] = array(
       '#type' => 'value',
       '#default_value' => $record_id,
@@ -111,14 +111,14 @@ class schema__alternate_name_widget extends TripalFieldWidget {
       '#default_value' => $syn_name,
       '#size' => 25,
     );
-    
+
     $widget['chado-' . $table_name . '__is_current'] = array(
       '#type' => 'checkbox',
       '#title' => t('Is Current'),
       '#default_value' => $is_current,
       '#required' => $element['#required'],
     );
-    
+
     $widget['chado-' . $table_name . '__is_internal'] = array(
       '#type' => 'checkbox',
       '#title' => t('Is Internal'),
@@ -157,7 +157,7 @@ class schema__alternate_name_widget extends TripalFieldWidget {
     $pkey = $schema['primary key'][0];
     $fkeys = array_values($schema['foreign keys'][$base_table]['columns']);
     $fkey = $fkeys[0];
-    
+
     $record_id = isset($form_state['values'][$field_name][$langcode][$delta]['chado-' . $table_name . '__' . $pkey]) ? $form_state['values'][$field_name][$langcode][$delta]['chado-' . $table_name . '__' . $pkey] : '';
     $fkey_value = isset($form_state['values'][$field_name][$langcode][$delta]['chado-' . $table_name . '__' . $fkey]) ? $form_state['values'][$field_name][$langcode][$delta]['chado-' . $table_name . '__' . $fkey] : '';
     $synonym_id = isset($form_state['values'][$field_name][$langcode][$delta]['chado-' . $table_name . '__synonym_id']) ? $form_state['values'][$field_name][$langcode][$delta]['chado-' . $table_name . '__synonym_id'] : '';
@@ -166,11 +166,11 @@ class schema__alternate_name_widget extends TripalFieldWidget {
     $is_internal = isset($form_state['values'][$field_name][$langcode][$delta]['chado-' . $table_name . '__is_internal']) ? $form_state['values'][$field_name][$langcode][$delta]['chado-' . $table_name . '__is_internal'] : '';
     $syn_name = isset($form_state['values'][$field_name][$langcode][$delta]['name']) ? $form_state['values'][$field_name][$langcode][$delta]['name'] : '';
     $syn_type = isset($form_state['values'][$field_name][$langcode][$delta]['type_id']) ? $form_state['values'][$field_name][$langcode][$delta]['type_id'] : '';
-    
+
     // If the user provided a $syn_name and a $syn_type then we want to set
     // the foreign key value to be the chado_record_id.
     if ($syn_name and $syn_type) {
-    
+
       // Get the synonym. If one with the same name and type is already present
       // then use that. Otherwise, insert a new one.
       if (!$synonym_id) {
@@ -183,11 +183,11 @@ class schema__alternate_name_widget extends TripalFieldWidget {
           ));
           $synonym = (object) $synonym;
         }
-    
+
         // Set the synonym_id and FK value
         $form_state['values'][$field_name][$langcode][$delta]['chado-' . $table_name . '__synonym_id'] = $synonym->synonym_id;
       }
-    
+
       if (!$pub_id) {
         $pub = chado_generate_var('pub', array('uniquename' => 'null'));
         $form_state['values'][$field_name][$langcode][$delta]['chado-' . $table_name . '__pub_id'] = $pub->pub_id;

+ 96 - 0
tripal_chado/includes/TripalFields/so__cds.inc

@@ -0,0 +1,96 @@
+<?php
+
+class so__cds extends TripalField {
+
+
+  // --------------------------------------------------------------------------
+  //                     EDITABLE STATIC CONSTANTS
+  //
+  // The following constants SHOULD be set for each descendent class.  They are
+  // used by the static functions to provide information to Drupal about
+  // the field and it's default widget and formatter.
+  // --------------------------------------------------------------------------
+
+  // The term that this field maps to.  The format for the term should be:
+  // [vocab]:[accession] where [vocab] is the short name of the vocabulary
+  // and [acession] is the unique accession number for the term.  This term
+  // must already exist in the vocabulary storage backend. This
+  // value should never be changed once fields exist for this type.
+  public static $term = 'SO:0000316';
+
+  // The default lable for this field.
+  public static $label = 'Coding Sequence';
+
+  // The default description for this field.
+  public static $description = 'A contiguous sequence which begins with, and includes, a start codon and ends with, and includes, a stop codon.';
+
+  // Provide a list of global settings. These can be accessed witihn the
+  // globalSettingsForm.  When the globalSettingsForm is submitted then
+  // Drupal will automatically change these settings for all fields.
+  public static $settings = array(
+    'chado_table' => '',
+    'chado_column' => '',
+    'base_table' => '',
+  );
+
+  // Provide a list of instance specific settings. These can be access within
+  // the instanceSettingsForm.  When the instanceSettingsForm is submitted
+  // then Drupal with automatically change these settings for the instnace.
+  // It is recommended to put settings at the instance level whenever possible.
+  public static $instance_settings  = array();
+
+  // Set this to the name of the storage backend that by default will support
+  // this field.
+  public static $storage = 'tripal_no_storage';
+
+  // The default widget for this field.
+  public static $default_widget = 'so__cds_widget';
+
+  // The default formatter for this field.
+  public static $default_formatter = 'so__cds_formatter';
+
+  /**
+   * @see TripalField::load()
+   */
+  public function load($entity, $details = array()) {
+    $field_name = $this->field['field_name'];
+    $feature = $details['record'];
+    $num_seqs = 0;
+
+    $feature = chado_expand_var($feature, 'table', 'featureloc', $options);
+    $featureloc_sequences = chado_get_featureloc_sequences($feature->feature_id, $feature->featureloc->feature_id);
+    foreach($featureloc_sequences as $src => $attrs){
+      // Generate a CDS sequence if one exsits for this feature alignment.
+      $cds_sequence = tripal_get_feature_sequences(
+        array(
+          'feature_id' => $feature->feature_id,
+          'parent_id' => $attrs['featureloc']->srcfeature_id->feature_id,
+          'name' => $feature->name,
+          'featureloc_id' => $attrs['featureloc']->featureloc_id,
+        ),
+        array(
+          // CDS are in parent-child relationships so we want to use the
+          // sequence from the parent
+          'derive_from_parent' => 1,
+          // we want to combine all CDS for this feature into a single sequence
+          'aggregate' => 1,
+          // we're looking for CDS features
+          'sub_feature_types' => array('CDS'),
+          'is_html' => 0
+        )
+      );
+
+      if (count($cds_sequence) > 0) {
+        $defline = tripal_get_fasta_defline($feature, '', $attrs['featureloc'], 'CDS', strlen($attrs['residues']));
+
+        // the tripal_get_feature_sequences() function can return multiple sequences
+        // if a feature is aligned to multiple places. In the case of CDSs we expect
+        // that one mRNA is only aligned to a single location on the assembly so we
+        // can access the CDS sequence with index 0.
+        if ($cds_sequence[0]['residues']) {
+          $entity->{$field_name}['und'][$num_seqs++]['value'] = $defline . "\n" .  $cds_sequence[0]['residues'];
+        }
+      }
+    }
+  }
+}

+ 44 - 0
tripal_chado/includes/TripalFields/so__cds_formatter.inc

@@ -0,0 +1,44 @@
+<?php
+
+class so__cds_formatter extends TripalFieldFormatter {
+  // The default lable for this field.
+  public static $label = 'Coding Sequence';
+
+  // The list of field types for which this formatter is appropriate.
+  public static $field_types = array('so__cds');
+
+  // The list of default settings for this formatter.
+  public static $settings = array();
+
+  /**
+   * @see TripalFieldFormatter::view()
+   */
+  public function view(&$element, $entity_type, $entity, $langcode, $items, $display) {
+    $element[0] = array(
+      // We create a render array to produce the desired markup,
+      '#type' => 'markup',
+      '#markup' => '',
+    );
+
+    $num_bases = 50;
+    foreach ($items as $delta => $item) {
+      // If there are no residues then skip this one.
+      if (!is_array($item['value']) or !array_key_exists('residues', $item['value'])) {
+        continue;
+      }
+
+      $residues = $item['value']['residues'];
+
+      $content .= '<pre class="residues-formatter">';
+      $content .= '>' . $defline . "<br>";
+      $content .= wordwrap($residues, $num_bases, "<br>", TRUE);
+      $content .= '</pre>';
+
+      $element[$delta] = array(
+        // We create a render array to produce the desired markup,
+        '#type' => 'markup',
+        '#markup' => $content,
+      );
+    }
+  }
+}

+ 43 - 0
tripal_chado/includes/TripalFields/so__cds_widget.inc

@@ -0,0 +1,43 @@
+<?php
+
+class so__cds_widget extends TripalFieldWidget {
+  // The default lable for this field.
+  public static $label = 'Coding Sequence';
+
+  // The list of field types for which this formatter is appropriate.
+  public static $field_types = array('so__cds');
+
+  /**
+   *
+   * @see TripalFieldWidget::form()
+   */
+  public function form(&$widget, &$form, &$form_state, $langcode, $items, $delta, $element) {
+    parent::form($widget, $form, $form_state, $langcode, $items, $delta, $element);
+
+    // TODO: add a widget...
+  }
+
+  /**
+   * Performs validation of the widgetForm.
+   *
+   * Use this validate to ensure that form values are entered correctly.  Note
+   * this is different from the validate() function which ensures that the
+   * field data meets expectations.
+   *
+   * @param $form
+   * @param $form_state
+   */
+  public function validate($form, &$form_state, $entity_type, $entity, $langcode, $delta) {
+
+  }
+
+
+  /**
+   *
+   * @see TripalFieldWidget::submit()
+   */
+  public function submit($form, &$form_state, $entity_type, $entity, $langcode, $delta) {
+    $field_name = $this->field['field_name'];
+
+  }
+}

+ 45 - 53
tripal_chado/includes/TripalFields/so__transcript.inc

@@ -19,7 +19,7 @@ class so__transcript extends TripalField {
   public static $term = 'SO:0000673';
 
   // The default lable for this field.
-  public static $label = 'Transcript';
+  public static $label = 'Transcripts';
 
   // The default description for this field.
   public static $description = 'An RNA synthesized on a DNA or RNA template by an RNA polymerase.';
@@ -77,9 +77,11 @@ class so__transcript extends TripalField {
   public function load($entity, $details = array()) {
 
     $record = $details['record'];
-    
     $field_name = $this->field['field_name'];
-    
+    $field_type = $this->field['type'];
+    $field_table = $this->field['settings']['chado_table'];
+    $field_column = $this->field['settings']['chado_column'];
+
     // Set some defaults for the empty record.
     $entity->{$field_name}['und'][0] = array(
       'value' => array(
@@ -89,56 +91,46 @@ class so__transcript extends TripalField {
         'location' => '',
       ),
     );
-    
-    // TODO: If the tripal_get_feature_relationships() slows this down then
-    // we may need to write a custom function to get the data.
-    $rels = tripal_get_feature_relationships($record);
-    
-    // TODO: what if other transcripts names from SO are used. In that
-    // case we should support those too (using cvtermpath table to find them).
-    // mRNA should not be hard-coded below.
-    
-    // Set the value to be a array of "table" rows.
-    $transcripts = array();
-    if (key_exists('part of', $rels['object']) &&
-        key_exists('mRNA', $rels['object']['part of'])) {
-          $transcripts =  $rels['object']['part of']['mRNA'];
-        }
-    
-        $headers = array('Name' ,'Identifier', 'Location');
-        $rows = array();
-        $i = 0;
-        foreach ($transcripts as $transcript) {
-          // link the feature to it's node
-          $feature_name = $transcript->record->subject_id->name;
-    
-          $locations = $transcript->child_featurelocs;
-          $loc = "";
-          foreach ($locations AS $location) {
-            $loc .= $location->srcfeature_name . ":" . $location->fmin . ".." . $location->fmax;
-          }
-          $type = $transcript->record->subject_id->type_id;
-          $entity->{$field_name}['und'][$i]['value'] = array(
-            'type' => $type->name,
-            'name' => $feature_name,
-            'identifier' => $transcript->record->subject_id->uniquename,
-            'location' => $loc,
-    
-          );
-          // Add in the semantic web information that describes each key in the
-          // value array.
-          $entity->{$field_name}['und'][$i]['semantic_web'] = array(
-            'type' => $type->dbxref_id->db_id->name . ":" . $type->dbxref_id->accession,
-            'name' => tripal_get_chado_semweb_term('cvterm', 'name'),
-            'identifier' => tripal_get_chado_semweb_term('feature', 'uniquename'),
-            'location' => '',
-          );
-          if (property_exists($transcript->record->subject_id, 'entity_id')) {
-            $entity_id = $transcript->record->subject_id->entity_id;
-            $entity->{$field_name}['und'][$i]['value']['entity'] = 'TripalEntity:' . $entity_id;
-          }
-          $i++;
-        }
+
+    // Get the mRNA features for this gene.
+    $sql = "
+      SELECT FS.name, FS.uniquename, FS.feature_id, FCVT.name as type
+      FROM {feature_relationship} FR
+        INNER JOIN {feature} FS on FS.feature_id = FR.subject_id
+        INNER JOIN {cvterm} FCVT on FCVT.cvterm_id = FS.type_id
+        INNER JOIN {cv} CV on CV.cv_id = FCVT.cv_id
+      WHERE
+        FR.object_id = :feature_id and
+        FCVT.name = 'mRNA' and
+        CV.name = 'sequence'
+    ";
+    $results = chado_query($sql, array(':feature_id' => $record->feature_id));
+    $i = 0;
+    while ($transcript = $results->fetchObject()) {
+      // Get the location of this mRNA.
+      $sql = "
+        SELECT FL.*, F.name as srcfeature_name
+        FROM {featureloc} FL
+          INNER JOIN {feature} F on F.feature_id = FL.srcfeature_id
+        WHERE FL.feature_id = :object_id
+      ";
+      $floc_results = chado_query($sql, array(':object_id' => $transcript->feature_id));
+      $loc = "";
+      while ($location = $floc_results->fetchObject()) {
+        $loc .= $location->srcfeature_name . ":" . $location->fmin . ".." . $location->fmax;
+      }
+      $entity->{$field_name}['und'][$i]['value'] = array(
+        'type' => $transcript->type,
+        'name' => $transcript->name,
+        'identifier' => $transcript->uniquename,
+        'location' => $loc,
+      );
+      $entity_id = tripal_get_chado_entity_id($field_table, $record->feature_id);
+      if ($entity_id) {
+         $entity->{$field_name}['und'][$i]['value']['entity'] = 'TripalEntity:' . $entity_id;
+       }
+      $i++;
+    }
   }
 
 }

+ 1 - 1
tripal_chado/includes/tripal_chado.custom_tables.inc

@@ -328,7 +328,7 @@ function tripal_custom_tables_form_validate($form, &$form_state) {
         $results = db_query($sql, array(':table_id' => $table_id));
         $ct = $results->fetchObject();
         if ($ct->table_name != $schema_array['table']) {
-          $exists = db_table_exists('chado.' . $schema_array['table']);
+          $exists = chado_table_exists($schema_array['table']);
           if ($exists) {
             form_set_error($form_state['values']['schema'],
               t("The table name already exists, please choose a different name."));

+ 89 - 105
tripal_chado/includes/tripal_chado.field_storage.inc

@@ -44,9 +44,9 @@ function tripal_chado_field_storage_write($entity_type, $entity, $op, $fields) {
   $field_vals = tripal_chado_field_storage_write_merge_fields($fields, $entity_type, $entity);
 
   // First, write the record for the base table.  If we have a record id then
-  // this is an upate and we need to set the primary key.  If not, then this
+  // this is an update and we need to set the primary key.  If not, then this
   // is an insert and we need to set the type_id if the table supports it.
-  $values = $field_vals[$base_table][0];
+  $values = $field_vals[$base_table];
   if ($record_id) {
     $values[$base_pkey] = $record_id;
   }
@@ -109,93 +109,72 @@ function tripal_chado_field_storage_write($entity_type, $entity, $op, $fields) {
  *   The unique record ID.
  */
 function tripal_chado_field_storage_write_table($table_name, $values) {
-   $schema = chado_get_schema($table_name);
-   $fkeys = $schema['foreign keys'];
-   $pkey = $schema['primary key'][0];
-
-
-//    // Before inserting or updating this table, recurse if there are any
-//    // nested FK array values.
-//    foreach ($values as $column => $value) {
-//      // If this value is an array then it must be a FK... let's recurse.
-//      if (is_array($value)) {
-
-//        // Find the name of the FK table for this column.
-//        $fktable_name = '';
-//        foreach ($fkeys as $fktable => $details) {
-//          foreach ($details['columns'] as $fkey_lcolumn => $fkey_rcolumn) {
-//            if ($fkey_lcolumn == $column) {
-//              $fktable_name = $fktable;
-//            }
-//          }
-//        }
-
-//        // Recurse on this recod.
-//        $record_id = tripal_chado_field_storage_write_table($fktable_name, $values[$column]);
-//        $values[$column] = $record_id;
-//      }
-//    }
-
-   // Fields with a cardinality greater than 1 will often submit an
-   // empty form.  We want to remove these empty submissions.  We can detect
-   // them if all of the fields are empty.
-   $num_empty = 0;
-   foreach ($values as $column => $value) {
-     if (!$value) {
-       $num_empty++;
-     }
-   }
-   if ($num_empty == count(array_keys($values))) {
-     return '';
-   }
-   // If the primary key column has a value but all other values are empty then
-   // this is a delete.
-   if (array_key_exists($pkey, $values) and $values[$pkey]) {
-     $num_vals = 0;
-     foreach ($values as $value) {
-       if ($value) {
-         $num_vals++;
-       }
-     }
-     if ($num_vals == 1) {
-       $new_vals[$pkey] = $values[$pkey];
-       if (!chado_delete_record($table_name, $new_vals)) {
-         throw new Exception('Could not delete record from table: "' . $table_name . '".');
-       }
-       return '';
-     }
-   }
+  $schema = chado_get_schema($table_name);
+  $fkeys = $schema['foreign keys'];
+  $pkey = $schema['primary key'][0];
+
+
+  // Fields with a cardinality greater than 1 will often submit an
+  // empty form.  We want to remove these empty submissions.  We can detect
+  // them if all of the fields are empty.
+  $num_empty = 0;
+  foreach ($values as $column => $value) {
+    if (!$value) {
+      $num_empty++;
+    }
+  }
+  if ($num_empty == count(array_keys($values))) {
+    return '';
+  }
 
-   // If the primary key column does not have a value then this is an insert.
-   if (!array_key_exists($pkey, $values) or !$values[$pkey] or !isset($values[$pkey])) {
-     // Before inserting, we want to make sure the record does not
-     // already exist.  Using the unique constraint check for a matching record.
-     $options = array('is_duplicate' => TRUE);
-     $is_duplicate = chado_select_record($table_name, array('*'), $values, $options);
-     if($is_duplicate) {
-       $record = chado_select_record($table_name, array('*'), $values);
-       return $record[0]->$pkey;
-     }
+  // If the primary key column has a value but all other values are empty then
+  // this is a delete.
+  if (array_key_exists($pkey, $values) and $values[$pkey]) {
+    $num_vals = 0;
+    foreach ($values as $value) {
+      if ($value) {
+        $num_vals++;
+      }
+    }
+    if ($num_vals == 1) {
+      $new_vals[$pkey] = $values[$pkey];
+      if (!chado_delete_record($table_name, $new_vals)) {
+        throw new Exception('Could not delete record from table: "' . $table_name . '".');
+      }
+      return '';
+    }
+  }
 
-     // Insert the values array as a new record in the table but remove the
-     // pkey as it should be set.
-     $new_vals = $values;
-     unset($new_vals[$pkey]);
-     $record = chado_insert_record($table_name, $new_vals);
-     if ($record === FALSE) {
-       throw new Exception('Could not insert Chado record into table: "' . $table_name . '".');
-     }
-     return $record[$pkey];
-   }
+  // If the primary key column does not have a value then this is an insert.
+  if (!array_key_exists($pkey, $values) or !$values[$pkey] or !isset($values[$pkey])) {
+    // Before inserting, we want to make sure the record does not
+    // already exist.  Using the unique constraint check for a matching record.
+    $options = array('is_duplicate' => TRUE);
+    $is_duplicate = chado_select_record($table_name, array('*'), $values, $options);
+    if($is_duplicate) {
+      $record = chado_select_record($table_name, array('*'), $values);
+      return $record[0]->$pkey;
+    }
 
-   // If we've made it to this point then this is an update.
-   // TODO: what if the unique constraint matches another record?  That is
-   // not being tested for here.
-   $match[$pkey] = $values[$pkey];
-   if (!chado_update_record($table_name, $match, $values)) {
-     drupal_set_message("Could not update Chado record in table: $table_name.", 'error');
-   }
-   return $values[$pkey];
+    // Insert the values array as a new record in the table but remove the
+    // pkey as it should be set.
+    $new_vals = $values;
+    unset($new_vals[$pkey]);
+    $record = chado_insert_record($table_name, $new_vals);
+    if ($record === FALSE) {
+      throw new Exception('Could not insert Chado record into table: "' . $table_name . '".');
+    }
+    return $record[$pkey];
+  }
+
+  // If we've made it to this point then this is an update.
+  // TODO: what if the unique constraint matches another record?  That is
+  // not being tested for here.
+  $match[$pkey] = $values[$pkey];
+  if (!chado_update_record($table_name, $match, $values)) {
+    drupal_set_message("Could not update Chado record in table: $table_name.", 'error');
+  }
+  return $values[$pkey];
 }
 
 /**
@@ -244,17 +223,6 @@ function tripal_chado_field_storage_load($entity_type, $entities, $age,
     $record = chado_generate_var($base_table, $match);
     $entity->chado_record = $record;
 
-    // For now, expand all 'text' fields.
-    // TODO: we want to be a bit smarter and allow the user to configure this
-    // for now we'll expand.
-    if (isset($schema['fields'])) {
-      foreach ($schema['fields'] as $field_name => $details) {
-        if ($schema['fields'][$field_name]['type'] == 'text') {
-          $record = chado_expand_var($record, 'field', $base_table . '.' . $field_name);
-        }
-      }
-    }
-
     // Iterate through the entity's fields so we can get the column names
     // that need to be selected from each of the tables represented.
     $tables = array();
@@ -331,7 +299,8 @@ function tripal_chado_field_storage_load($entity_type, $entities, $age,
  * Merges the values of all fields into a single array keyed by table name.
  */
 function tripal_chado_field_storage_write_merge_fields($fields, $entity_type, $entity) {
-  $new_fields = array();
+  $all_fields = array();
+  $base_fields = array();
 
   // Iterate through all of the fields and organize them into a
   // new fields array keyed by the table name
@@ -348,12 +317,12 @@ function tripal_chado_field_storage_write_merge_fields($fields, $entity_type, $e
     }
     $chado_table = $field['settings']['chado_table'];
     $chado_column = $field['settings']['chado_column'];
+    $base_table = $field['settings']['base_table'];
 
     // Iterate through the field's items. Fields with cardinality ($delta) > 1
     // are multi-valued.
     $items = field_get_items($entity_type, $entity, $field_name);
     $temp = array();
-
     foreach ($items as $delta => $item) {
 
       // A field may have multiple items. The field can use items
@@ -364,30 +333,45 @@ function tripal_chado_field_storage_write_merge_fields($fields, $entity_type, $e
         if (preg_match('/^chado-(.*?)__(.*?)$/', $item_name, $matches)) {
           $table_name = $matches[1];
           $column_name = $matches[2];
-          $temp[$table_name][$delta][$column_name] = $value;
+          // If this field belongs to the base table then we just add
+          // those values in... there's no delta.
+          if ($table_name == $base_table) {
+            $base_fields[$table_name][$column_name] = $value;
+          }
+          else {
+            $temp[$table_name][$delta][$column_name] = $value;
+          }
         }
       }
       // If there is no value set for the field using the
-      // chado-[table_name]__[field name] naming schema then check if a 'value' item
-      // is present and if so use that.
+      // chado-[table_name]__[field name] naming schema then check if a 'value'
+      // item is present and if so use that for the table column value.
       if ((!array_key_exists($chado_table, $temp) or
            !array_key_exists($delta, $temp[$chado_table]) or
            !array_key_exists($chado_column, $temp[$chado_table][$delta])) and
           array_key_exists('value', $items[$delta]) and
           !is_array($items[$delta]['value'])) {
-        $temp[$chado_table][$delta][$chado_column] = $items[$delta]['value'];
+        // If this field belongs to the base table then we just add
+        // those values in... there's no delta.
+        if ($base_table == $chado_table) {
+          $base_fields[$chado_table][$chado_column] = $items[$delta]['value'];
+        }
+        else {
+          $temp[$chado_table][$delta][$chado_column] = $items[$delta]['value'];
+        }
       }
     }
 
     // Now merge the records for this field with the $new_fields array
     foreach ($temp as $table_name => $details) {
       foreach ($details as $delta => $list) {
-        $new_fields[$table_name][] = $list;
+        $all_fields[$table_name][] = $list;
       }
     }
   }
 
-  return $new_fields;
+  $all_fields = array_merge($base_fields, $all_fields);
+  return $all_fields;
 }
 
 /**

+ 78 - 79
tripal_chado/includes/tripal_chado.fields.inc

@@ -98,19 +98,22 @@ function tripal_chado_bundle_create_fields_base(&$info, $details, $entity_type,
   // Get the list of columns for this table and create a new field for each one.
   $columns = $schema['fields'];
   foreach ($columns as $column_name => $details) {
-    $field_name = $table_name . '__' . $column_name;
-
-    // Skip fields with a custom field:
-    if ($field_name == 'dbxref_id' or $field_name == 'organism_id') {
-      continue;
-    }
-    if ($table_name == 'feature' and ($field_name == 'md5checksum' or
-        $field_name == 'residues' or $field_name == 'seqlen')) {
-      continue;
-    }
-    if ($table_name == 'organism' and ($field_name == 'type_id')) {
-      continue;
-    }
+    $cvterm = tripal_get_chado_semweb_term($table_name, $column_name, array('return_object' => TRUE));
+    $semweb_term = $cvterm->dbxref_id->db_id->name . ':' . $cvterm->dbxref_id->accession;
+    //$field_name = $table_name . '__' . $column_name;
+    $field_name = strtolower($cvterm->dbxref_id->db_id->name . '__' . preg_replace('/ /', '_', $cvterm->name));
+
+//     // Skip fields with a custom field:
+//     if ($field_name == 'dbxref_id' or $field_name == 'organism_id') {
+//       continue;
+//     }
+//     if ($table_name == 'feature' and ($field_name == 'md5checksum' or
+//         $field_name == 'residues' or $field_name == 'seqlen')) {
+//       continue;
+//     }
+//     if ($table_name == 'organism' and ($field_name == 'type_id')) {
+//       continue;
+//     }
 
     // Skip the primary key field.
     if ($column_name == $schema['primary key'][0]) {
@@ -122,6 +125,7 @@ function tripal_chado_bundle_create_fields_base(&$info, $details, $entity_type,
       continue;
     }
 
+
     // Set some defaults for the field.
     $base_info = array(
       'field_name' => $field_name,
@@ -134,7 +138,8 @@ function tripal_chado_bundle_create_fields_base(&$info, $details, $entity_type,
       'settings' => array(
         'chado_table' => $table_name,
         'chado_column' => $column_name,
-        'semantic_web' => tripal_get_chado_semweb_term($table_name, $column_name),
+        'base_table' => $table_name,
+        'semantic_web' => $semweb_term,
       ),
     );
 
@@ -234,6 +239,7 @@ function tripal_chado_bundle_create_fields_custom(&$info, $details, $entity_type
       'settings' => array(
         'chado_table' => $table_name,
         'chado_column' => 'organism_id',
+        'base_table' => $table_name,
       ),
     );
   }
@@ -253,6 +259,7 @@ function tripal_chado_bundle_create_fields_custom(&$info, $details, $entity_type
       'settings' => array(
         'chado_table' => $table_name,
         'chado_column' => 'dbxref_id',
+        'base_table' => $table_name,
         'semantic_web' => tripal_get_chado_semweb_term($table_name, 'dbxref_id'),
       ),
     );
@@ -273,6 +280,7 @@ function tripal_chado_bundle_create_fields_custom(&$info, $details, $entity_type
       'settings' => array(
         'chado_table' => $table_name,
         'chado_column' => 'md5checksum',
+        'base_table' => $table_name,
         'semantic_web' => tripal_get_chado_semweb_term($table_name, 'md5checksum'),
       ),
     );
@@ -293,11 +301,11 @@ function tripal_chado_bundle_create_fields_custom(&$info, $details, $entity_type
       'settings' => array(
         'chado_table' => $table_name,
         'chado_column' => 'residues',
-        'semantic_web' => tripal_get_chado_semweb_term($table_name, 'residues'),
+        'base_table' => $table_name,
       ),
     );
   }
-  
+
   // FEATURE SEQLEN
   if ($table_name == 'feature') {
     $field_name = 'data__sequence_length';
@@ -313,7 +321,7 @@ function tripal_chado_bundle_create_fields_custom(&$info, $details, $entity_type
       'settings' => array(
         'chado_table' => $table_name,
         'chado_column' => 'seqlen',
-        'semantic_web' => tripal_get_chado_semweb_term($table_name, 'seqlen'),
+        'base_table' => $table_name,
       ),
     );
   }
@@ -335,30 +343,28 @@ function tripal_chado_bundle_create_fields_custom(&$info, $details, $entity_type
         'chado_table' => $rel_table,
         'chado_column' => '',
         'base_table' => $table_name,
-        'semantic_web' => 'SO:0000673',
       ),
     );
   }
 
   // ORGANISM TYPE_ID
-  if ($table_name == 'organism' and array_key_exists('type_id', $schema['fields'])) {
-    $field_name = 'taxarank__infraspecific_taxon';
-    $field_type = 'taxarank__infraspecific_taxon';
-    $info[$field_name] = array(
-      'field_name' => $field_name,
-      'type' => $field_type,
-      'cardinality' => 1,
-      'locked' => FALSE,
-      'storage' => array(
-        'type' => 'field_chado_storage',
-      ),
-      'settings' => array(
-        'chado_table' => 'organism',
-        'chado_column' => 'type_id',
-        'semantic_web' => 'TAXRANK:0000046',
-      ),
-    );
-  }
+//   if ($table_name == 'organism' and array_key_exists('type_id', $schema['fields'])) {
+//     $field_name = 'taxarank__infraspecific_taxon';
+//     $field_type = 'taxarank__infraspecific_taxon';
+//     $info[$field_name] = array(
+//       'field_name' => $field_name,
+//       'type' => $field_type,
+//       'cardinality' => 1,
+//       'locked' => FALSE,
+//       'storage' => array(
+//         'type' => 'field_chado_storage',
+//       ),
+//       'settings' => array(
+//         'chado_table' => 'organism',
+//         'chado_column' => 'type_id',
+//       ),
+//     );
+//   }
 }
 
 /**
@@ -392,7 +398,6 @@ function tripal_chado_bundle_create_fields_linker(&$info, $details, $entity_type
         'chado_table' => $contact_table,
         'base_table' => $table_name,
         'chado_column' => 'contact_id',
-        'semantic_web' => tripal_get_chado_semweb_term($table_name, 'contact_id'),
       ),
     );
   }
@@ -435,7 +440,6 @@ function tripal_chado_bundle_create_fields_linker(&$info, $details, $entity_type
         'chado_table' => $dbxref_table,
         'chado_column' => $pkey,
         'base_table' => $table_name,
-        'semantic_web' => 'SBO:0000554',
       ),
     );
   }
@@ -459,7 +463,6 @@ function tripal_chado_bundle_create_fields_linker(&$info, $details, $entity_type
         'chado_table' => $expression_table,
         'chado_column' => $pkey,
         'base_table' => $table_name,
-        'semantic_web' => 'GO:0010467',
       ),
     );
   }
@@ -482,7 +485,6 @@ function tripal_chado_bundle_create_fields_linker(&$info, $details, $entity_type
         'chado_table' => 'featureloc',
         'chado_column' => $pkey,
         'base_table' => 'feature',
-        'semantic_web' => 'data:2012',
       ),
     );
   }
@@ -505,7 +507,6 @@ function tripal_chado_bundle_create_fields_linker(&$info, $details, $entity_type
         'chado_table' => 'featurepos',
         'chado_column' => $pkey,
         'base_table' => 'feature',
-        'semantic_web' => 'OGI:0000021',
       ),
     );
   }
@@ -528,7 +529,6 @@ function tripal_chado_bundle_create_fields_linker(&$info, $details, $entity_type
       'settings' => array(
         'chado_table' => $genotype_table,
         'chado_column' => $pkey,
-        'semantic_web' => 'SO:0001027',
         'base_table' => $table_name,
       ),
     );
@@ -553,7 +553,6 @@ function tripal_chado_bundle_create_fields_linker(&$info, $details, $entity_type
         'chado_table' => $phenotype_table,
         'chado_column' => $pkey,
         'base_table' => $table_name,
-        'semantic_web' => 'SBO:0000358',
       ),
     );
   }
@@ -596,7 +595,6 @@ function tripal_chado_bundle_create_fields_linker(&$info, $details, $entity_type
         'chado_table' => $pub_table,
         'chado_column' => $pkey,
         'base_table' => $table_name,
-        'semantic_web' => 'schema:publication',
       ),
     );
   }
@@ -621,7 +619,6 @@ function tripal_chado_bundle_create_fields_linker(&$info, $details, $entity_type
         'chado_table' => $rel_table,
         'chado_column' => $pkey,
         'base_table' => $table_name,
-        'semantic_web' => 'SBO:0000374',
       ),
     );
   }
@@ -645,7 +642,6 @@ function tripal_chado_bundle_create_fields_linker(&$info, $details, $entity_type
         'chado_table' => $syn_table,
         'chado_column' => $pkey,
         'base_table' => $table_name,
-        'semantic_web' => 'schema:alternateName',
       ),
     );
   }
@@ -721,7 +717,10 @@ function tripal_chado_bundle_create_instances_base(&$info, $entity_type, $bundle
 
   $columns = $schema['fields'];
   foreach ($columns as $column_name => $details) {
-    $field_name = $table_name . '__' . $column_name;
+    $cvterm = tripal_get_chado_semweb_term($table_name, $column_name, array('return_object' => TRUE));
+    $semweb_term = $cvterm->dbxref_id->db_id->name . ':' . $cvterm->dbxref_id->accession;
+    //$field_name = $table_name . '__' . $column_name;
+    $field_name = strtolower($cvterm->dbxref_id->db_id->name . '__' . preg_replace('/ /', '_', $cvterm->name));
 
     // Skip the primary key field.
     if ($column_name == $schema['primary key'][0]) {
@@ -991,7 +990,7 @@ function tripal_chado_bundle_create_instances_custom(&$info, $entity_type, $bund
       'field_name' => $field_name,
       'entity_type' => $entity_type,
       'bundle' => $bundle->name,
-      'label' => 'Sequences',
+      'label' => 'Sequence',
       'description' => 'All available sequences for this record.',
       'required' => FALSE,
       'settings' => array(
@@ -1053,8 +1052,8 @@ function tripal_chado_bundle_create_instances_custom(&$info, $entity_type, $bund
       'field_name' => $field_name,
       'entity_type' => $entity_type,
       'bundle' => $bundle->name,
-      'label' => 'Transcript',
-      'description' => 'These transcripts are associated with this gene.',
+      'label' => 'Transcripts',
+      'description' => 'Transcripts that are part of this gene.',
       'required' => FALSE,
       'settings' => array(
         'auto_attach' => FALSE,
@@ -1076,33 +1075,33 @@ function tripal_chado_bundle_create_instances_custom(&$info, $entity_type, $bund
   }
 
   // ORGANISM TYPE_ID
-  if ($table_name == 'organism' and array_key_exists('type_id', $schema['fields'])) {
-    $field_name = 'taxarank__infraspecific_taxon';
-    $info[$field_name] = array(
-      'field_name' => $field_name,
-      'entity_type' => $entity_type,
-      'bundle' => $bundle->name,
-      'label' => 'Infraspecific Taxon',
-      'description' => 'The Infraspecific Taxon.',
-      'required' => FALSE,
-      'settings' => array(
-        'auto_attach' => TRUE,
-      ),
-      'widget' => array(
-        'type' => 'taxarank__infraspecific_taxon_widget',
-        'settings' => array(
-          'display_label' => 1,
-        ),
-      ),
-      'display' => array(
-        'default' => array(
-          'label' => 'inline',
-          'type' => 'taxarank__infraspecific_taxon_formatter',
-          'settings' => array(),
-        ),
-      ),
-    );
-  }
+//   if ($table_name == 'organism' and array_key_exists('type_id', $schema['fields'])) {
+//     $field_name = 'taxarank__infraspecific_taxon';
+//     $info[$field_name] = array(
+//       'field_name' => $field_name,
+//       'entity_type' => $entity_type,
+//       'bundle' => $bundle->name,
+//       'label' => 'Infraspecific Taxon',
+//       'description' => 'The Infraspecific Taxon.',
+//       'required' => FALSE,
+//       'settings' => array(
+//         'auto_attach' => TRUE,
+//       ),
+//       'widget' => array(
+//         'type' => 'taxarank__infraspecific_taxon_widget',
+//         'settings' => array(
+//           'display_label' => 1,
+//         ),
+//       ),
+//       'display' => array(
+//         'default' => array(
+//           'label' => 'inline',
+//           'type' => 'taxarank__infraspecific_taxon_formatter',
+//           'settings' => array(),
+//         ),
+//       ),
+//     );
+//   }
 }
 
 /**
@@ -1131,7 +1130,7 @@ function tripal_chado_bundle_create_instances_linker(&$info, $entity_type, $bund
       'description' => 'Associates an indviddual or organization with this record',
       'required' => FALSE,
       'settings' => array(
-        'auto_attach' => TRUE,
+        'auto_attach' => FALSE,
       ),
       'widget' => array(
         'type' => 'local__contact_widget',
@@ -1148,7 +1147,7 @@ function tripal_chado_bundle_create_instances_linker(&$info, $entity_type, $bund
       ),
     );
   }
-  
+
   // CVTERM
   $cvterm_table = $table_name . '_cvterm';
   if (chado_table_exists($cvterm_table)) {

+ 20 - 20
tripal_chado/includes/tripal_chado.mapping.inc

@@ -37,44 +37,44 @@ function tripal_chado_map_cvterms() {
         }
       }
     }
-    
+
     // Now we also want to map tripal terms for existing bundles
-    $sql = 
-      "SELECT 
+    $sql =
+      "SELECT
          (SELECT vocabulary FROM tripal_vocab TV WHERE id = TM.vocab_id),
-          accession, 
-          name 
+          accession,
+          name
        FROM tripal_term TM";
     $results = db_query($sql);
     while ($tripal_term = $results->fetchObject()) {
       $voc = $tripal_term->vocabulary;
       $accession = $tripal_term->accession;
       $name = $tripal_term->name;
-      $dbxref_sql = 
-        "SELECT dbxref_id 
-          FROM {dbxref} 
-          WHERE 
-            accession = :accession 
-          AND 
+      $dbxref_sql =
+        "SELECT dbxref_id
+          FROM {dbxref}
+          WHERE
+            accession = :accession
+          AND
             db_id = (SELECT db_id FROM {db} WHERE name = :voc)";
       $dbxref_id = chado_query($dbxref_sql, array(':accession' => $accession, ':voc' => $voc))->fetchField();
       if ($dbxref_id) {
-        $cvterm_sql = 
-          "SELECT cvterm_id 
-            FROM {cvterm} 
-            WHERE 
-              dbxref_id = :dbxref_id 
+        $cvterm_sql =
+          "SELECT cvterm_id
+            FROM {cvterm}
+            WHERE
+              dbxref_id = :dbxref_id
             AND name = :name";
         $cvterm_id = chado_query($cvterm_sql, array(':dbxref_id' => $dbxref_id, ':name' => $name))->fetchField();
         if ($cvterm_id) {
          // Check if this term is already mapped in the tripal_cvterm_mapping table
-         $check_sql = 
-           "SELECT mapping_id 
-             FROM tripal_cvterm_mapping 
+         $check_sql =
+           "SELECT mapping_id
+             FROM tripal_cvterm_mapping
              WHERE cvterm_id = :cvterm_id";
          $mapped = db_query($check_sql, array(':cvterm_id' => $cvterm_id))->fetchField();
          // If mapping does not exist and a table name matches the term name, add it
-         if (!$mapped && db_table_exists('chado.' . $name)) {
+         if (!$mapped && chado_table_exists($name)) {
            print "Adding mapped tripal term: $name\n";
            tripal_chado_add_cvterm_mapping($cvterm_id, $name, NULL);
          }

+ 5 - 4
tripal_chado/includes/tripal_chado.migrate.inc

@@ -472,10 +472,11 @@ function tripal_chado_migrate_form_step2_ajax_callback(&$form, &$form_state) {
  */
 function tripal_chado_get_tripal_v2_content_type_options($all_option = FALSE, $has_template = FALSE) {
   // Get all available Tripal v2 chado tables
-  $sql =
-  "SELECT table_name
-      FROM information_schema.tables
-      WHERE table_schema = 'public' AND table_name LIKE 'chado_%'";
+  $sql = "
+    SELECT table_name
+    FROM information_schema.tables
+    WHERE table_schema = 'public' AND table_name LIKE 'chado_%'
+  ";
   $result = db_query($sql);
   // Store 'chado_*' tables that has at least one node
   $tables = array();