Procházet zdrojové kódy

Working on targeted loading of fields

Stephen Ficklin před 8 roky
rodič
revize
eb4d5f91fe
33 změnil soubory, kde provedl 601 přidání a 162 odebrání
  1. 0 0
      legacy/tripal_core/theme/css/tripal_core.css
  2. 0 0
      legacy/tripal_core/theme/js/tripal_core.js
  3. 2 2
      legacy/tripal_core/tripal_core.info
  4. 49 0
      tripal/api/tripal.entities.api.inc
  5. 234 0
      tripal/includes/TripalEntityController.inc
  6. 5 1
      tripal/includes/TripalField.inc
  7. 53 0
      tripal/includes/tripal.entity.inc
  8. binární
      tripal/theme/images/ajax-loader.gif
  9. 23 0
      tripal/theme/js/tripal.js
  10. 20 5
      tripal/tripal.module
  11. 3 1
      tripal_chado/includes/fields/chado_base__dbxref_id.inc
  12. 15 12
      tripal_chado/includes/fields/chado_base__organism_id.inc
  13. 3 2
      tripal_chado/includes/fields/chado_feature__md5checksum.inc
  14. 4 2
      tripal_chado/includes/fields/chado_feature__residues.inc
  15. 3 1
      tripal_chado/includes/fields/chado_feature__seqlen.inc
  16. 9 5
      tripal_chado/includes/fields/chado_gene__transcripts.inc
  17. 11 7
      tripal_chado/includes/fields/chado_linker__contact.inc
  18. 6 4
      tripal_chado/includes/fields/chado_linker__cvterm.inc
  19. 3 1
      tripal_chado/includes/fields/chado_linker__cvterm_adder.inc
  20. 3 1
      tripal_chado/includes/fields/chado_linker__dbxref.inc
  21. 9 5
      tripal_chado/includes/fields/chado_linker__expression.inc
  22. 10 6
      tripal_chado/includes/fields/chado_linker__featureloc.inc
  23. 46 41
      tripal_chado/includes/fields/chado_linker__genotype.inc
  24. 45 41
      tripal_chado/includes/fields/chado_linker__phenotype.inc
  25. 7 4
      tripal_chado/includes/fields/chado_linker__prop.inc
  26. 3 1
      tripal_chado/includes/fields/chado_linker__prop_adder.inc
  27. 10 5
      tripal_chado/includes/fields/chado_linker__pub.inc
  28. 9 5
      tripal_chado/includes/fields/chado_linker__relationship.inc
  29. 5 2
      tripal_chado/includes/fields/chado_linker__synonym.inc
  30. 3 1
      tripal_chado/includes/fields/chado_organism__type_id.inc
  31. 3 1
      tripal_chado/includes/tripal_chado.fields.inc
  32. 5 5
      tripal_chado/includes/tripal_chado.semweb.inc
  33. 0 1
      tripal_ws/includes/tripal_ws.rest.inc

+ 0 - 0
legacy/tripal_core/theme/css/tripal.css → legacy/tripal_core/theme/css/tripal_core.css


+ 0 - 0
legacy/tripal_core/theme/js/tripal.js → legacy/tripal_core/theme/js/tripal_core.js


+ 2 - 2
legacy/tripal_core/tripal_core.info

@@ -6,8 +6,8 @@ package = Tripal v2 Legacy
 version = 7.x-3.0-alpha1
 configure = admin/tripal
 
-stylesheets[all][] = theme/css/tripal.css
-scripts[]          = theme/js/tripal.js
+stylesheets[all][] = theme/css/tripal_core.css
+scripts[]          = theme/js/tripal_core.js
 
 dependencies[] = views
 dependencies[] = path

+ 49 - 0
tripal/api/tripal.entities.api.inc

@@ -1,4 +1,53 @@
 <?php
