|  | @@ -17,44 +17,54 @@ function tripal_entities_field_storage_info() {
 | 
	
		
			
				|  |  |   */
 | 
	
		
			
				|  |  |  function tripal_entities_field_storage_write($entity_type, $entity, $op, $fields) {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  switch ($op) {
 | 
	
		
			
				|  |  | -    case FIELD_STORAGE_INSERT:
 | 
	
		
			
				|  |  | -      // Use the cvterm_id to look up tables where this term is used
 | 
	
		
			
				|  |  | -      $sel_values = array(
 | 
	
		
			
				|  |  | -        'term_id' => array(
 | 
	
		
			
				|  |  | -          'cvterm_id' => $entity->cvterm_id,
 | 
	
		
			
				|  |  | -        ),
 | 
	
		
			
				|  |  | -      );
 | 
	
		
			
				|  |  | -      $term_usage = chado_generate_var('tripal_term_usage', $sel_values, array('return_array' => 1));
 | 
	
		
			
				|  |  | +  // Conver the fields into a key/value list of fields and their values.
 | 
	
		
			
				|  |  | +  $field_vals = tripal_entities_field_storage_reformat_fields($fields, $entity_type, $entity);
 | 
	
		
			
				|  |  | +  $transaction = db_transaction();
 | 
	
		
			
				|  |  | +  try {
 | 
	
		
			
				|  |  | +    switch ($op) {
 | 
	
		
			
				|  |  | +      case FIELD_STORAGE_INSERT:
 | 
	
		
			
				|  |  | +        // Use the cvterm_id to look up tables where this term is used
 | 
	
		
			
				|  |  | +        $sel_values = array(
 | 
	
		
			
				|  |  | +          'term_id' => array(
 | 
	
		
			
				|  |  | +            'cvterm_id' => $entity->cvterm_id,
 | 
	
		
			
				|  |  | +          ),
 | 
	
		
			
				|  |  | +        );
 | 
	
		
			
				|  |  | +        $term_usage = chado_generate_var('tripal_term_usage', $sel_values, array('return_array' => 1));
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -      // For each table that uses this term, insert the field recursively
 | 
	
		
			
				|  |  | -      foreach ($term_usage as $usage) {
 | 
	
		
			
				|  |  | -        $data_table = $usage->data_table;
 | 
	
		
			
				|  |  | -        //$type_table = $usage->type_table;
 | 
	
		
			
				|  |  | -        $type_field = $usage->field;
 | 
	
		
			
				|  |  | -        tripal_entities_field_storage_write_recursive($entity_type, $entity,
 | 
	
		
			
				|  |  | -          $op, $fields, $data_table, $type_field);
 | 
	
		
			
				|  |  | -      }
 | 
	
		
			
				|  |  | -      break;
 | 
	
		
			
				|  |  | +        // For each table that uses this term, insert the field recursively
 | 
	
		
			
				|  |  | +        foreach ($term_usage as $usage) {
 | 
	
		
			
				|  |  | +          $data_table = $usage->data_table;
 | 
	
		
			
				|  |  | +          //$type_table = $usage->type_table;
 | 
	
		
			
				|  |  | +          $type_field = $usage->field;
 | 
	
		
			
				|  |  | +          tripal_entities_field_storage_write_recursive($entity_type, $entity,
 | 
	
		
			
				|  |  | +            $op, $field_vals, $data_table, $type_field);
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        break;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    case FIELD_STORAGE_UPDATE :
 | 
	
		
			
				|  |  | +      case FIELD_STORAGE_UPDATE :
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -      // 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();
 | 
	
		
			
				|  |  | -      $tablename = $details->data_table;
 | 
	
		
			
				|  |  | -      $type_field = $details->field;
 | 
	
		
			
				|  |  | -      $record_id = $details->record_id;
 | 
	
		
			
				|  |  | +        // 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();
 | 
	
		
			
				|  |  | +        $tablename = $details->data_table;
 | 
	
		
			
				|  |  | +        $type_field = $details->field;
 | 
	
		
			
				|  |  | +        $record_id = $details->record_id;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -      tripal_entities_field_storage_write_recursive($entity_type, $entity,
 | 
	
		
			
				|  |  | -        $op, $fields, $tablename, $type_field, $record_id);
 | 
	
		
			
				|  |  | -      if (!$details) {
 | 
	
		
			
				|  |  | -        // TODO: what to do if record is missing!
 | 
	
		
			
				|  |  | -      }
 | 
	
		
			
				|  |  | -      break;
 | 
	
		
			
				|  |  | +        tripal_entities_field_storage_write_recursive($entity_type, $entity,
 | 
	
		
			
				|  |  | +          $op, $field_vals, $tablename, $type_field, $record_id);
 | 
	
		
			
				|  |  | +        if (!$details) {
 | 
	
		
			
				|  |  | +          // TODO: what to do if record is missing!
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        break;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  catch (Exception $e) {
 | 
	
		
			
				|  |  | +    $transaction->rollback();
 | 
	
		
			
				|  |  | +    watchdog_exception('tripal_feature', $e);
 | 
	
		
			
				|  |  | +    drupal_set_message('Could not write record to Chado.  See recent logs', 'error');
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -62,7 +72,7 @@ function tripal_entities_field_storage_write($entity_type, $entity, $op, $fields
 | 
	
		
			
				|  |  |   * Implements hook_field_storage_write_recursive().
 | 
	
		
			
				|  |  |   */
 | 
	
		
			
				|  |  |  function tripal_entities_field_storage_write_recursive($entity_type, $entity,
 | 
	
		
			
				|  |  | -    $op, $fields, $tablename, $type_field = NULL, $record_id = NULL, $depth = 0) {
 | 
	
		
			
				|  |  | +    $op, $field_vals, $tablename, $type_field = NULL, $record_id = NULL, $depth = 0) {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    // Intialize the values array and $record_id;
 | 
	
		
			
				|  |  |    $values = array();
 | 
	
	
		
			
				|  | @@ -89,24 +99,13 @@ function tripal_entities_field_storage_write_recursive($entity_type, $entity,
 | 
	
		
			
				|  |  |        // loop through the $fk_fields again.
 | 
	
		
			
				|  |  |        $fkey_fields_list[] = $local_id;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -      // Recurse differently if this is an insert or an update.
 | 
	
		
			
				|  |  | +      // Recurse on the FK field.  Pass in the ID for the FK field if one
 | 
	
		
			
				|  |  | +      // exists in the $field_vals;
 | 
	
		
			
				|  |  |        $fk_val = NULL;
 | 
	
		
			
				|  |  | -      switch ($op) {
 | 
	
		
			
				|  |  | -        case FIELD_STORAGE_INSERT:
 | 
	
		
			
				|  |  | -          // On an insert we do not pass in a $record_id because
 | 
	
		
			
				|  |  | -          // we don't have any.
 | 
	
		
			
				|  |  | -          $fk_val = tripal_entities_field_storage_write_recursive($entity_type,
 | 
	
		
			
				|  |  | -            $entity, $op, $fields, $fk_table, NULL, NULL, $depth + 1);
 | 
	
		
			
				|  |  | -          break;
 | 
	
		
			
				|  |  | -        case FIELD_STORAGE_UPDATE:
 | 
	
		
			
				|  |  | -          // On an update we must get the value of the FK field. This should
 | 
	
		
			
				|  |  | -          // be present as a field, so get it's value and pass it in as the
 | 
	
		
			
				|  |  | -          // $record_id field.
 | 
	
		
			
				|  |  | -          $fk_val = tripal_entities_get_field_value($tablename . '__' . $local_id, $entity, $entity_type);
 | 
	
		
			
				|  |  | -          $fk_val = tripal_entities_field_storage_write_recursive($entity_type,
 | 
	
		
			
				|  |  | -            $entity, $op, $fields, $fk_table, NULL, $fk_val, $depth + 1);
 | 
	
		
			
				|  |  | -          break;
 | 
	
		
			
				|  |  | -      }
 | 
	
		
			
				|  |  | +      $fk_field_name = $tablename . '__' . $local_id;
 | 
	
		
			
				|  |  | +      $fk_val = array_key_exists($fk_field_name, $field_vals) ? $field_vals[$fk_field_name] : NULL;
 | 
	
		
			
				|  |  | +      $fk_val = tripal_entities_field_storage_write_recursive($entity_type,
 | 
	
		
			
				|  |  | +        $entity, $op, $field_vals, $fk_table, NULL, $fk_val, $depth + 1);
 | 
	
		
			
				|  |  |        if ($fk_val) {
 | 
	
		
			
				|  |  |          $values[$local_id] = $fk_val;
 | 
	
		
			
				|  |  |        }
 | 
	
	
		
			
				|  | @@ -116,95 +115,71 @@ function tripal_entities_field_storage_write_recursive($entity_type, $entity,
 | 
	
		
			
				|  |  |    // STEP 2: Loop through the incoming fields.
 | 
	
		
			
				|  |  |    // Loop through the fields passed to the function and find any that
 | 
	
		
			
				|  |  |    // are for this table.  Then add their values to the $values array.
 | 
	
		
			
				|  |  | -  foreach ($fields as $field_id) {
 | 
	
		
			
				|  |  | -    $field = field_info_field_by_id($field_id);
 | 
	
		
			
				|  |  | -    $field_name = $field['field_name'];
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | +  foreach ($field_vals as $field_name => $field_val) {
 | 
	
		
			
				|  |  | +    // If the field value is empty then continue.
 | 
	
		
			
				|  |  | +    if (!$field_val) {
 | 
	
		
			
				|  |  | +      continue;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  |      if (preg_match('/^' . $tablename . '__(.*)/', $field_name, $matches)) {
 | 
	
		
			
				|  |  |        $chado_field = $matches[1];
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +      // Skip the Pkey field. We won't ever insert a primary key and if
 | 
	
		
			
				|  |  | +      // one is provided in the fields then we use it for matching on an
 | 
	
		
			
				|  |  | +      // update.  We don't add it to the $values array in either case.
 | 
	
		
			
				|  |  | +      if ($chado_field == $pkey_field) {
 | 
	
		
			
				|  |  | +        continue;
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |        // Skip FK fields as those should already have been dealt with the
 | 
	
		
			
				|  |  |        // recursive code above.
 | 
	
		
			
				|  |  | -      if (in_array($field_id, $fkey_fields_list)) {
 | 
	
		
			
				|  |  | +      if (in_array($chado_field, $fkey_fields_list)) {
 | 
	
		
			
				|  |  |          continue;
 | 
	
		
			
				|  |  |        }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |        // Add the value of the field to the $values arr for later insert/update.
 | 
	
		
			
				|  |  | -      $values[$chado_field] = tripal_entities_get_field_value($tablename . '__' . $chado_field, $entity, $entity_type);
 | 
	
		
			
				|  |  | +      $values[$chado_field] = $field_vals[$field_name];
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    // STEP 3: Insert/Update the record.
 | 
	
		
			
				|  |  |    // If there are no values then return.
 | 
	
		
			
				|  |  | -  $entity->storage = array();
 | 
	
		
			
				|  |  | -  switch ($op) {
 | 
	
		
			
				|  |  | -    case FIELD_STORAGE_INSERT:
 | 
	
		
			
				|  |  | -      if (count($values) == 0) {
 | 
	
		
			
				|  |  | -        return NULL;
 | 
	
		
			
				|  |  | -      }
 | 
	
		
			
				|  |  | -      // Inser the values array as a new record in the table.
 | 
	
		
			
				|  |  | -      $record = chado_insert_record($tablename, $values);
 | 
	
		
			
				|  |  | -      if ($record === FALSE) {
 | 
	
		
			
				|  |  | -        drupal_set_message('Could not insert Chado record.', 'error');
 | 
	
		
			
				|  |  | -      }
 | 
	
		
			
				|  |  | -      $record_id = $record[$pkey_field];
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -      // Add a record to the chado_entity table so that the data for the
 | 
	
		
			
				|  |  | -      // fields can be pulled from Chado when loaded the next time. Only do
 | 
	
		
			
				|  |  | -      // this for the base table record.
 | 
	
		
			
				|  |  | -      if ($depth == 0) {
 | 
	
		
			
				|  |  | -        $record = array(
 | 
	
		
			
				|  |  | -          'entity_id' => $entity->id,
 | 
	
		
			
				|  |  | -          'record_id' => $record_id,
 | 
	
		
			
				|  |  | -          'data_table' => $tablename,
 | 
	
		
			
				|  |  | -          'type_table' => $tablename, // TODO: this must be fixed.
 | 
	
		
			
				|  |  | -          'field' => $type_field,
 | 
	
		
			
				|  |  | -        );
 | 
	
		
			
				|  |  | -        $success = drupal_write_record('chado_entity', $record);
 | 
	
		
			
				|  |  | -        if (!$success) {
 | 
	
		
			
				|  |  | -          drupal_set_message('Unable to insert new data.', 'error');
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -      }
 | 
	
		
			
				|  |  | -      break;
 | 
	
		
			
				|  |  | -    case FIELD_STORAGE_UPDATE:
 | 
	
		
			
				|  |  | -      // If we don't have any values we are not going to update the
 | 
	
		
			
				|  |  | -      // record because there is nothing to udpate, do just return the
 | 
	
		
			
				|  |  | -      // record_id.
 | 
	
		
			
				|  |  | -      if (count($values) == 0) {
 | 
	
		
			
				|  |  | -        return $record_id;
 | 
	
		
			
				|  |  | -      }
 | 
	
		
			
				|  |  | -      $match[$pkey_field] = $record_id;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -      chado_update_record($tablename, $match, $values);
 | 
	
		
			
				|  |  | -      break;
 | 
	
		
			
				|  |  | +  if (count($values) == 0) {
 | 
	
		
			
				|  |  | +    return $record_id;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  | -  return $record_id;
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | +  // If we don't have an incoming record ID then this is an insert.
 | 
	
		
			
				|  |  | +  if (!$record_id) {
 | 
	
		
			
				|  |  | +    // Insert the values array as a new record in the table.
 | 
	
		
			
				|  |  | +    $record = chado_insert_record($tablename, $values);
 | 
	
		
			
				|  |  | +    if ($record === FALSE) {
 | 
	
		
			
				|  |  | +      drupal_set_message('Could not insert Chado record into table, "$table".', 'error');
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    $record_id = $record[$pkey_field];
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -/**
 | 
	
		
			
				|  |  | - *
 | 
	
		
			
				|  |  | - */
 | 
	
		
			
				|  |  | -function tripal_entities_get_field_value($field_name, $entity, $entity_type) {
 | 
	
		
			
				|  |  | -  $value = NULL;
 | 
	
		
			
				|  |  | -  $field = field_info_field($field_name);
 | 
	
		
			
				|  |  | -  if (!$field) {
 | 
	
		
			
				|  |  | -    return $value;
 | 
	
		
			
				|  |  | +    // Add a record to the chado_entity table so that the data for the
 | 
	
		
			
				|  |  | +    // fields can be pulled from Chado when loaded the next time. Only do
 | 
	
		
			
				|  |  | +    // this for the base table record.
 | 
	
		
			
				|  |  | +    if ($depth == 0) {
 | 
	
		
			
				|  |  | +      $record = array(
 | 
	
		
			
				|  |  | +        'entity_id' => $entity->id,
 | 
	
		
			
				|  |  | +        'record_id' => $record_id,
 | 
	
		
			
				|  |  | +        'data_table' => $tablename,
 | 
	
		
			
				|  |  | +        'type_table' => $tablename, // TODO: this must be fixed.
 | 
	
		
			
				|  |  | +        'field' => $type_field,
 | 
	
		
			
				|  |  | +      );
 | 
	
		
			
				|  |  | +      $success = drupal_write_record('chado_entity', $record);
 | 
	
		
			
				|  |  | +      if (!$success) {
 | 
	
		
			
				|  |  | +        drupal_set_message('Unable to insert new Chado entity.', 'error');
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  // Currently, we only support one language, but for for the sake of
 | 
	
		
			
				|  |  | -  // thoroughness we'll iterate through all possible languages.
 | 
	
		
			
				|  |  | -  $all_languages = field_available_languages($entity_type, $field);
 | 
	
		
			
				|  |  | -  $field_languages = array_intersect($all_languages, array_keys((array) $entity->$field_name));
 | 
	
		
			
				|  |  | -  foreach ($field_languages as $langcode) {
 | 
	
		
			
				|  |  | -    $items = (array) $entity->{$field_name}[$langcode];
 | 
	
		
			
				|  |  | -    // The number of items is related to the cardinatily of the field.
 | 
	
		
			
				|  |  | -    // We should always only have one item because this is a field in a
 | 
	
		
			
				|  |  | -    // table. But we loop anyway.
 | 
	
		
			
				|  |  | -    foreach ($items as $delta => $item) {
 | 
	
		
			
				|  |  | -      $value = $item['value'];
 | 
	
		
			
				|  |  | +  // We have an incoming record_id so this is an update.
 | 
	
		
			
				|  |  | +  else {
 | 
	
		
			
				|  |  | +    $match[$pkey_field] = $record_id;
 | 
	
		
			
				|  |  | +    if (!chado_update_record($tablename, $match, $values)) {
 | 
	
		
			
				|  |  | +      drupal_set_message('Could not update Chado record for in table, "$table".', 'error');
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  | -  return $value;
 | 
	
		
			
				|  |  | +  return $record_id;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  /**
 | 
	
	
		
			
				|  | @@ -272,4 +247,44 @@ function tripal_entities_field_storage_load($entity_type, $entities, $age, $fiel
 | 
	
		
			
				|  |  |        }
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/**
 | 
	
		
			
				|  |  | + * Iterates through all of the fields reformats to a key/value array.
 | 
	
		
			
				|  |  | + *
 | 
	
		
			
				|  |  | + * @param $fields
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +function tripal_entities_field_storage_reformat_fields($fields, $entity_type, $entity) {
 | 
	
		
			
				|  |  | +  $new_fields = array();
 | 
	
		
			
				|  |  | +  foreach ($fields as $field_id => $ids) {
 | 
	
		
			
				|  |  | +    $field = field_info_field_by_id($field_id);
 | 
	
		
			
				|  |  | +    $field_name = $field['field_name'];
 | 
	
		
			
				|  |  | +    // Currently, we only support one language, but for for the sake of
 | 
	
		
			
				|  |  | +    // thoroughness we'll iterate through all possible languages.
 | 
	
		
			
				|  |  | +    $all_languages = field_available_languages($entity_type, $field);
 | 
	
		
			
				|  |  | +    $field_languages = array_intersect($all_languages, array_keys((array) $entity->$field_name));
 | 
	
		
			
				|  |  | +    foreach ($field_languages as $langcode) {
 | 
	
		
			
				|  |  | +      $items = (array) $entity->{$field_name}[$langcode];
 | 
	
		
			
				|  |  | +      // The number of items is related to the cardinatily of the field.
 | 
	
		
			
				|  |  | +      // We should always only have one item because this is a field in a
 | 
	
		
			
				|  |  | +      // table. But we loop anyway.
 | 
	
		
			
				|  |  | +      foreach ($items as $delta => $item) {
 | 
	
		
			
				|  |  | +        // If the $value is an array then this field has nested fields. We
 | 
	
		
			
				|  |  | +        // want to add those to our $new_fields list.
 | 
	
		
			
				|  |  | +        if (is_array($item['value'])) {
 | 
	
		
			
				|  |  | +          foreach ($item['value'] as $children) {
 | 
	
		
			
				|  |  | +            foreach ($children as $child_field_name => $child_value) {
 | 
	
		
			
				|  |  | +              if (preg_match('/^.*?__.*?$/', $child_field_name)) {
 | 
	
		
			
				|  |  | +                $new_fields[$child_field_name] = $child_value;
 | 
	
		
			
				|  |  | +              }
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +          }
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        else {
 | 
	
		
			
				|  |  | +          $new_fields[$field_name] = $item['value'];
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  return $new_fields;
 | 
	
		
			
				|  |  |  }
 |