Ver Fonte

Merge branch '7.x-3.x' of github.com:tripal/tripal into 7.x-3.x

Chun-Huai Cheng há 8 anos atrás
pai
commit
4553848ab3

+ 69 - 30
tripal/api/tripal.entities.api.inc

@@ -813,46 +813,85 @@ function tripal_get_entity_tokens($entity, $options = array()) {
  * @return
  *   The string will all tokens replaced with values.
  */
-function tripal_replace_entity_tokens($string, $entity, $bundle_entity = NULL) {
-
-
+function tripal_replace_entity_tokens($string, &$entity, $bundle_entity = NULL) {
   // Determine which tokens were used in the format string
+  $used_tokens = array();
   if (preg_match_all('/\[\w+\]/', $string, $matches)) {
     $used_tokens = $matches[0];
+  }
 
-    foreach($used_tokens as $token) {
-      $field = str_replace(array('.','[',']'),array('__','',''),$token);
-
-      $value = '';
-      if (isset($entity->{$field})) {
-
-        // Render the value from the field.
-        // First get the items to be rendered.
-        $field_value = field_get_items('TripalEntity', $entity, $field);
-        if (isset($field_value[0])) {
-          // Then get a render array for just the value of the first item (no markup).
-          $field_render_arr = field_view_value('TripalEntity', $entity, $field, $field_value[0]);
-          // Finally render the value from the render array.
-          $value = render($field_render_arr);
-        }
-      }
-      elseif ($field === 'TripalBundle__bundle_id') {
+  // If there are no tokens then just return the string.
+  if (count($used_tokens) == 0) {
+    return $string;
+  }
 
-        // Load the bundle entity if we weren't given it.
-        if (!$bundle_entity) {
-          $bundle_entity = tripal_load_bundle_entity(array('name' => $entity->bundle));
-        }
+  // If the field are not loaded for the entity then we want to load them
+  // but we won't do a field_attach_load() as that will load all of the
+  // fields. For syncing (publishing) of content loading all fields for
+  // all synced entities causes extreme slowness, so we'll only attach
+  // the necessary fields for replacing tokens.
+  $attach_fields = array();
+  foreach($used_tokens as $token) {
+    $field_name = str_replace(array('.','[',']'), array('__','',''), $token);
+
+    if (!property_exists($entity, $field_name)) {
+      $field = field_info_field($field_name);
+      $storage = $field['storage'];
+      $attach_fields[$storage['type']]['storage'] = $storage;
+      $attach_fields[$storage['type']]['fields'][]  = $field;
+    }
+  }
 
-        // This token should be the id of the TripalBundle.
-        $value = $bundle_entity->id;
+  // If we have any fields that need attaching, then do so now.
+  if (count(array_keys($attach_fields)) > 0) {
+    foreach ($attach_fields as $storage_type => $details) {
+      $storage = $details['storage'];
+      $fields = $details['fields'];
+      $field_ids = array();
+      foreach ($fields as $field) {
+        $field_ids[$field['id']] = array($entity->id);
       }
-      elseif ($field === 'TripalEntity__entity_id') {
 
-        // This token should be the id of the TripalEntity.
-        $value = $entity->id;
+      $entities = array($entity->id => $entity);
+      module_invoke($storage['module'], 'field_storage_load', 'TripalEntity',
+        $entities, FIELD_LOAD_CURRENT, $field_ids, array());
+    }
+  }
+
+  // Now that all necessary fields are attached process the tokens.
+  foreach($used_tokens as $token) {
+    $value = '';
+    if (isset($entity->{$field_name})) {
+
+      // Render the value from the field.
+      // First get the items to be rendered.
+      $field_value = field_get_items('TripalEntity', $entity, $field_name);
+      if (isset($field_value[0])) {
+        // Then get a render array for just the value of the first item (no markup).
+        $field_render_arr = field_view_value('TripalEntity', $entity, $field_name, $field_value[0]);
+        // Finally render the value from the render array.
+        $value = render($field_render_arr);
       }
-      $string = str_replace($token, $value, $string);
     }
+    // The TripalBundle__bundle_id is a special token for substituting the
+    // bundle id.
+    elseif ($field_name === 'TripalBundle__bundle_id') {
+      // Load the bundle entity if we weren't given it.
+      if (!$bundle_entity) {
+        $bundle_entity = tripal_load_bundle_entity(array('name' => $entity->bundle));
+      }
+      // This token should be the id of the TripalBundle.
+      $value = $bundle_entity->id;
+    }
+    // The TripalBundle__bundle_id is a special token for substituting the
+    // entty id.
+    elseif ($field_name === 'TripalEntity__entity_id') {
+      // This token should be the id of the TripalEntity.
+      $value = $entity->id;
+    }
+
+    // Perform the replacement of the token with the value.
+    $string = str_replace($token, $value, $string);
   }
 
   return $string;

+ 9 - 8
tripal/includes/TripalEntityController.inc

@@ -107,18 +107,13 @@ class TripalEntityController extends EntityAPIController {
     // If no title was supplied then we should try to generate one using the
     // default format set by admins.
     if (!$title) {
-
       // Load the TripalBundle entity for this TripalEntity.
+      // Get the format for the title based on the bundle of the entity.
+      // And then replace all the tokens with values from the entity fields.
       $bundle_entity = tripal_load_bundle_entity(array('name' => $entity->bundle));
-
-      // First get the format for the title based on the bundle of the entity.
       $title = tripal_get_title_format($bundle_entity);
-
-      // And then replace all the tokens with values from the entity fields.
       $title = tripal_replace_entity_tokens($title, $entity, $bundle_entity);
-
     }
-
     // As long as we were able to determine a title, we should update it ;-).
     if ($title) {
       db_update('tripal_entity')
@@ -257,7 +252,13 @@ class TripalEntityController extends EntityAPIController {
   }
 
   /**
-   * Saves the custom fields using drupal_write_record().
+   * Saves a new entity.
+   *
+   * @param $entity
+   *   A TripalEntity object to save.
+   *
+   * @return
+   *   The saved entity object with updated properties.
    */
   public function save($entity) {
     global $user;

+ 9 - 2
tripal/includes/TripalEntityUIController.inc

@@ -219,11 +219,18 @@ function tripal_view_entity($entity, $view_mode = 'full') {
    // For each entity retrieved add a row to the data listing.
    //while ($entity = $entities->fetchObject()) {
    foreach ($results['TripalEntity'] as $entity_id => $stub) {
-     $entity = entity_load('TripalEntity', array($entity_id));
-     $entity = reset($entity);
      $vocabulary = '';
      $term_name = '';
 
+     // We don't need all of the attached fields for an entity so, we'll
+     // not use the entity_load() function.  Instead just pull it from the
+     // database table.
+     $entity = db_select('tripal_entity', 'TE')
+       ->fields('TE')
+       ->condition('TE.id', $entity_id)
+       ->execute()
+       ->fetchObject();
+
      // Get the term
      $term = entity_load('TripalTerm', array('id' => $entity->term_id));
      $term = reset($term);

+ 26 - 13
tripal_chado/api/tripal_chado.api.inc

@@ -56,43 +56,58 @@ function tripal_get_chado_entity_id($data_table, $record_id) {
  *   FALSE if a failure occured.
  */
 function tripal_chado_publish_records($values, $job_id = NULL) {
-  $bundle_name = $values['bundle_name'];
-  $sync_node = array_key_exists('sync_node', $values) ? $values['sync_node'] : '';
 
+  // Make sure we have the required options: bundle_name.
   if (!array_key_exists('bundle_name', $values) or !$values['bundle_name']) {
-    tripal_report_error('tripal_chado', TRIPAL_ERROR, "Could not publish record: @error", array('@error' => 'The bundle name was not provided'));
+    tripal_report_error('tripal_chado', TRIPAL_ERROR,
+      "Could not publish record: @error",
+      array('@error' => 'The bundle name must be provided'));
     return FALSE;
   }
 
+  $bundle_name = $values['bundle_name'];
+  $sync_node = array_key_exists('sync_node', $values) ? $values['sync_node'] : '';
+
+
+  // Load the bundle entity so we can get information about which Chado
+  // table/field this entity belongs to.
   $bundle = tripal_load_bundle_entity(array('name' => $bundle_name));
   $bundle_id = $bundle->id;
   $table = tripal_get_bundle_variable('chado_table', $bundle_id);
   $column = tripal_get_bundle_variable('chado_column', $bundle_id);
   $cvterm_id = tripal_get_bundle_variable('chado_cvterm_id', $bundle_id);
 
-  // Get the table information
+  // Get the table information for the Chado table.
   $table_schema = chado_get_schema($table);
   $pkey_field = $table_schema['primary key'][0];
 
+  // Construct the SQL for identifying which records should be published.
   $select = "SELECT $pkey_field as record_id ";
-  $from = "FROM {" . $table . "} T
+  $from = "
+    FROM {" . $table . "} T
       LEFT JOIN public.chado_entity CE on CE.record_id = T.$pkey_field
     AND CE.data_table = '$table'
   ";
 
+  // For migration of Tripal v2 nodes to entities we want to include the
+  // coresponding chado linker table.
   if ($sync_node && db_table_exists('chado_' . $table)) {
     $select = "SELECT T.$pkey_field as record_id, CT.nid ";
     $from .= "INNER JOIN public.chado_$table CT ON CT.$pkey_field = T.$pkey_field";
   }
   $where = " WHERE CE.record_id IS NULL ";
+  // TODO: here we have hard-coded the analysis and organism tables, but
+  // there may be more that don't hve a type field.  I think if the $column
+  // value is null then that check is good enough, but it needs to be looked at.
   if ($table != 'analysis' and $table != 'organism') {
     $where .= "AND $column = $cvterm_id";
   }
 
+  // Perform the query.
   $sql = $select . $from . $where;
   $records = chado_query($sql);
   $num_published = 0;
-  $transaction  = db_transaction();
+  //$transaction  = db_transaction();
   try {
     while($record = $records->fetchObject()) {
 
@@ -102,8 +117,11 @@ function tripal_chado_publish_records($values, $job_id = NULL) {
       $entity = $ec->create(array(
         'bundle' => $bundle_name,
         'term_id' => $bundle->term_id,
+        'chado_record' => chado_generate_var($table, array($pkey_field => $record_id)),
+        'chado_record_id' => $record_id,
       ));
-      if (!$entity->save()) {
+      $entity = $entity->save();
+      if (!$entity) {
         throw new Exception('Could not create entity.');
       }
 
@@ -123,16 +141,11 @@ function tripal_chado_publish_records($values, $job_id = NULL) {
       }
       $success = drupal_write_record('chado_entity', $entity_record);
 
-      $entity = entity_load('TripalEntity', array($entity->id));
-      $entity = reset($entity);
-      $title_format = tripal_get_title_format($bundle);
-      $title = tripal_replace_entity_tokens($title_format, $entity, $bundle);
-      $ec->setTitle($entity, $title);
       $num_published++;
     }
   }
   catch (Exception $e) {
-    $transaction->rollback();
+    //$transaction->rollback();
     $error = $e->getMessage();
     tripal_report_error('tripal_chado', TRIPAL_ERROR, "Could not publish record: @error", array('@error' => $error));
     drupal_set_message('Failed publishing record. See recent logs for more details.', 'error');

+ 155 - 66
tripal_chado/api/tripal_chado.variables.api.inc

@@ -5,12 +5,80 @@
  */
 
 /**
- * Generates an array containing the full details of a record(s) in chado. The
- * returned array differs from the array returned by chado_select_record as all foreign key
- * relationships have been followed and those data are also included. The array
- * returned by this function can be used with chado_expand_var function to add
- * additional FK relationships that were not included because they were not
- * a one-to-one mapping or for fields that were excluded such as large text fields.
+ * Generates an object containing the full details of a record(s) in Chado.
+ *
+ * The object returned contains key/value pairs where the keys are the fields
+ * in the Chado table.
+ *
+ * The returned object differs from the array returned by chado_select_record()
+ * as all foreign key relationships in the Chado table have been followed and
+ * those data are also included. This function automatically excludes some
+ * fields and tables. Fields that are extremely long, such as text fields are
+ * automatically excluded to prevent long page loads.  Linking tables that have
+ * a many-to-one relationship with the record are also excluded. Use the
+ * chado_expand_var() to manually add in excluded fields and data from linker
+ * tables.
+ *
+ * Example Usage:
+ * @code
+ *   $values = array(
+ *     'name' => 'Medtr4g030710'
+ *   );
+ *   $feature = chado_generate_var('feature', $values);
+ * @endcode
+ *
+ * The $values array passed to this fucntion can be of the same format used
+ * by the chado_select_record() function.
+ *
+ * If a field is a foreign key then its value is an object that contains
+ * key/value pairs for that record.  The following code provides examples
+ * for retrieving values associated with the record, either as columns in the
+ * original Chado table or as columns in linked records through foreign keys:
+ * @code
+ *   // Get the feature name.
+ *   $name = $feature->name;
+ *   // Get the feature unique name.
+ *   $uniquename = $feature->uniquename;
+ *   // Get the feature type. Because the type name is obtained via
+ *   // a foreign key with the cvterm table, the objects are nested
+ *   // and we can follow the foreign key fields to retrieve those values
+ *   $type = $feature->type_id->name;
+ *   // Get the name of the vocabulary.
+ *   $cv = $feature->type_id->cv_id->name;
+ *   // Get the vocabulary id.
+ *   $cv_id = $feature->type_id->cv_id->cv_id;
+ * @endcode
+ *
+ *
+ * This will return an object if there is only one feature with the name
+ * Medtr4g030710 or it will return an array of feature objects if more than one
+ * feature has that name.
+ *
+ * Note to Module Designers: Fields can be excluded by default from these
+ * objects by implementing one of the following hooks:
+ *  - hook_exclude_field_from_tablename_by_default (where tablename is the
+ *    name of the table): This hook allows you to add fields to be excluded
+ *    on a per table basis. Simply implement this hook to return an array of
+ *    fields to be excluded. The following example will ensure that
+ *    feature.residues is excluded from a feature object by default:
+ *    @code
+ *      mymodule_exclude_field_from_feature_by_default() {
+ *        return array('residues' => TRUE);
+ *      }
+ *    @endcode
+ *  - hook_exclude_type_by_default:
+ *      This hook allows you to exclude fields using conditional. This
+ *      function should return an array of postgresql types mapped to criteria.
+ *      If the field types of any table match the criteria then the field
+ *      is excluded. Tokens available in criteria are >field_value<
+ *      and >field_name<. The following example will exclude all text
+ *      fields with a length > 50. Thus if $feature.residues is longer than
+ *      50 it will be excluded, otherwise it will be added.
+ *      @code
+ *        mymodule_exclude_type_by_default() {
+ *          return array('text' => 'length(>field_value< ) > 50');
+ *        }
+ *      @endcode
  *
  *
  * @param $table
@@ -26,16 +94,16 @@
  *   Additionally,  These options are available for this function:
  *   -return_array:
  *     can be provided to force the function to always return an array. Default
- *     behavior is to return a single record if only one record exists or to return
- *     an array if multiple records exist.
+ *     behavior is to return a single record if only one record exists or to
+ *     return an array if multiple records exist.
  *  - include_fk:
  *     an array of FK relationships to follow. By default, the
  *     chado_select_record function will follow all FK relationships but this
- *     may generate more queries then is desired slowing down this function call when
- *     there are lots of FK relationships to follow.  Provide an array specifying the
- *     fields to include.  For example, if expanding a property table (e.g. featureprop)
- *     and you want the CV and accession but do not want the DB the following
- *     array would work:
+ *     may generate more queries then is desired slowing down this function
+ *     call when there are lots of FK relationships to follow.  Provide an
+ *     array specifying the fields to include.  For example, if expanding a
+ *     property table (e.g. featureprop) and you want the CV and accession
+ *     but do not want the DB the following array would work:
  *
  *        $table_options =  array(
  *          'include_fk' => array(
@@ -58,41 +126,9 @@
  *     one for each pager.
  * @return
  *   Either an object (if only one record was selected from the base table)
- *   or an array of objects (if more than one record was selected from the base table).
- *   If the option 'return_array' is provided the function always returns an array.
- *
- * Example Usage:
- * @code
-   $values = array(
-     'name' => 'Medtr4g030710'
-   );
-   $features = chado_generate_var('feature', $values);
- * @endcode
- * This will return an object if there is only one feature with the name Medtr4g030710 or it will
- * return an array of feature objects if more than one feature has that name.
- *
- * Note to Module Designers: Fields can be excluded by default from these objects by implementing
- * one of the following hooks:
- *  - hook_exclude_field_from_tablename_by_default (where tablename is the name of the table):
- *      This hook allows you to add fields to be excluded on a per table basis. Simply implement
- *      this hook to return an array of fields to be excluded. For example:
- * @code
-   mymodule_exclude_field_from_feature_by_default() {
-     return array('residues' => TRUE);
-   }
- * @endcode
- *      will ensure that feature.residues is ecluded from a feature object by default.
- *  - hook_exclude_type_by_default:
- *      This hook allows you to exclude fields from all tables that are of a given postgresql field
- *      type. Simply implement this hook to return an array of postgresql types mapped to criteria.
- *      Then all fields of that type where the criteria supplied returns TRUE will be excluded from
- *      any table. Tokens available in criteria are >field_value<  and >field_name< . For example:
- * @code
-   mymodule_exclude_type_by_default() {
-     return array('text' => 'length(>field_value< ) > 50');
-   }
- * @endcode
- *      will exclude all text fields with a length > 50. Thus if $feature.residues is longer than 50 *      it will be excluded, otherwise it will be added.
+ *   or an array of objects (if more than one record was selected from the
+ *   base table). If the option 'return_array' is provided the function
+ *   always returns an array.
  *
  * @ingroup tripal_chado_query_api
  */
@@ -417,11 +453,78 @@ function chado_generate_var($table, $values, $base_options = array()) {
 }
 
 /**
- * Retrieves fields/tables/nodes that were excluded by default from a variable and adds them
+ * Retrieves fields, or tables that were excluded by default from a variable.
+ *
+ * The chado_generate_var() function automatically excludes some
+ * fields and tables from the default form of a variable. Fields that are
+ * extremely long, such as text fields are automatically excluded to prevent
+ * long page loads.  Linking tables that have a many-to-one relationship with
+ * the record are also excluded.  This function allows for custom expansion
+ * of the record created by chado_generate_var() by specifyin the field and
+ * tables that should be added.
+ *
+ * Example Usage:
+ * @code
+ *  // Get a chado object to be expanded
+ *  $values = array(
+ *    'name' => 'Medtr4g030710'
+ *  );
+ *  $features = chado_generate_var('feature', $values);
+ *  // Expand the feature.residues field
+ *  $feature = chado_expand_var($feature, 'field', 'feature.residues');
+ *  // Expand the feature properties (featureprop table)
+ *  $feature = chado_expand_var($feature, 'table', 'featureprop');
+ * @endcode
  *
- * This function exists to allow chado_generate_var() to excldue some
- * fields/tables/nodes from the default form of a variable without making it extremely difficult for
- * the tripal admin to get at these variables if he/she wants them.
+ * If a field is requested, it's value is added where it normally is expected
+ * in the record.  If a table is requested then a new key/value element is
+ * added to the record. The key is the table's name and the value is an
+ * array of records (of the same type created by chado_generate_var()). For
+ * example, expanding a 'feature' record to include a 'pub' record via the
+ * 'feature_pub' table.  The following provides a simple example for how
+ * the 'feature_pub' table is added.
+ *
+ * @code
+ * array(
+ *   'feature_id' => 1
+ *   'name' => 'blah',
+ *   'uniquename' => 'blah',
+ *   ....
+ *   'feature_pub => array(
+ *      [pub object],
+ *      [pub object],
+ *      [pub object],
+ *      [pub object],
+ *   )
+ * )
+ * @endcode
+ *
+ * where [pub object] is a record of a publication as created by
+ * chado_generate_var().
+ *
+ * If the requested table has multiple foreign keys, such as the 'featureloc'
+ * or 'feature_genotype' tables, then an additional level is added to the
+ * array where the foreign key column names are added.  An example feature
+ * record with an expanded featureloc table is shown below:
+ *
+ * @code
+ * array(
+ *   'feature_id' => 1
+ *   'name' => 'blah',
+ *   'uniquename' => 'blah',
+ *   ....
+ *   'featureloc => array(
+ *      'srcfeature_id' => array(
+ *        [feature object],
+ *        ...
+ *      )
+ *      'feature_id' => array(
+ *        [feature object],
+ *        ...
+ *      )
+ *   )
+ * )
+ * @endcode
  *
  * @param $object
  *   This must be an object generated using chado_generate_var()
@@ -485,20 +588,6 @@ function chado_generate_var($table, $values, $base_options = array()) {
  *   If the type is a table and it has already been expanded no changes is made to the
  *   returned object
  *
- * Example Usage:
- * @code
-   // Get a chado object to be expanded
-   $values = array(
-     'name' => 'Medtr4g030710'
-   );
-   $features = chado_generate_var('feature', $values);
-   // Expand the organism node
-   $feature = chado_expand_var($feature, 'node', 'organism');
-   // Expand the feature.residues field
-   $feature = chado_expand_var($feature, 'field', 'feature.residues');
-   // Expand the feature properties (featureprop table)
-   $feature = chado_expand_var($feature, 'table', 'featureprop');
- * @endcode
  *
  * @ingroup tripal_chado_query_api
  */

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

@@ -166,7 +166,7 @@ class chado_base__organism_id extends TripalField {
     // Set some defaults for the empty record.
     $entity->{$field_name}['und'][0] = array(
       'value' => '',
-      'organism__type_id' => '',
+      'organism__organism_id' => '',
     );
 
     if ($record) {

+ 16 - 12
tripal_chado/includes/tripal_chado.entity.inc

@@ -11,18 +11,22 @@ function tripal_chado_entity_create(&$entity, $type) {
   if ($type == 'TripalEntity') {
 
     // Set some defaults on vars needed by this module.
-    $entity->chado_table = NULL;
-    $entity->chado_column = NULL;
-    $entity->chado_record = NULL;
-    $entity->chado_record_id = NULL;
-
-    // Add in the Chado table information for this entity type.
-    $bundle = tripal_load_bundle_entity(array('name' => $entity->bundle));
-    $chado_table = tripal_get_bundle_variable('chado_table', $bundle->id);
-    $chado_column = tripal_get_bundle_variable('chado_column', $bundle->id);
-    if ($chado_table) {
-      $entity->chado_table = $chado_table;
-      $entity->chado_column = $chado_column;
+    if (!property_exists($entity, 'chado_table')) {
+      $entity->chado_table =  NULL;
+      $entity->chado_column = NULL;
+
+      // Add in the Chado table information for this entity type.
+      $bundle = tripal_load_bundle_entity(array('name' => $entity->bundle));
+      $chado_table = tripal_get_bundle_variable('chado_table', $bundle->id);
+      $chado_column = tripal_get_bundle_variable('chado_column', $bundle->id);
+      if ($chado_table) {
+        $entity->chado_table = $chado_table;
+        $entity->chado_column = $chado_column;
+      }
+    }
+    if (!property_exists($entity, 'chado_record')) {
+      $entity->chado_record = NULL;
+      $entity->chado_record_id = NULL;
     }
   }
 }

+ 34 - 21
tripal_chado/includes/tripal_chado.field_storage.inc

@@ -40,13 +40,14 @@ function tripal_chado_field_storage_write($entity_type, $entity, $op, $fields) {
   // Convert the fields into a key/value list of fields and their values.
   $field_vals = tripal_chado_field_storage_write_merge_fields($fields, $entity_type, $entity);
 
-  // Write the record for the base table.  First get the values for this table
-  // and set the record_id (update) or the type_id (insert)
+  // 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
+  // is an insert and we need to set the type_id if the table supports it.
   $values = $field_vals[$base_table][0];
   if ($record_id) {
     $values[$base_pkey] = $record_id;
   }
-  else {
+  elseif ($type_field) {
     $values[$type_field] = $cvterm->cvterm_id;
   }
   $base_record_id = tripal_chado_field_storage_write_table($base_table, $values);
@@ -107,7 +108,7 @@ function tripal_chado_field_storage_write_table($table_name, $values) {
    $fkeys = $schema['foreign keys'];
    $pkey = $schema['primary key'][0];
 
-   // Before inserting or updating this table, recruse if there are any
+   // 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.
@@ -157,7 +158,7 @@ function tripal_chado_field_storage_write_table($table_name, $values) {
      // Insert the values array as a new record in the table.
      $record = chado_insert_record($table_name, $values);
      if ($record === FALSE) {
-       throw new Exception('Could not insert Chado record into table: "' . $tablename . '".');
+       throw new Exception('Could not insert Chado record into table: "' . $table_name . '".');
      }
      return $record[$pkey];
    }
@@ -167,7 +168,7 @@ function tripal_chado_field_storage_write_table($table_name, $values) {
      // 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: $tablename.", 'error');
+       drupal_set_message("Could not update Chado record in table: $table_name.", 'error');
      }
      return $values[$pkey];
    }
@@ -187,22 +188,34 @@ function tripal_chado_field_storage_load($entity_type, $entities, $age,
   $langcode = $language->language;
 
   foreach ($entities as $id => $entity) {
-
-    // Get the base table and record id for the fields of this entity.
-    $details = db_select('chado_entity', 'ce')
-      ->fields('ce')
-      ->condition('entity_id', $entity->id)
-      ->execute()
-      ->fetchObject();
-
-    if (!$details) {
-      // TODO: what to do if record is missing!
+    // The chado_xxxx properties are added to the entity in the
+    // tripal_chado_entity_load() hook which unfortunately is called after
+    // attaching fields.  So, we may not have these properties. If that's
+    // the case we can get them by querying the chado_entity table directly.
+    // The chado_xxxx properites will be here in the case of syncing
+    // records.
+    // TODO: perhaps we should add a hook_entity_preattach() hook?
+    if (property_exists($entity, 'chado_table')) {
+      // Get the base table and record id for the fields of this entity.
+      $base_table = $entity->chado_table;
+      $type_field = $entity->chado_column;
+      $record_id = $entity->chado_record_id;
+    }
+    else {
+      // Get the base table and record id for the fields of this entity.
+      $details = db_select('chado_entity', 'ce')
+        ->fields('ce')
+        ->condition('entity_id', $entity->id)
+        ->execute()
+        ->fetchObject();
+      if (!$details) {
+        // TODO: what to do if record is missing!
+      }
+      // Get some values needed for loading the values from Chado.
+      $base_table = $details->data_table;
+      $type_field = $details->field;
+      $record_id = $details->record_id;
     }
-
-    // Get some values needed for loading the values from Chado.
-    $base_table = $details->data_table;
-    $type_field = $details->field;
-    $record_id = $details->record_id;
 
     // Get this table's schema.
     $schema = chado_get_schema($base_table);

+ 1 - 1
tripal_chado/tripal_chado.module

@@ -155,7 +155,7 @@ function tripal_chado_menu() {
     'title' => 'Publish Chado Content',
     'description' => t('Publish data that is present in Chado but which does
         not yet have a page on this site for viewing. In Tripal v2.0 or
-        earlier this was refered to as "syncing".'),    'page callback' => 'drupal_get_form',
+        earlier this was refered to as "syncing".'),
     'page callback' => 'drupal_get_form',
     'page arguments' => array('tripal_chado_publish_form'),
     'access arguments' => array('administer tripal'),