+
+
+/**
+ * A replacement for the entity_load function of Drupal.
+ *
+ * This function should be used for loading of Tripal Entities. It provides
+ * greater control to limit which fields are loaded with the entity. The
+ * entity_load() function of Drupal will automatically attach all fields at
+ * once but this may not be desired as some fields can be comples and large and
+ * the site developer may desire loading of fields via AJAX or the user of
+ * web services may wish to specify the fields they want to include.
+ *
+ * @param $entity_type:
+ *   The entity type to load, e.g. node or user.
+ * @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.
+ * @param $field_ids
+ *   A list of numeric feild IDs that should be loaded.  The
+ *   TripalField named 'content_type' is always automatically added.
+ *
+ * @return
+ *   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,
+    $field_ids = array()) {
+
+  // The $conditions is deprecated in the funtion arguments of entity_load
+  // so it was removed from the parameters of this function as well. But
+  // the load() function of the entity controller still expects it so set it
+  // to an empty array.
+  $conditions = array();
+
+  // If this isn't a TripalEntity then just load it the old fashioned way
+  // although caching will not be used if it not specifically set to FALSE.
+  if ($entity_type != 'TripalEntity') {
+    return entity_load($entity_type, $ids, $conditions, $reset);
+  }
+
+  // Get the entity controller and clear the cache if requested (default).
+  $ec = entity_get_controller($entity_type);
+  if ($reset) {
+    $ec->resetCache();
+  }
+
+  return $ec->load($ids, $conditions, $field_ids);
+}
 /**
  * Retrieves a TripalTerm entity that matches the given arguments.
  *

+ 234 - 0
tripal/includes/TripalEntityController.inc

@@ -331,5 +331,239 @@ class TripalEntityController extends EntityAPIController {
       return FALSE;
     }
   }
+
+  /**
+   * Override the load function.
+   *
+   * A TripalEntity may have a large number of fields attached which may
+   * slow down the loading of pages and web services.  Therefore, we only
+   * want to attach fields that are needed.
+   *
+   * @param $ids
+   *  The list of entity IDs to load.
+   * @param $conditions
+   *  The list of key/value filters for querying the entity.
+   * @param $field_ids
+   *  The list of numeric field IDs for fields that should be included.
+   */
+  public function load($ids = array(), $conditions = array(), $field_ids = array()) {
+
+    $entities = array();
+
+    // Revisions are not statically cached, and require a different query to
+    // other conditions, so separate the revision id into its own variable.
+    if ($this->revisionKey && isset($conditions[$this->revisionKey])) {
+      $revision_id = $conditions[$this->revisionKey];
+      unset($conditions[$this->revisionKey]);
+    }
+    else {
+      $revision_id = FALSE;
+    }
+
+    // Create a new variable which is either a prepared version of the $ids
+    // array for later comparison with the entity cache, or FALSE if no $ids
+    // were passed. The $ids array is reduced as items are loaded from cache,
+    // and we need to know if it's empty for this reason to avoid querying the
+    // database when all requested entities are loaded from cache.
+    $passed_ids = !empty($ids) ? array_flip($ids) : FALSE;
+
+    // Try to load entities from the static cache.
+    if ($this->cache && !$revision_id) {
+      $entities = $this->cacheGet($ids, $conditions);
+      // If any entities were loaded, remove them from the ids still to load.
+      if ($passed_ids) {
+        $ids = array_keys(array_diff_key($passed_ids, $entities));
+      }
+    }
+
+    // Support the entitycache module if activated.
+    if (!empty($this->entityInfo['entity cache']) && !$revision_id && $ids && !$conditions) {
+      $cached_entities = EntityCacheControllerHelper::entityCacheGet($this, $ids, $conditions);
+      // If any entities were loaded, remove them from the ids still to load.
+      $ids = array_diff($ids, array_keys($cached_entities));
+      $entities += $cached_entities;
+
+      // Add loaded entities to the static cache if we are not loading a
+      // revision.
+      if ($this->cache && !empty($cached_entities) && !$revision_id) {
+        $this->cacheSet($cached_entities);
+      }
+    }
+
+    // Load any remaining entities from the database. This is the case if $ids
+    // is set to FALSE (so we load all entities), if there are any ids left to
+    // load or if loading a revision.
+    if (!($this->cacheComplete && $ids === FALSE && !$conditions) && ($ids === FALSE || $ids || $revision_id)) {
+      $queried_entities = array();
+      foreach ($this->query($ids, $conditions, $revision_id) as $record) {
+        // Skip entities already retrieved from cache.
+        if (isset($entities[$record->{$this->idKey}])) {
+          continue;
+        }
+
+        // For DB-based entities take care of serialized columns.
+        if (!empty($this->entityInfo['base table'])) {
+          $schema = drupal_get_schema($this->entityInfo['base table']);
+
+          foreach ($schema['fields'] as $field => $info) {
+            if (!empty($info['serialize']) && isset($record->$field)) {
+              $record->$field = unserialize($record->$field);
+              // Support automatic merging of 'data' fields into the entity.
+              if (!empty($info['merge']) && is_array($record->$field)) {
+                foreach ($record->$field as $key => $value) {
+                  $record->$key = $value;
+                }
+                unset($record->$field);
+              }
+            }
+          }
+        }
+
+        $queried_entities[$record->{$this->idKey}] = $record;
+      }
+    }
+
+    // Pass all entities loaded from the database through $this->attachLoad(),
+    // which attaches fields (if supported by the entity type) and calls the
+    // entity type specific load callback, for example hook_node_load().
+    if (!empty($queried_entities)) {
+      $this->attachLoad($queried_entities, $revision_id, $field_ids);
+      $entities += $queried_entities;
+    }
+
+    // Entitycache module support: Add entities to the entity cache if we are
+    // not loading a revision.
+    if (!empty($this->entityInfo['entity cache']) && !empty($queried_entities) && !$revision_id) {
+      EntityCacheControllerHelper::entityCacheSet($this, $queried_entities);
+    }
+
+    if ($this->cache) {
+      // Add entities to the cache if we are not loading a revision.
+      if (!empty($queried_entities) && !$revision_id) {
+        $this->cacheSet($queried_entities);
+
+        // Remember if we have cached all entities now.
+        if (!$conditions && $ids === FALSE) {
+          $this->cacheComplete = TRUE;
+        }
+      }
+    }
+    // Ensure that the returned array is ordered the same as the original
+    // $ids array if this was passed in and remove any invalid ids.
+    if ($passed_ids && $passed_ids = array_intersect_key($passed_ids, $entities)) {
+      foreach ($passed_ids as $id => $value) {
+        $passed_ids[$id] = $entities[$id];
+      }
+      $entities = $passed_ids;
+    }
+    return $entities;
+  }
+
+  /**
+   * Override the attachLoad function.
+   *
+   * A TripalEntity may have a large number of fields attached which may
+   * slow down the loading of pages and web services.  Therefore, we only
+   * want to attach fields that are needed.
+   *
+   *
+   *
+   * @param $queried_entities
+   *   The list of queried
+   * @param $revision_id
+   * @param $field_ids
+   */
+  protected function attachLoad(&$queried_entities, $revision_id = FALSE,
+      $field_ids = array()) {
+
+    // Get the list of fields for later user.
+    $fields = field_info_fields();
+    // A temporary holding place for field instances (so we don't have
+    // to keep looking them up in our loop below).
+    $instances = array();
+
+    // Add in the content_type field by default. It should always be
+    // attached.
+    $ids = array();
+    $ct = field_info_field('content_type');
+    $ids[] = $ct['id'];
+    $field_ids += $ids;
+
+
+    // Attach fields.
+    if ($this->entityInfo['fieldable']) {
+      if ($revision_id) {
+        $function = 'field_attach_load_revision';
+      }
+      else {
+        $function = 'field_attach_load';
+      }
+      foreach ($queried_entities as $entity) {
+        $entity_ids = array();
+        $entity_ids += $field_ids;
+        // Iterate through the fields and find those that are set to
+        // 'auto_attach' and which are attached to this bundle.
+        foreach ($fields as $field) {
+          $field_name =  $field['field_name'];
+          if (array_key_exists('TripalEntity', $field['bundles'])) {
+            foreach ($field['bundles']['TripalEntity'] as $bundle_name) {
+              if ($bundle_name == $entity->bundle) {
+                // Get the instance of this field for this bundle.
+                if (!array_key_exists($field_name . '-' . $bundle_name, $instances)) {
+                  $instance = field_info_instance('TripalEntity', $field['field_name'], $bundle_name);
+                  $instances[$field_name . '-' . $bundle_name] = $instance;
+                }
+                else {
+                  $instance = $instances[$field_name . '-' . $bundle_name];
+                }
+                // If the 'auto_attach' is set then add this field id to our
+                // list.
+                if (array_key_exists('settings', $instance) and
+                    array_key_exists('auto_attach', $instance['settings']) and
+                    $instance['settings']['auto_attach'] === TRUE) {
+                  $entity_ids[] = $field['id'];
+                }
+                // If the field is not auto attached then we want to add an
+                // empty default valuea nd add an 'unattached' key to
+                // clue in other things that there may be data, it's just
+                // not attached.
+                else {
+                  $value = array(
+                    'und' => array(
+                      0 => array(
+                        'value' => '',
+                        '#unattached' => TRUE,
+                      ),
+                    ),
+                  );
+                  $entity->$field_name = $value;
+                }
+              }
+            }
+          }
+        }
+
+        // Iterate through each field that should be added and attach it.
+        foreach ($entity_ids as $field_id) {
+          $options = array();
+          $options['field_id'] = $field_id;
+          $function($this->entityType, array($entity->id => $entity), FIELD_LOAD_CURRENT, $options);
+        }
+      }
+    }
+
+    // Call hook_entity_load().
+    foreach (module_implements('entity_load') as $module) {
+      $function = $module . '_entity_load';
+      $function($queried_entities, $this->entityType);
+    }
+    // Call hook_TYPE_load(). The first argument for hook_TYPE_load() are
+    // always the queried entities, followed by additional arguments set in
+    // $this->hookLoadArguments.
+    $args = array_merge(array($queried_entities), $this->hookLoadArguments);
+    foreach (module_implements($this->entityInfo['load hook']) as $module) {
+      call_user_func_array($module . '_' . $this->entityInfo['load hook'], $args);
+    }
+  }
 }
 

+ 5 - 1
tripal/includes/TripalField.inc

@@ -174,7 +174,11 @@ class TripalField {
    *      - label: 'above'
    *      - type: the default formatter specified in field_info().
    *      - settings: each omitted setting is given the default value specified
-   *        in formatter_info().
+   *        in formatter_info().  A setting specific to TripalFields is the
+   *        'auto_attach'. If this settings is set to TRUE then the field
+   *        will be automatically attached to the entity. IF FALSE then it
+   *        will not be and can be attached with a separate field_attach_load()
+   *        call.  If not specified the default is FALSE.
    *      View modes not present in the definition are left empty, and the
    *      field will not be displayed in this mode.
    *

+ 53 - 0
tripal/includes/tripal.entity.inc

@@ -48,6 +48,9 @@ function tripal_entity_info() {
     // FALSE disables caching. Caching functionality is handled by Drupal core.
     'static cache' => FALSE,
 
+    // Disable caching of fields
+    'field cache' => FALSE,
+
     // This entity doesn't support bundles.
     'bundles' => array (),
 
@@ -263,4 +266,54 @@ function tripal_entity_access($entity) {
 
 function tripal_form_tripal_entity_form_alter(&$form, &$form_state, $form_id) {
   //dpm($form);
+}
+
+/**
+ * Implements hook_entity_view.
+ *
+ * Here we want to overwite unattached fields with a div box that will be
+ * recognized by JavaScript that will the use AJAX to load the field.
+ *
+ * The tripal_ajax_attach_field() function is called by an AJAX call to
+ * retrieve the field.
+ */
+function tripal_entity_view($entity, $type, $view_mode, $langcode) {
+  if ($type == 'TripalEntity') {
+    foreach (element_children($entity->content) as $child_name) {
+      $child = $entity->content[$child_name];
+      if (array_key_exists('#items', $child) and
+          array_key_exists('0', $child['#items']) and
+          array_key_exists('#unattached', $child['#items'][0])
+          and $child['#items'][0]['#unattached'] === TRUE) {
+        $entity->content[$child_name]['#prefix'] = '<div id="tripal-entity-' . $entity->id . '--' . $child_name . '" class="tripal-entity-unattached">';
+        $entity->content[$child_name]['#suffix'] = '</div>';
+      }
+    }
+  }
+}
+
+/**
+ * Responds to an AJAX call for populating a field.
+ *
+ * @param $id
+ *   The ID of the HTML div box where the field is housed. The ID contains the
+ *   entity ID and field name.
+ */
+function tripal_ajax_attach_field($id) {
+
+  $matches = array();
+  if (preg_match('/^tripal-entity-(\d+)--(.+)$/', $id, $matches)) {
+    $entity_id = $matches[1];
+    $field_name = $matches[2];
+    $field = field_info_fields($field_name);
+    $result = tripal_load_entity('TripalEntity', array($entity_id), FALSE, array($field['id']));
+    reset($result);
+    $entity = $result[$entity_id];
+
+    $content = drupal_render(field_view_field('TripalEntity', $entity, $field_name));
+    return drupal_json_output(array(
+      'id' => $id,
+      'content' => $content
+    ));
+  }
 }

binární
tripal/theme/images/ajax-loader.gif


+ 23 - 0
tripal/theme/js/tripal.js

@@ -0,0 +1,23 @@
+// Using the closure to map jQuery to $. 
+(function ($) {
+  // Store our function as a property of Drupal.behaviors.
+  Drupal.behaviors.myModuleSecureLink = {
+    attach: function (context, settings) {
+
+      $(".tripal-entity-unattached .field-items").replaceWith('Loading... <img src="/' + tripal_path + '/theme/images/ajax-loader.gif">');
+      $(".tripal-entity-unattached").each(function() {
+        id = $(this).attr('id');
+        $.ajax({
+          url: baseurl + '/bio_data/ajax/field_attach/' + id,
+          dataType: 'json',
+          type: 'GET',
+          success: function(data){
+            var content = data['content'];
+            var id = data['id'];
+            $("#" + id).replaceWith(content);
+          }
+        });
+      });
+    }
+  }
+})(jQuery);

+ 20 - 5
tripal/tripal.module

@@ -56,9 +56,11 @@ function tripal_init() {
 
   // add some variables for all javasript to use for building URLs
   $clean_urls = variable_get('clean_url', 0);
-  drupal_add_js(
-    "var baseurl  = '$base_url';" .
-    "var isClean  =  $clean_urls;",
+  $tripal_path = drupal_get_path('module', 'tripal');
+  drupal_add_js("
+    var baseurl  = '$base_url';
+    var isClean  =  $clean_urls;
+    var tripal_path = '$tripal_path';",
     'inline', 'header');
 
   // make sure the date time settings are the way Tripal will insert them
@@ -228,6 +230,18 @@ function tripal_menu() {
     'type' => MENU_CALLBACK,
   );
 
+  /*
+   * AJAX Callbacks.
+   */
+  $items['bio_data/ajax/field_attach/%'] = array(
+    'page callback' => 'tripal_ajax_attach_field',
+    'page arguments' => array(3),
+    'access arguments' => array('access content'),
+    'type' => MENU_CALLBACK,
+    'file' => 'includes/tripal.entity.inc',
+    'file path' => drupal_get_path('module', 'tripal'),
+  );
+
 
 
   return $items;
@@ -482,8 +496,9 @@ function TripalBundle_load($bundle_type, $reset = FALSE) {
  *
  * @see tripal_entity_load_multiple()
  */
-function TripalEntity_load($id, $reset = FALSE) {
-  $entity = entity_load('TripalEntity', array($id), array(), $reset);
+function TripalEntity_load($id, $reset = TRUE) {
+  // $entity = entity_load('TripalEntity', array($id), array(), $reset);
+  $entity = tripal_load_entity('TripalEntity', array($id), $reset);
   return reset($entity);
 }
 

+ 3 - 1
tripal_chado/includes/fields/chado_base__dbxref_id.inc

@@ -90,7 +90,9 @@ class chado_base__dbxref_id extends TripalField {
       'description' => 'This field specifies the unique stable accession (ID) for
         this record. It requires that this site have a database entry.',
       'required' => FALSE,
-      'settings' => array(),
+      'settings' => array(
+        'auto_attach' => TRUE,
+      ),
       'widget' => array(
         'type' => 'chado_base__dbxref_id_widget',
         'settings' => array(

+ 15 - 12
tripal_chado/includes/fields/chado_base__organism_id.inc

@@ -108,7 +108,9 @@ class chado_base__organism_id extends TripalField {
       'label' => 'Organism',
       'description' => 'Select an organism.',
       'required' => $is_required,
-      'settings' => array(),
+      'settings' => array(
+        'auto_attach' => TRUE,
+      ),
       'widget' => array(
         'type' => 'chado_base__organism_id_widget',
         'settings' => array(
@@ -152,17 +154,19 @@ class chado_base__organism_id extends TripalField {
   public function formatter_view(&$element, $entity_type, $entity,
       $field, $instance, $langcode, $items, $display) {
 
-    $content =  $items[0]['value'];
-    if (array_key_exists('entity_id', $items[0])) {
-      $content = l(strip_tags($items[0]['value']), 'bio_data/' . $items[0]['entity_id']);
-    }
+    if (count($items) > 0) {
+      $content =  $items[0]['value'];
+      if (array_key_exists('entity_id', $items[0])) {
+        $content = l(strip_tags($items[0]['value']), 'bio_data/' . $items[0]['entity_id']);
+      }
 
-    // The cardinality of this field is 1 so we don't have to
-    // iterate through the items array, as there will never be more than 1.
-    $element[0] = array(
-      '#type' => 'markup',
-      '#markup' => $content,
-    );
+      // The cardinality of this field is 1 so we don't have to
+      // iterate through the items array, as there will never be more than 1.
+      $element[0] = array(
+        '#type' => 'markup',
+        '#markup' => $content,
+      );
+    }
   }
 
   /**
@@ -216,7 +220,6 @@ class chado_base__organism_id extends TripalField {
     // Set some defaults for the empty record.
     $entity->{$field_name}['und'][0] = array(
       'value' => '',
-      'organism__organism_id' => '',
     );
 
     if ($record) {

+ 3 - 2
tripal_chado/includes/fields/chado_feature__md5checksum.inc

@@ -11,7 +11,6 @@ class chado_feature__md5checksum  extends TripalField {
       'description' => t('A field for generating MD5 checksum for a sequence.'),
       'default_widget' => 'chado_feature__md5checksum_widget',
       'default_formatter' => 'chado_feature__md5checksum_formatter',
-      'settings' => array(),
       'storage' => array(
         'type' => 'field_chado_storage',
         'module' => 'tripal_chado',
@@ -89,7 +88,9 @@ class chado_feature__md5checksum  extends TripalField {
         to calculate the value. If the value calculated is identical the one shown
         here, then the downloaded sequence is uncorrupted.',
       'required' => FALSE,
-      'settings' => array(),
+      'settings' => array(
+        'auto_attach' => FALSE,
+      ),
       'widget' => array(
         'type' => 'chado_feature__md5checksum_widget',
         'settings' => array(

+ 4 - 2
tripal_chado/includes/fields/chado_feature__residues.inc

@@ -85,7 +85,9 @@ class chado_feature__residues extends TripalField {
       'label' => 'Sequences',
       'description' => 'All available sequences for this record.',
       'required' => FALSE,
-      'settings' => array(),
+      'settings' => array(
+        'auto_attach' => FALSE,
+      ),
       'widget' => array(
         'type' => 'chado_feature__residues_widget',
         'settings' => array(
@@ -131,7 +133,7 @@ class chado_feature__residues extends TripalField {
 
     foreach ($items as $delta => $item) {
       // If there are no residues then skip this one.
-      if (!array_key_exists('residues', $item['value'])) {
+      if (!is_array($item['value']) or !array_key_exists('residues', $item['value'])) {
         continue;
       }
 

+ 3 - 1
tripal_chado/includes/fields/chado_feature__seqlen.inc

@@ -85,7 +85,9 @@ class chado_feature__seqlen extends TripalField {
         sequences derived from alignments. If this value is zero but aligned sequences
         are present then this record has no official assigned sequence.',
       'required' => FALSE,
-      'settings' => array(),
+      'settings' => array(
+        'auto_attach' => FALSE,
+      ),
       'widget' => array(
         'type' => 'chado_feature__seqlen_widget',
         'settings' => array(

+ 9 - 5
tripal_chado/includes/fields/chado_gene__transcripts.inc

@@ -90,7 +90,9 @@ class chado_gene__transcripts extends TripalField {
       'label' => 'Transcripts',
       'description' => 'These transcripts are associated with this gene.',
       'required' => FALSE,
-      'settings' => array(),
+      'settings' => array(
+        'auto_attach' => FALSE,
+      ),
       'widget' => array(
         'type' => 'chado_gene__transcripts_widget',
         'settings' => array(
@@ -193,10 +195,12 @@ class chado_gene__transcripts extends TripalField {
 
     // once we have our table array structure defined, we call Drupal's theme_table()
     // function to generate the table.
-    $element[$delta] = array(
-      '#type' => 'markup',
-      '#markup' => $content,
-    );
+    if (count($items) > 0) {
+      $element[0] = array(
+        '#type' => 'markup',
+        '#markup' => $content,
+      );
+    }
   }
 
   /**

+ 11 - 7
tripal_chado/includes/fields/chado_linker__contact.inc

@@ -95,7 +95,9 @@ class chado_linker__contact extends TripalField {
         some responsibility for the creation, delivery or maintenance of
         the associated data.',
       'required' => FALSE,
-      'settings' => array(),
+      'settings' => array(
+        'auto_attach' => FALSE,
+      ),
       'widget' => array(
         'type' => 'chado_linker__contact_widget',
         'settings' => array(
@@ -178,12 +180,14 @@ class chado_linker__contact extends TripalField {
     );
     $content = theme_table($table);
 
-    // once we have our table array structure defined, we call Drupal's theme_table()
-    // function to generate the table.
-    $element[$delta] = array(
-      '#type' => 'markup',
-      '#markup' => $content,
-    );
+    if (count($items) > 0) {
+      // once we have our table array structure defined, we call Drupal's theme_table()
+      // function to generate the table.
+      $element[0] = array(
+        '#type' => 'markup',
+        '#markup' => $content,
+      );
+    }
   }
 
 

+ 6 - 4
tripal_chado/includes/fields/chado_linker__cvterm.inc

@@ -122,10 +122,12 @@ class chado_linker__cvterm extends TripalField {
       'empty' => 'There are no annotations of this type',
     );
 
-    $element[0] = array(
-      '#type' => 'markup',
-      '#markup' => theme_table($table),
-    );
+    if (count($items) > 0) {
+      $element[0] = array(
+        '#type' => 'markup',
+        '#markup' => theme_table($table),
+      );
+    }
   }
   /**
    * @see TripalField::widget_form()

+ 3 - 1
tripal_chado/includes/fields/chado_linker__cvterm_adder.inc

@@ -85,7 +85,9 @@ class chado_linker__cvterm_addr extends TripalField {
       'label' => 'Add Annotation Types',
       'description' => 'Add additional annotations types to this record.',
       'required' => FALSE,
-      'settings' => array(),
+      'settings' => array(
+        'auto_attach' => FALSE,
+      ),
       'widget' => array(
         'type' => 'chado_linker__cvterm_adder_widget',
         'settings' => array(

+ 3 - 1
tripal_chado/includes/fields/chado_linker__dbxref.inc

@@ -104,7 +104,9 @@ class chado_linker__dbxref extends TripalField {
       'label' => 'Cross References',
       'description' => 'The IDs where this record may be available in other external online databases.',
       'required' => FALSE,
-      'settings' => array(),
+      'settings' => array(
+        'auto_attach' => FALSE,
+      ),
       'widget' => array(
         'type' => 'chado_linker__dbxref_widget',
         'settings' => array(

+ 9 - 5
tripal_chado/includes/fields/chado_linker__expression.inc

@@ -91,7 +91,9 @@ class chado_linker__expression extends TripalField {
       'label' => 'Expression',
       'description' => 'Information about the expression of this record.',
       'required' => FALSE,
-      'settings' => array(),
+      'settings' => array(
+        'auto_attach' => FALSE,
+      ),
       'widget' => array(
         'type' => 'chado_linker__expression_widget',
         'settings' => array(
@@ -198,10 +200,12 @@ class chado_linker__expression extends TripalField {
 
     // once we have our table array structure defined, we call Drupal's theme_table()
     // function to generate the table.
-    $element[$delta] = array(
-      '#type' => 'markup',
-      '#markup' => $content,
-    );
+    if (count($items) > 0) {
+      $element[0] = array(
+        '#type' => 'markup',
+        '#markup' => $content,
+      );
+    }
   }
 
   /**

+ 10 - 6
tripal_chado/includes/fields/chado_linker__featureloc.inc

@@ -89,7 +89,9 @@ class chado_linker__featureloc extends TripalField {
       'description' => 'The locations on other genomic sequences where this
         record has been aligned.',
       'required' => FALSE,
-      'settings' => array(),
+      'settings' => array(
+        'auto_attach' => FALSE,
+      ),
       'widget' => array(
         'type' => 'chado_linker__featureloc_widget',
         'settings' => array(
@@ -211,15 +213,17 @@ class chado_linker__featureloc extends TripalField {
       'sticky' => FALSE,
       'caption' => '',
       'colgroups' => array(),
-      'empty' => '',
+      'empty' => 'This record is not aligned to any locations.',
     );
 
     // once we have our table array structure defined, we call Drupal's theme_table()
     // function to generate the table.
-    $element[$delta] = array(
-      '#type' => 'markup',
-      '#markup' => theme_table($table),
-    );
+    if (count($items) > 0) {
+      $element[0] = array(
+        '#type' => 'markup',
+        '#markup' => theme_table($table),
+      );
+    }
   }
 
   /**

+ 46 - 41
tripal_chado/includes/fields/chado_linker__genotype.inc

@@ -112,7 +112,9 @@ class chado_linker__genotype extends TripalField {
       'label' => 'Genotypes',
       'description' => 'The genotypes associated with this record.',
       'required' => FALSE,
-      'settings' => array(),
+      'settings' => array(
+        'auto_attach' => FALSE,
+      ),
       'widget' => array(
         'type' => 'chado_linker__genotype_widget',
         'settings' => array(
@@ -134,51 +136,54 @@ class chado_linker__genotype extends TripalField {
    */
   public function formatter_view(&$element, $entity_type, $entity,
       $field, $instance, $langcode, $items, $display) {
-        // Get the settings
-        $settings = $display['settings'];
-        $record = $entity->chado_record;
 
-        $headers = array('Name', 'Description', 'Type');
-        $rows = array();
+    // Get the settings
+    $settings = $display['settings'];
+    $record = $entity->chado_record;
 
-        foreach ($items as $delta => $item) {
-          $genotype = $item['value'];
-          if (!$genotype) {
-            continue;
-          }
+    $headers = array('Name', 'Description', 'Type');
+    $rows = array();
 
-          // Get the field values
-          $genotype_name = $genotype['name'];
-          $description = $genotype['description'];
-          $type = $genotype['type'];
+    foreach ($items as $delta => $item) {
+      $genotype = $item['value'];
+      if (!$genotype) {
+        continue;
+      }
 
-          // Add a link i there is an entity.
-          if (array_key_exists('entity_id', $item) and $item['entity_id']) {
-            $entity_id = $item['entity_id'];
-            $genotype_name = l($genotype_name, "bio_data/" . $entity_id, array('attributes' => array('target' => "_blank")));
-          }
-          $rows[] = array($genotype_name, $description, $type);
-        }
-        $table = array(
-          'header' => $headers,
-          'rows' => $rows,
-          'attributes' => array(
-            'id' => 'tripal_linker-table-genotype-object',
-            'class' => 'tripal-data-table'
-          ),
-          'sticky' => FALSE,
-          'caption' => "",
-          'colgroups' => array(),
-          'empty' => 'No genotypes available',
-        );
-        $content = theme_table($table);
+      // Get the field values
+      $genotype_name = $genotype['name'];
+      $description = $genotype['description'];
+      $type = $genotype['type'];
 
-        // once we have our table array structure defined, we call Drupal's theme_table()
-        // function to generate the table.
-        $element[$delta] = array(
-          '#type' => 'markup',
-          '#markup' => $content,
-        );
+      // Add a link i there is an entity.
+      if (array_key_exists('entity_id', $item) and $item['entity_id']) {
+        $entity_id = $item['entity_id'];
+        $genotype_name = l($genotype_name, "bio_data/" . $entity_id, array('attributes' => array('target' => "_blank")));
+      }
+      $rows[] = array($genotype_name, $description, $type);
+    }
+    $table = array(
+      'header' => $headers,
+      'rows' => $rows,
+      'attributes' => array(
+        'id' => 'tripal_linker-table-genotype-object',
+        'class' => 'tripal-data-table'
+      ),
+      'sticky' => FALSE,
+      'caption' => "",
+      'colgroups' => array(),
+      'empty' => 'No genotypes available.',
+    );
+    $content = theme_table($table);
+
+    // once we have our table array structure defined, we call Drupal's theme_table()
+    // function to generate the table.
+    if (count($items) > 0) {
+      $element[0] = array(
+        '#type' => 'markup',
+        '#markup' => $content,
+      );
+    }
   }
 
 

+ 45 - 41
tripal_chado/includes/fields/chado_linker__phenotype.inc

@@ -112,7 +112,9 @@ class chado_linker__phenotype extends TripalField {
       'label' => 'Phenotypes',
       'description' => 'The phenotypes associated with this record.',
       'required' => FALSE,
-      'settings' => array(),
+      'settings' => array(
+        'auto_attach' => FALSE,
+      ),
       'widget' => array(
         'type' => 'chado_linker__phenotype_widget',
         'settings' => array(
@@ -135,51 +137,53 @@ class chado_linker__phenotype extends TripalField {
    */
   public function formatter_view(&$element, $entity_type, $entity,
       $field, $instance, $langcode, $items, $display) {
-        // Get the settings
-        $settings = $display['settings'];
-        $record = $entity->chado_record;
+    // Get the settings
+    $settings = $display['settings'];
+    $record = $entity->chado_record;
 
-        $headers = array('Name', 'Value', 'Type');
-        $rows = array();
+    $headers = array('Name', 'Value', 'Type');
+    $rows = array();
 
-        foreach ($items as $delta => $item) {
-          $phenotype = $item['value'];
-          if (!$phenotype) {
-            continue;
-          }
+    foreach ($items as $delta => $item) {
+      $phenotype = $item['value'];
+      if (!$phenotype) {
+        continue;
+      }
 
-          // Get the field values
-          $phenotype_name = $phenotype['name'];
-          $value = $phenotype['value'];
-          $type = $phenotype['type'];
+      // Get the field values
+      $phenotype_name = $phenotype['name'];
+      $value = $phenotype['value'];
+      $type = $phenotype['type'];
 
-          // Add a link i there is an entity.
-          if (array_key_exists('entity_id', $item) and $item['entity_id']) {
-            $entity_id = $item['entity_id'];
-            $phenotype_name = l($phenotype_name, "bio_data/" . $entity_id, array('attributes' => array('target' => "_blank")));
-          }
-          $rows[] = array($phenotype_name, $value, $type);
-        }
-        $table = array(
-          'header' => $headers,
-          'rows' => $rows,
-          'attributes' => array(
-            'id' => 'tripal_linker-table-phenotype-object',
-            'class' => 'tripal-data-table'
-          ),
-          'sticky' => FALSE,
-          'caption' => "",
-          'colgroups' => array(),
-          'empty' => 'No phenotypes available',
-        );
-        $content = theme_table($table);
+      // Add a link i there is an entity.
+      if (array_key_exists('entity_id', $item) and $item['entity_id']) {
+        $entity_id = $item['entity_id'];
+        $phenotype_name = l($phenotype_name, "bio_data/" . $entity_id, array('attributes' => array('target' => "_blank")));
+      }
+      $rows[] = array($phenotype_name, $value, $type);
+    }
+    $table = array(
+      'header' => $headers,
+      'rows' => $rows,
+      'attributes' => array(
+        'id' => 'tripal_linker-table-phenotype-object',
+        'class' => 'tripal-data-table'
+      ),
+      'sticky' => FALSE,
+      'caption' => "",
+      'colgroups' => array(),
+      'empty' => 'No phenotypes available',
+    );
+    $content = theme_table($table);
 
-        // once we have our table array structure defined, we call Drupal's theme_table()
-        // function to generate the table.
-        $element[$delta] = array(
-          '#type' => 'markup',
-          '#markup' => $content,
-        );
+    // once we have our table array structure defined, we call Drupal's theme_table()
+    // function to generate the table.
+    if (count($items) > 0) {
+      $element[0] = array(
+        '#type' => 'markup',
+        '#markup' => $content,
+      );
+    }
   }
 
 

+ 7 - 4
tripal_chado/includes/fields/chado_linker__prop.inc

@@ -91,10 +91,13 @@ class chado_linker__prop extends TripalField {
       $properties[] = $item[$chado_table . '__value'];
     }
     $content = implode(', ', $properties);
-    $element[$delta] = array(
-      '#type' => 'markup',
-      '#markup' => $content,
-    );
+
+    if (count($items) > 0) {
+      $element[0] = array(
+        '#type' => 'markup',
+        '#markup' => $content,
+      );
+    }
   }
   /**
    * @see TripalField::widget_form()

+ 3 - 1
tripal_chado/includes/fields/chado_linker__prop_adder.inc

@@ -86,7 +86,9 @@ class chado_linker__prop_adder extends TripalField {
       'label' => 'Add Properties',
       'description' => 'Add additional property types to this record.',
       'required' => FALSE,
-      'settings' => array(),
+      'settings' => array(
+        'auto_attach' => FALSE,
+      ),
       'widget' => array(
         'type' => 'chado_linker__prop_adder_widget',
         'settings' => array(

+ 10 - 5
tripal_chado/includes/fields/chado_linker__pub.inc

@@ -91,7 +91,9 @@ class chado_linker_pub extends TripalField {
       'description' => 'This record has been referenced or is sourced from
         these publications.',
       'required' => FALSE,
-      'settings' => array(),
+      'settings' => array(
+        'auto_attach' => FALSE,
+      ),
       'widget' => array(
         'type' => 'chado_linker__pub_widget',
         'settings' => array(
@@ -151,10 +153,13 @@ class chado_linker_pub extends TripalField {
       'type' => 'ol',
       'attributes' => array(),
     );
-    $element[0] = array(
-      '#type' => 'markup',
-      '#markup' => theme_item_list($list),
-    );
+
+    if (count($items) > 0) {
+      $element[0] = array(
+        '#type' => 'markup',
+        '#markup' => theme_item_list($list),
+      );
+    }
   }
   /**
    * @see TripalField::widget_form()

+ 9 - 5
tripal_chado/includes/fields/chado_linker__relationship.inc

@@ -88,7 +88,9 @@ class chado_linker__relationship extends TripalField {
       'label' => 'Relationships',
       'description' => 'Other records with relationships to this record.',
       'required' => FALSE,
-      'settings' => array(),
+      'settings' => array(
+        'auto_attach' => FALSE,
+      ),
       'widget' => array(
         'type' => 'chado_linker__relationship_widget',
         'settings' => array(
@@ -199,10 +201,12 @@ class chado_linker__relationship extends TripalField {
 
     // once we have our table array structure defined, we call Drupal's theme_table()
     // function to generate the table.
-    $element[$delta] = array(
-      '#type' => 'markup',
-      '#markup' => theme_table($table),
-    );
+    if (count($items) > 0) {
+      $element[0] = array(
+        '#type' => 'markup',
+        '#markup' => theme_table($table),
+      );
+    }
   }
   /**
    * @see TripalField::widget_form()

+ 5 - 2
tripal_chado/includes/fields/chado_linker__synonym.inc

@@ -91,7 +91,9 @@ class chado_linker__synonym extends TripalField {
       'label' => 'Synonyms',
       'description' => 'Alternate names, aliases or synonyms for this record.',
       'required' => FALSE,
-      'settings' => array(),
+      'settings' => array(
+        'auto_attach' => FALSE,
+      ),
       'widget' => array(
         'type' => 'chado_linker__synonym_widget',
         'settings' => array(
@@ -135,7 +137,8 @@ class chado_linker__synonym extends TripalField {
 
     $chado_table = $field['settings']['chado_table'];
     foreach ($items as $delta => $item) {
-      if ($item[$chado_table . '__synonym_id']) {
+      if (array_key_exists($chado_table . '__synonym_id', $item) and
+          $item[$chado_table . '__synonym_id']) {
         $synonym = chado_generate_var('synonym', array('synonym_id' => $item[$chado_table . '__synonym_id']));
         $name = $synonym->name;
         if ($synonym->type_id->name != 'exact') {

+ 3 - 1
tripal_chado/includes/fields/chado_organism__type_id.inc

@@ -88,7 +88,9 @@ class chado_organism__type_id extends TripalField {
       'label' => 'Infrapsecific Type',
       'description' => 'The Infrapsecific Type.',
       'required' => FALSE,
-      'settings' => array(),
+      'settings' => array(
+        'auto_attach' => FALSE,
+      ),
       'widget' => array(
         'type' => 'chado_organism__type_id_widget',
         'settings' => array(

+ 3 - 1
tripal_chado/includes/tripal_chado.fields.inc

@@ -398,7 +398,9 @@ function tripal_chado_field_create_instance_info_base_defaults($bundle_name,
       'label' => ucwords(preg_replace('/_/', ' ', $column_name)),
       'description' => '',
       'required' => FALSE,
-      'settings' => array(),
+      'settings' => array(
+        'auto_attach' => TRUE,
+      ),
       'widget' => array(
         'settings' => array(
           'display_label' => 1,

+ 5 - 5
tripal_chado/includes/tripal_chado.semweb.inc

@@ -169,11 +169,11 @@ function tripal_chado_populate_chado_semweb_table() {
     'name' => 'software',
     'cv_name' => 'schema',
     'definition' => 'Computer software, or generally just software, is any ' .
-    'set of machine-readable instructions (most often in the form of a ' .
-    'computer program) that conform to a given syntax (sometimes ' .
-    'referred to as a language) that is interpretable by a given ' .
-    'processor and that directs a computer\'s processor to perform ' .
-    'specific operations.',
+      'set of machine-readable instructions (most often in the form of a ' .
+      'computer program) that conform to a given syntax (sometimes ' .
+      'referred to as a language) that is interpretable by a given ' .
+      'processor and that directs a computer\'s processor to perform ' .
+      'specific operations.',
   ));
   tripal_associate_chado_semweb_term('analysis', 'program', $term);
 

+ 0 - 1
tripal_ws/includes/tripal_ws.rest.inc

@@ -471,7 +471,6 @@ function tripal_ws_get_content($api_url, &$response, $ws_path, $ctype, $entity_i
 
   // Get the TripalEntity and attach all the fields.
   $entity = entity_load('TripalEntity', array('id' => $entity_id));
-  field_attach_load('TripalEntity', $entity);
   $entity = reset($entity);