Explorar o código

Fixed merge conflict

Stephen Ficklin %!s(int64=8) %!d(string=hai) anos
pai
achega
3961980a4e
Modificáronse 46 ficheiros con 3249 adicións e 2763 borrados
  1. 29 3
      tripal/api/tripal.jobs.api.inc
  2. 4 4
      tripal/api/tripal.notice.api.inc
  3. 3 23
      tripal/includes/TripalBundleController.inc
  4. 7 2
      tripal/includes/TripalEntityViewsController.inc
  5. 1 0
      tripal/includes/TripalFieldQuery.inc
  6. 86 8
      tripal/includes/TripalFields/TripalField.inc
  7. 1 1
      tripal/includes/tripal.field_storage.inc
  8. 48 1
      tripal/includes/tripal.fields.inc
  9. 46 0
      tripal/includes/tripal.jobs.inc
  10. 304 0
      tripal/includes/tripal.upload.inc
  11. 4 4
      tripal/theme/css/tripal.css
  12. 17 0
      tripal/theme/css/tripal_jobs.css
  13. 450 0
      tripal/theme/js/TripalUploadFile.js
  14. 578 0
      tripal/theme/js/TripalUploader.js
  15. 19 0
      tripal/theme/js/tripal_jobs.js
  16. 5 1
      tripal/tripal.info
  17. 2 1
      tripal/tripal.install
  18. 17 0
      tripal/tripal.module
  19. 62 50
      tripal/tripal.views.inc
  20. 109 93
      tripal/tripal_views_query.inc
  21. 63 0
      tripal/views_handlers/tripal_views_handler_field.inc
  22. 1 1
      tripal/views_handlers/tripal_views_handler_field_entity.inc
  23. 17 0
      tripal/views_handlers/tripal_views_handler_filter.inc
  24. 1 1
      tripal/views_handlers/tripal_views_handler_filter_select_string.inc
  25. 326 0
      tripal/views_handlers/tripal_views_handler_filter_string.inc
  26. 32 9
      tripal_chado/api/modules/tripal_chado.feature.api.inc
  27. 133 89
      tripal_chado/api/tripal_chado.api.inc
  28. 46 0
      tripal_chado/api/tripal_chado.entity.api.inc
  29. 18 9
      tripal_chado/api/tripal_chado.variables.api.inc
  30. 6 23
      tripal_chado/includes/TripalFields/ChadoField.inc
  31. 1 1
      tripal_chado/includes/TripalFields/obi__organism/obi__organism.inc
  32. 1 1
      tripal_chado/includes/TripalFields/sbo__relationship/sbo__relationship_formatter.inc
  33. 1 3
      tripal_chado/includes/TripalFields/schema__publication/schema__publication_formatter.inc
  34. 1 1
      tripal_chado/includes/TripalFields/so__transcript/so__transcript.inc
  35. 71 1
      tripal_chado/includes/tripal_chado.bundle.inc
  36. 4 1
      tripal_chado/includes/tripal_chado.entity.inc
  37. 10 10
      tripal_chado/includes/tripal_chado.field_storage.inc
  38. 4 5
      tripal_chado/includes/tripal_chado.fields.inc
  39. 0 1684
      tripal_chado/includes/tripal_chado.fields.inc.orig
  40. 7 0
      tripal_chado/includes/tripal_chado.semweb.inc
  41. 56 57
      tripal_chado/tripal_chado.install
  42. 15 14
      tripal_chado/tripal_chado.module
  43. 132 132
      tripal_chado/tripal_chado.views.inc
  44. 212 232
      tripal_chado/tripal_chado.views_default.inc
  45. 7 7
      tripal_chado/views_handlers/chado_views_handler_filter.inc
  46. 292 291
      tripal_chado_views/tripal_chado_views.views_default.inc

+ 29 - 3
tripal/api/tripal.jobs.api.inc

@@ -173,9 +173,9 @@ function tripal_get_job($job_id) {
   $job = db_query('SELECT j.* FROM {tripal_jobs} j WHERE j.job_id=:job_id', array(':job_id' => $job_id))
     ->fetchObject();
 
-  $job->submit_date_string = format_date($job->submit_date);
-  $job->start_time_string = format_date($job->start_time);
-  $job->end_time_string = format_date($job->end_time);
+  $job->submit_date_string = $job->submit_date ? format_date($job->submit_date) : '';
+  $job->start_time_string = $job->start_time ? format_date($job->start_time): '';
+  $job->end_time_string = $job->end_time ? format_date($job->end_time): '';
 
   return $job;
 }
@@ -426,6 +426,32 @@ function tripal_set_job_progress($job_id, $percentage) {
 
   return FALSE;
 }
+
+/**
+ * Retrieves the current proress of a job.
+ *
+ * @param $job_id
+ *   The job_id to get the progress for
+ *
+ * @return
+ *   A value between 0 and 100 indicating the percentage complete of the job.
+ */
+function tripal_get_job_progress($job_id) {
+
+  if (!$job_id) {
+    watchdog('tripal', "Must provide a \$$job_id argument to the tripal_get_job_progress() function.");
+    return FALSE;
+  }
+
+  // Get the progress.
+  $progress = db_select('tripal_jobs', 'tj')
+    ->fields('tj', array('progress'))
+    ->condition('job_id', $job_id)
+    ->execute()
+    ->fetchField();
+
+  return $progress;
+}
 /**
  * Returns a list of jobs that are active.
  *

+ 4 - 4
tripal/api/tripal.notice.api.inc

@@ -179,10 +179,10 @@ function tripal_set_message($message, $importance = TRIPAL_INFO, $options = arra
 
   // Mark-up the Message
   $full_message =
-     '<div class="tripal-site-admin-message">'
-       . '<span class="tripal-severity-string ' . strtolower($importance_string) . '">' . $importance_string . ': </span>'
-       . $message
-   . '</div>';
+     '<div class="tripal-site-admin-message">' .
+       '<span class="tripal-severity-string ' . strtolower($importance_string) . '">' . $importance_string . ': </span>' .
+       $message .
+   '</div>';
 
   // Handle whether to return the HTML & let the caller deal with it
   // or to use drupal_set_message to put it near the top of the page  & let the theme deal with it

+ 3 - 23
tripal/includes/TripalBundleController.inc

@@ -79,30 +79,10 @@ class TripalBundleController extends EntityAPIControllerExportable {
           }
         }
 
-        // TODO: this Chado sepcific code needs to be moved out of here!
-
-        // Remove the entries in the chado_entity and tripal_entity
-        $query = db_select('chado_entity', 'ce');
-        $query->join('tripal_entity', 'te', 'te.id = ce.entity_id');
-        $records = $query->fields('ce', array('chado_entity_id', 'data_table', 'record_id'))
-          ->condition('te.bundle', $bundle->name)
-          ->execute();
-        $num_removed = 0;
-        while ($record = $records->fetchObject()) {
-          db_delete('chado_entity')
-            ->condition('chado_entity_id', $record->chado_entity_id)
-            ->execute();
-          db_delete('tripal_entity')
-            ->condition('id', $record->chado_entity_id)
-            ->execute();
-          $num_removed++;
-        }
-        db_delete('chado_bundle')
-          ->condition('bundle_id', $bundle->id)
+        // Remove any entities from the tripal_entity table.
+        db_delete('tripal_entity')
+          ->condition('bundle', $bundle->name)
           ->execute();
-        if ($num_removed > 0) {
-          drupal_set_message(t('Removed %num records', array('%num' => $num_removed)));
-        }
 
         // Remove the terms for the bundles that are to be deleted.
         db_delete('tripal_term')

+ 7 - 2
tripal/includes/TripalEntityViewsController.inc

@@ -25,7 +25,6 @@ class TripalEntityViewsController extends EntityDefaultViewsController {
     $data['tripal_entity']['id']['title'] = 'tid';
     $data['tripal_entity']['id']['help'] = 'The unique numeric ID for the content';
 
-
     $data['tripal_entity']['title']['help'] = 'The content\'s title.';
     $data['tripal_entity']['title']['field']['handler'] = 'tripal_views_handler_field_entity';
 
@@ -34,7 +33,6 @@ class TripalEntityViewsController extends EntityDefaultViewsController {
     $data['tripal_entity']['status']['help'] = 'The publish status.';
     $data['tripal_entity']['status']['field']['handler'] = 'tripal_views_handler_field_entity_status';
 
-
     // We want to use our own query plugin.
     $data['tripal_entity']['table']['base']['query class'] = 'tripal_views_query';
 
@@ -51,6 +49,13 @@ class TripalEntityViewsController extends EntityDefaultViewsController {
     unset($data['tripal_entity']['term_id']);
     unset($data['tripal_entity']['type']);
 
+
+    // This should not be a base table. We're not going to allow
+    // for views based on TripalEntity content types or the list of
+    // fields would become outrageously overwhelming. Instead we will
+    // provide views by bundle.
+    unset($data['tripal_entity']['table']['base']);
+
     return $data;
   }
 

+ 1 - 0
tripal/includes/TripalFieldQuery.inc

@@ -8,6 +8,7 @@ class TripalFieldQuery extends EntityFieldQuery {
 
   protected $field_storage = array();
 
+
   public function execute() {
     // Give a chance for other modules to alter the query.
     drupal_alter('entity_query', $this);

+ 86 - 8
tripal/includes/TripalFields/TripalField.inc

@@ -25,6 +25,13 @@ class TripalField {
   // changed.
   public static $default_settings = array(
     'storage' => 'tripal_no_storage',
+    // It is expected that all fields set a 'value' in the load() function.
+    // In many cases, the value may be an associative array of key/value pairs.
+    // In order for Tripal to provide context for all data, the keys should
+    // be a controlled vocabulary term (e.g. rdfs:type). Keys in the load()
+    // function that are supported by the query() function should be
+    // listed here.
+    'searchable_keys' => array(),
   );
 
   // Provide a list of instance specific settings. These can be access within
@@ -67,6 +74,7 @@ class TripalField {
   // and field_create_instance().
   public static $no_ui = TRUE;
 
+
   // --------------------------------------------------------------------------
   //              PROTECTED CLASS MEMBERS -- DO NOT OVERRIDE
   // --------------------------------------------------------------------------
@@ -111,7 +119,6 @@ class TripalField {
         $accession = $instance['settings']['term_accession'];
         $term = tripal_get_term_details($vocabulary, $accession);
         if (!$term) {
-          dpm(debug_backtrace());
           throw new Error(t('Cannot create TripalField of type "%term" as that
               term does not exist.', array('%term' => "$vocabulary:$accession")));
         }
@@ -268,16 +275,48 @@ class TripalField {
   }
 
   /**
-   * Describes this fields "data tables" to Views.
+   * Describes this field to Views.
    *
-   * This function is the equivalent of the hook_views_data() function of
-   * the Drupal Views API.  It provides the necessary details to allow
-   * Views to integrate the field.
+   * An array of views data, in the same format as the return value of
+   * hook_views_data().
    *
-   * @return
-   *   An associative array describing the data structure of the field.
    */
-  public function viewsDataAlter(&$data, $entity_info) {
+  public function viewsData() {
+    $data = array();
+
+    $bundle_name = $this->instance['bundle'];
+    $field_name = $this->field['field_name'];
+
+    $data[$bundle_name][$field_name] = array(
+      'title' => $this->instance['label'],
+      'help' => $this->instance['description'],
+      'field' => array(
+        'handler' => 'tripal_views_handler_field',
+        'click sortable' => TRUE,
+      ),
+      'filter' => array(
+        'handler' => 'tripal_views_handler_filter_string',
+      ),
+      'sort' => array(
+        'handler' => 'views_handler_sort',
+      ),
+    );
+
+    return $data;
+  }
+
+  /**
+   * Allows the view data for this field to be altered.
+   *
+   * This function is the equivalent of the hook_field_views_data_alter()
+   * function of the Drupal Field API.  It provides the necessary details to
+   * allow views to integrate the field.
+   *
+   * @param $data
+   *   An array of views table data provided for a single field. This has the
+   *   same format as the return value of hook_views_data().
+   */
+  public function viewsDataAlter(&$data) {
 
   }
 
@@ -338,4 +377,43 @@ class TripalField {
 
   }
 
+  /**
+   * Used to filter records that match a given condition.
+   *
+   * Entities can be filtered using the fields.  This function should be
+   * implemented if the field  supports filtering.  To provide filtering,
+   * the $query object should be updated to including any joins and
+   * conditions necessary. The following rules should be followed when
+   * implementing this function:
+   * - Any keys from the value array that support filtering should be set
+   *   in the $default_settings['searchable_keys'] array of this class file.
+   * - Implement support for every key in the
+   *   $default_settings['searchable_keys'] array.
+   * - However, avoid making filteres for non-indexed database columns.
+   * - This function should never set the fields that should be returned
+   *   nor ordering or group by.
+   *
+   * @param $query
+   *   A query object appropriate for the data storage backend. For example,
+   *   The Tripal Chado module will provide a SelectQuery object.
+   * @param $condition
+   *   The field specific condition as set in the TripalFieldQuery object.
+   */
+  public function query($query, $condition) {
+
+  }
+
+  /**
+   * Used to sort records that have been filtered.
+   *
+   * @param $query
+   *   A query object appropriate for the data storage backend. For example,
+   *   The Tripal Chado module will provide a SelectQuery object.
+   * @param $order
+   *   The field ordering as set in the TripalFieldQuery object.  This function
+   *   should handle the ordering request as specified by this object.
+   */
+  public function queryOrder($query, $order) {
+
+  }
 }

+ 1 - 1
tripal/includes/tripal.field_storage.inc

@@ -49,7 +49,7 @@ function tripal_field_storage_load($entity_type, $entities, $age,
       $field_module = $field['module'];
 
       // Get the instnace for this field
-      $instance = field_info_instance($entity_type, $field_name, $entity->bundle); 
+      $instance = field_info_instance($entity_type, $field_name, $entity->bundle);
 
       // Allow the creating module to alter the value if desired.  The
       // module should do this if the field has any other form elements

+ 48 - 1
tripal/includes/tripal.fields.inc

@@ -82,6 +82,54 @@ function tripal_field_widget_info_alter(&$info) {
 
 }
 
+/**
+ * Implements hook_field_views_data();
+ */
+function tripal_field_views_data($field) {
+  $data = array();
+
+  $field_type = $field['type'];
+  $field_types = tripal_get_field_types();
+
+  // Iterate through the bundles to which this field is attached and
+  // if it is a TripalField field then we'll call the viewsDataAlater function.
+  $bundles = $field['bundles']['TripalEntity'];
+  foreach ($bundles as $bundle_name) {
+    $instance = field_info_instance('TripalEntity', $field['field_name'], $bundle_name);
+    if (in_array($field_type, $field_types)) {
+      $tfield = new $field_type($field, $instance);
+      $data += $tfield->viewsData();
+    }
+  }
+  return $data;
+}
+
+/**
+ * Implements hook_field_views_data_alter();
+ */
+function tripal_field_views_data_alter(&$result, $field, $module) {
+  // Skip fields that aren't TripalEntity fields.
+  if (!array_key_exists('TripalEntity', $field['bundles'])) {
+    return;
+  }
+
+  // Get the list of our Tripal field types for reference.
+  $tripal_field_types = tripal_get_field_types();
+
+  // Iterate through the bundles to which this field is attached and
+  // if it is a TripalField field then we'll call the viewsDataAlater function.
+  $bundles = $field['bundles']['TripalEntity'];
+  foreach ($bundles as $bundle_name) {
+
+    $field_type = $field['type'];
+    if (in_array($field_type, $tripal_field_types)) {
+      $instance = field_info_instance('TripalEntity', $field['field_name'], $bundle_name);
+      $tfield = new $field_type($field, $instance);
+      return $tfield->viewsDataAlter($result);
+    }
+  }
+}
+
 /**
  * Implements hook_field_formatter_info().
  */
@@ -430,7 +478,6 @@ function tripal_field_instance_settings_form_alter_process($element, &$form_stat
     $term_name = $instance['settings']['term_name'];
     $term = tripal_get_term_details($vocabulary, $accession);
   }
-  dpm($instance);
 
   // Construct a table for the vocabulary information.
   $headers = array();

+ 46 - 0
tripal/includes/tripal.jobs.inc

@@ -328,3 +328,49 @@ function tripal_jobs_view($job_id) {
   $output .= theme_table($table);
   return $output;
 }
+
+/**
+ * Runs a Tripal job from within the request.
+ *
+ * @param $job_id
+ */
+function tripal_jobs_status_view($job_id) {
+  // set the breadcrumb
+  $breadcrumb = array();
+  $breadcrumb[] = l('Home', '<front>');
+  $breadcrumb[] = l('Administration', 'admin');
+  $breadcrumb[] = l('Tripal', 'admin/tripal');
+  $breadcrumb[] = l('Jobs', 'admin/tripal/tripal_jobs');
+  drupal_set_breadcrumb($breadcrumb);
+
+  $job = tripal_get_job($job_id);
+
+  drupal_add_css(drupal_get_path ('module', 'tripal') . '/theme/css/tripal_jobs.css');
+  drupal_add_js(drupal_get_path ('module', 'tripal') . '/theme/js/tripal_jobs.js');
+
+  $markup  = "<h2>Job Progress</h2>";
+  $markup .=  "<p>Job: " . $job->job_name . ' (' . $job->progress . '% Complete)';
+  $markup .= '<br>Status: ' . $job->status . '</p>';
+  $markup .= '<div id="tripal-jobs-progress-bar"><div></div></div>';
+  $markup .= '<p>' . l('Refresh Page', 'admin/tripal/tripal_jobs/status/' . $job_id) . '</p>';
+
+  drupal_add_js('var progress_percent = ' . $job->progress . ';', array('type' => 'inline'));
+
+  // Reload the page every 30 seconds.
+  $meta = array(
+    '#tag' => 'meta',
+    '#attributes' => array(
+      'http-equiv' => 'refresh',
+      'content' =>  '30',
+    )
+  );
+  drupal_add_html_head($meta, 'tripal_job_status_page');
+
+  $page = array(
+    '#type' => 'markup',
+    '#markup' => $markup,
+  );
+
+  return $page;
+}
+

+ 304 - 0
tripal/includes/tripal.upload.inc

@@ -0,0 +1,304 @@
+<?php
+
+function tripal_file_upload($type, $filename, $action = NULL, $chunk = 0) {
+  global $user;
+
+  $user_dir = 'public://tripal/users/' . $user->uid;
+
+  if (!file_prepare_directory($user_dir, FILE_CREATE_DIRECTORY)) {
+    $message = 'Could not access the directory on the server for storing this file.';
+    watchdog('tripal', $message, array(), WATCHDOG_ERROR);
+    drupal_json_output(array(
+      'status'  => 'failed',
+      'message' => $message,
+      'file_id' => '',
+    ));
+    return;
+  }
+
+  // Check to see if this file is uploaded already. If it is
+  // we don't want to allow the file to be uploaded again.
+//   $merge_file = $user_dir . '/' . $filename;
+//   if (file_exists($merge_file)) {
+//     $message = 'This file aready exists on the server and will not be ' .
+//       'uploaded again.',
+//     watchdog('tripal', $message, array(), WATCHDOG_ERROR);
+//     drupal_json_output(array(
+//       'status'  => 'failed',
+//       'message' => $message,
+//       'file_id' => '',
+//     ));
+//     return;
+//   }
+
+  switch ($action) {
+    // If the action is 'put' then the callee is sending a chunk of the file
+    case 'save':
+      tripal_file_upload_put($filename, $chunk, $user_dir);
+      break;
+    case 'check':
+      tripal_file_upload_check($filename, $chunk, $user_dir);
+      break;
+    case 'merge':
+      tripal_file_upload_merge($filename, $type, $user_dir);
+      break;
+  }
+}
+/**
+ * Merges all chunks into a single file
+ * @param unknown $filename
+ */
+function tripal_file_upload_merge($filename, $type, $user_dir) {
+  global $user;
+
+  $module = $_GET['module'];
+
+  $status = 'merging';
+  $message = '';
+
+  // Build the paths to the temp directory and merged file.
+  $temp_dir = $user_dir . '/temp' . '/' . $filename;
+  $merge_file = $user_dir . '/' . $filename;
+
+  // If the temp directory where the chunks are found does not exist and the
+  // client is requesting merge then most likely the file has already been
+  // merged and the user hit the upload button again.
+  if (file_exists($temp_dir)) {
+    // Get the upload log.
+    $log = tripal_file_upload_read_log($temp_dir);
+
+    // Keep up with the expected file size.
+    $merge_size = 0;
+
+    // Open the new merged file.
+    $merge_fh = fopen($merge_file, "w");
+    if ($merge_fh){
+      if (flock($merge_fh, LOCK_EX)) {
+        $chunks_written = $log['chunks_written'];
+        $max_chunk = max(array_keys($chunks_written));
+        // Iterate through the chunks in order and see if any are missing.
+        // If so then break out of the loop and fail. Otherwise concatentate
+        // them together.
+        for ($i = 0; $i <= $max_chunk; $i++) {
+          if (!array_key_exists($i, $chunks_written)) {
+            $status = 'failed';
+            $message = 'Missing some chunks. Cannot complete file merge.';
+            break;
+          }
+          $merge_size += $chunks_written[$i];
+          $chunk_file = $temp_dir . '/' . $filename . '.chunk.' . $i;
+          $cfh = fopen($chunk_file, 'r');
+          while ($data = fread($cfh, 1024)) {
+            fwrite($merge_fh, $data);
+          }
+          fclose($cfh);
+        } // end for ($i = 0; $i <= $max_chunk; $i++) { ...
+
+        if (filesize($merge_file) != $merge_size) {
+          $status = 'failed';
+          $message = 'File was uploaded but final merged size is incorrect: ' . $merge_file . '.';
+        }
+      }
+      else {
+        $status = 'failed';
+        $message = 'Cannot lock merged file for writing: ' . $merge_file . '.';
+      }
+    }
+    else {
+      $status = 'failed';
+      $message = 'Cannot open merged file: ' . $merge_file . '.';
+    }
+    fclose($merge_fh);
+  }
+
+  // Make sure the merged file exists
+  if (!file_exists($merge_file)) {
+    $status = 'failed';
+    $message = 'Merge file is missing after upload ' . $merge_file . '.';
+  }
+  $file_id = NULL;
+
+  // If the file has been successfully merged then let the calling module
+  // deal with it.
+  if ($status != 'failed') {
+    $function = $module . '_handle_uploaded_file';
+    if(function_exists($function)) {
+      $file_id = $function($filename, $merge_file, $type);
+      if ($file_id) {
+        $file = file_load($file_id);
+        $status = 'completed';
+        $full_path = drupal_realpath($file->uri);
+        $md5sum = md5_file($full_path);
+        $md5sum_file = fopen("$full_path.md5", "w");
+        fwrite($md5sum_file, $md5sum);
+        fclose($md5sum_file);
+        unlink($temp_dir);
+      }
+      else {
+        $status = 'failed';
+        $message = 'Could not add file to GenSAS database.';
+      }
+    }
+    else {
+      $status = 'failed';
+      $message = 'Requesting module does not implement hook_handle_uploaded_file.';
+    }
+  }
+
+  if ($status == 'failed') {
+    watchdog('tripal', $message, array(), WATCHDOG_ERROR);
+  }
+  drupal_json_output(array(
+    'status'  => $status,
+    'message' => $message,
+    'file_id' => $file_id,
+  ));
+}
+/**
+ * Checks the size of a chunk to see if is fully uploded.
+ *
+ * @return
+ *   returns a JSON array with a status, message and the
+ *   current chunk.
+ */
+function tripal_file_upload_check($filename, $chunk, $user_dir) {
+
+  $chunk_size = $_GET['chunk_size'];
+
+  // Store the chunked file in a temp folder.
+  $temp_dir = $user_dir . '/temp' . '/' . $filename;
+  if (!file_exists($temp_dir)) {
+    mkdir($temp_dir, 0700, TRUE);
+  }
+
+  // Get the upload log.
+  $log = tripal_file_upload_read_log($temp_dir);
+  $chunks_written = $log['chunks_written'];
+  $max_chunk = 0;
+  if ($chunks_written) {
+    $max_chunk = max(array_keys($chunks_written));
+  }
+
+  // Iterate through the chunks in order and see if any are missing.
+  // If so then break out of the loop and this is the chunk to start
+  // on.
+  for ($i = 0; $i <= $max_chunk; $i++) {
+    if (!array_key_exists($i, $chunks_written)) {
+      break;
+    }
+  }
+
+
+  drupal_json_output(array(
+    'status' => 'success',
+    'message' => '',
+    'curr_chunk'  => $i,
+  ));
+}
+/**
+ * Saves the contents of the file being sent to the server.
+ *
+ * The file is saved using the filename the chunk number as an
+ * extension.  This function uses file locking to prevent two
+ * jobs from writing to the same file at the same time.
+ */
+function tripal_file_upload_put($filename, $chunk, $user_dir) {
+
+  // Get the HTTP PUT data.
+  $putdata = fopen("php://input", "r");
+  $size = $_SERVER['CONTENT_LENGTH'];
+
+  // Store the chunked file in a temp folder.
+  $temp_dir = $user_dir . '/temp/' . $filename;
+  if (!file_exists($temp_dir)) {
+    mkdir($temp_dir, 0700, TRUE);
+  }
+
+  // Open the file for writing if doesn't already exist with the proper size.
+  $chunk_file = $temp_dir . '/' . $filename . '.chunk.' . $chunk;
+  if (!file_exists($chunk_file) or filesize($chunk_file) != $size) {
+    // Read the data 1 KB at a time and write to the file
+    $fh = fopen($chunk_file, "w");
+    // Lock the file for writing. We don't want two different
+    // processes trying to write to the same file at the same time.
+    if (flock($fh, LOCK_EX)) {
+      while ($data = fread($putdata, 1024)) {
+        fwrite($fh, $data);
+      }
+      fclose($fh);
+    }
+  }
+  fclose($putdata);
+
+  // Get the current log, updated and re-write it.
+  $log = tripal_file_upload_read_log($temp_dir);
+  $log['chunks_written'][$chunk] = $size;
+  tripal_file_upoad_write_log($temp_dir, $log);
+}
+/**
+ * Reads the upload log file.
+ *
+ * The log file is used to keep track of which chunks have been uploaded.
+ * The format is an array with a key of 'chunks_written' which each element
+ * a key/value pair containing the chunk index as the key and the chunk size
+ * as the value.
+ *
+ * @param $temp_dir
+ *   The directory where the log file will be written. It must be a unique
+ *   directory where only chunks from a single file are kept.
+ */
+function tripal_file_upload_read_log($temp_dir) {
+
+  $log_file = $temp_dir . '/tripal_upload.log';
+  $log = NULL;
+
+  if (file_exists($log_file)) {
+    $fh = fopen($log_file, "r");
+
+    if ($fh and flock($fh, LOCK_EX)) {
+      $contents = '';
+      while ($data = fread($fh, 1024)) {
+        $contents .= $data;
+      }
+      $log = unserialize($contents);
+    }
+    fclose($fh);
+  }
+  if (!is_array($log)) {
+    $log = array(
+      'chunks_written' => array(),
+    );
+  }
+  return $log;
+}
+/**
+ * Writes the upload log file.
+ *
+ * The log file is used to keep track of which chunks have been uploaded.
+ * The format is an array with a key of 'chunks_written' which each element
+ * a key/value pair containing the chunk index as the key and the chunk size
+ * as the value.
+ *
+ * @param $temp_dir
+ *   The directory where the log file will be written. It must be a unique
+ *   directory where only chunks from a single file are kept.
+ * @param $log
+ *   The log array, that is serialized and then written to the file.
+ */
+function tripal_file_upoad_write_log($temp_dir, $log) {
+
+  $log_file = $temp_dir . '/tripal_upload.log';
+
+  if (!$log or !is_array($log)) {
+    $log = array(
+      'chunks_written' => array(),
+    );
+  }
+
+  // Get the last chunk read
+  $fh = fopen($log_file, "w");
+  if ($fh and flock($fh, LOCK_EX)) {
+    fwrite($fh, serialize($log));
+  }
+  fclose($fh);
+}

+ 4 - 4
tripal/theme/css/tripal.css

@@ -69,12 +69,12 @@ div.messages.tripal-site-admin-only{
 }
 
 
- /******************************************************************************
-  * Spinner for paginated elements
-  *****************************************************************************/
+/******************************************************************************
+ * Spinner for paginated elements
+ *****************************************************************************/
  #spinner {
    position: absolute;
    display: none;
    left: 24%;
    bottom: 7%;
- }
+ }

+ 17 - 0
tripal/theme/css/tripal_jobs.css

@@ -0,0 +1,17 @@
+#tripal-jobs-progress-bar {
+    width: 400px;
+    height: 22px;
+    border: 1px solid #111;
+    border-radius: 5px;
+    background-color: #292929;
+    box-shadow: 0 0 5px #333;
+}
+
+#tripal-jobs-progress-bar div {
+    height: 100%;
+    color: #fff;
+    text-align: right;
+    line-height: 22px; /* same as #progressBar height if we want text middle aligned */
+    width: 0;
+    background-color: #0099ff;
+}

+ 450 - 0
tripal/theme/js/TripalUploadFile.js

@@ -0,0 +1,450 @@
+/**
+ *  TripalUploadFile Object
+ */
+(function($) {
+
+  "use strict";
+
+  /**
+   * The constructor function.
+   */
+  var TripalUploadFile = function (file, options) {
+   
+    this.file = file;
+    this.options = options;
+    this.file_size = file.size;
+    this.chunk_size = (1024 * 2000); // 2024MB
+    this.total_chunks = ((this.file.size % this.chunk_size == 0) ? Math.floor(this.file.size / this.chunk_size) : Math.floor(this.file.size / this.chunk_size) + 1); 
+    this.curr_chunk = 0;
+    this.status = 'pending';
+    this.file_id = null;
+   
+    if ('mozSlice' in file) {
+      this.slice_method = 'mozSlice';
+    }
+    else if ('webkitSlice' in file) {
+      this.slice_method = 'webkitSlice';
+    }
+    else {
+      this.slice_method = 'slice';
+    }
+
+    var self = this;
+    this.xhr = new XMLHttpRequest();
+    this.xhr.onload = function() {
+      self._onChunkComplete();
+    }
+
+    // Respond to changes in connection
+    if ('onLine' in navigator) {
+      window.addEventListener('online', function () {self._onConnectionFound});
+      window.addEventListener('offline', function () {self._onConnectionLost});
+    }
+  
+
+    // ------------------------------------------------------------------------
+    // Internal Methods 
+    // ------------------------------------------------------------------------
+    /**
+     * 
+     */
+    this._upload = function() {
+      // Cacluate the range for the current chunk
+      var range_start = this.curr_chunk * this.chunk_size;
+      var range_end = range_start + this.chunk_size;
+      
+      // If we've gone beyond the number of chunks then just quit.
+      if (this.curr_chunk > this.total_chunks) {
+        this._onChunkComplete();
+        return;
+      }
+
+      // Prevent range overflow
+      if (this.range_end > this.file_size) {
+        this.range_end = this.file_size;
+      }
+         
+      var chunk = this.file[this.slice_method](range_start, range_end);
+      var url = this.options.url + '/' + this.file.name + '/save/' + this.curr_chunk;
+      
+      this.xhr.open('PUT', url, true);
+      this.xhr.overrideMimeType('application/octet-stream');  
+      this.xhr.setRequestHeader('Content-Range', 'bytes ' + range_start + '-' + range_end + '/' + this.file_size);
+      
+      this.xhr.send(chunk);
+    };
+    
+    /**
+     * Converts a file size into a human readable value.
+     * Borrowed function from:
+     * http://stackoverflow.com/questions/10420352/converting-file-size-in-bytes-to-human-readable
+     */
+    this._getReadableSize = function(bytes, si) {
+        var thresh = si ? 1000 : 1024;
+        
+        if(Math.abs(bytes) < thresh) {
+            return bytes + ' B';
+        }
+        var units = si
+          ? ['kB','MB','GB','TB','PB','EB','ZB','YB']
+          : ['KiB','MiB','GiB','TiB','PiB','EiB','ZiB','YiB'];
+        var u = -1;
+        do {
+          bytes /= thresh;
+          ++u;
+        } 
+        while(Math.abs(bytes) >= thresh && u < units.length - 1);
+        return bytes.toFixed(1) + ' ' + units[u];
+    };
+    
+    /**
+     * Queries server to see what chunk the loading left off at.
+     */
+    this._checkUpload = function() {
+      var url = this.options.url + '/' + this.file.name + '/check/';
+      var self = this;
+      $.ajax({
+        url : url,
+        data : {
+          'chunk_size' : this.chunk_size,
+        },
+        success : function(data, textStatus, jqXHR) {
+          if (data['status'] == 'failed') {
+            self.status = 'failed';
+            self.updateStatus();
+            alert(data['message']);
+          }
+          else {
+            self.curr_chunk =  data['curr_chunk'];
+            self.status = 'uploading';
+            self._upload();
+            self.updateStatus();
+            self.updateProgressBar();
+          }
+        },
+        error : function() {
+          self.curr_chunk = 0;
+          self._upload();
+        }
+      });
+    }
+    
+    /**
+     * 
+     */
+    this._mergeChunks = function() {
+        var url = this.options.url + '/' + this.file.name + '/merge';
+        var self = this;
+        $.ajax({
+          url : url,
+          data : {
+            'module' : this.options['module'],
+          },
+          success : function(data, textStatus, jqXHR) {
+            if (data['status'] == 'completed') {
+              self.file_id = data['file_id'];
+              self.status = 'completed';
+              self.updateStatus();
+            }
+            else {
+              self.status = 'failed';
+              self.updateStatus();
+              alert(data['message']);
+            }
+          },
+          error : function() {
+            self.status = 'failed';
+            self.updateStatus();
+          }
+        });
+    }
+   
+    // ------------------------------------------------------------------------
+    // Event Handlers
+    // ------------------------------------------------------------------------
+   
+    this._onChunkComplete = function() {
+      // If the curr_chunk and the total_chunks is the same then
+      // we've reached the end.
+      if (this.curr_chunk >= this.total_chunks) {
+        this.updateStatus();
+        this._onUploadComplete();
+
+        return;
+      }
+
+      // Continue as long as we aren't paused
+      if (this.status == 'uploading') {
+        this._upload();
+        this.curr_chunk++;
+        this.updateProgressBar();
+      }
+    };
+    /**
+     * 
+     */
+    this._onUploadComplete = function() {
+      this.status = 'merging';
+      this._mergeChunks();
+      this.updateStatus();
+    };
+    /**
+     * When a connection has been lost but reistablished then resume uploads.
+     */
+    this._onConnectionFound = function() {
+      this.resume();
+    };
+ 
+    /**
+     * When a cnnection has been lost then pause uploads.
+     */
+    this._onConnectionLost = function() {
+      this.pause();
+    };
+   
+    // ------------------------------------------------------------------------
+    // Public Methods 
+    // ------------------------------------------------------------------------
+    /**
+     * 
+     */
+    this.getProgressBar = function() {
+      var progress_id = this.options['progress'];
+      return '<div id="' + progress_id + '" class="tripal-uploader-progress-label">0%</div>';
+    };
+    
+    /**
+     * 
+     */
+    this.getLinks = function() {
+      var links_id = this.options['links'];
+      return '<div id="' + links_id + '" class="tripal-uploader-links">0%</div>';
+    }
+    
+    this.getCategory = function() {
+      return this.options['category'];
+    }
+    this.getIndex = function() {
+      return this.options['category'];
+    }
+    this.getTName = function() {
+      return this.options['tname'];
+    }
+    this.getFileName = function() {
+      return this.file.name;
+    }
+    /**
+     * 
+     */
+    this.getFileSize = function(readable) {
+      if (readable) {
+        return this._getReadableSize(this.file.size, true);
+      }
+      else {
+        return this.file.size;
+      }
+    };
+    /**
+     * Updates the links, status text and status bar.
+     */
+    this.updateStatus = function() {
+
+      var progress_id = this.options['progress'];
+      
+      // Add the progress text.
+      $('#' + progress_id).html('');
+      if (this.status == 'cancelled') {
+        $("<span>", {
+          'text' : 'Cancelled',
+        }).appendTo('#' + progress_id)
+      }
+      else if (this.status == 'checking') {
+        $("<span>", {
+          'text' : 'Checking...',
+        }).appendTo('#' + progress_id)
+      }
+      else if (this.status == 'merging') {
+        $("<span>", {
+          'text' : 'Processing...',
+        }).appendTo('#' + progress_id)
+      }
+      else if (this.status == 'failed') {
+        $("<span>", {
+          'text' : 'Failed',
+        }).appendTo('#' + progress_id)
+      }
+      else if (this.status == 'completed') {
+        $("<span>", {
+          'text' : 'Complete',
+        }).appendTo('#' + progress_id)
+        // Set the parent's target field.
+        var parent = self.options['parent'];
+        var tname = self.options['tname'];
+        var category = self.options['category'];
+        parent.setTarget(this.file_id, tname, category);
+      }
+      else if (this.status == 'paused') {
+        $("<span>", {
+          'text' : 'Paused',
+        }).appendTo('#' + progress_id)
+      }
+      
+      // Add a throbber if the status is uploading
+      if (this.status == 'uploading' || this.status == 'checking' || this.status == 'merging') {
+        $("<img>", {
+           'src': tripal_path + '/theme/images/ajax-loader.gif',
+           'class' : 'tripal-chunked-file-progress-throbber',
+         }).appendTo('#' + progress_id);
+      }
+      
+      // Add the appropriate links.
+      var links_id = this.options['links'];
+      var category = this.options['category'];
+      $('#' + links_id).html('');
+      if (this.status == 'cancelled') {
+        $("<a>", {
+          'id': links_id + '-pending',
+          'class': category + '-pending',
+          'href': 'javascript:void(0);',
+          'text': 'Restore',
+        }).appendTo('#' + links_id);
+        $('#' + links_id + '-pending').click(function() {
+          self.pending();
+        })
+      }
+      if (this.status == 'pending') {
+        $("<a>", {
+          'id': links_id + '-cancel',
+          'class': category + '-cancel',
+          'href': 'javascript:void(0);',
+          'text': 'Cancel',
+        }).appendTo('#' + links_id);
+        $('#' + links_id + '-cancel').click(function() {
+          self.cancel();
+        })
+      }
+      if (this.status == 'uploading') {
+        $("<a>", {
+          'id': links_id + '-pause',
+          'class': category + '-pause',
+          'href': 'javascript:void(0);',
+          'text': 'Pause',
+        }).appendTo('#' + links_id);
+        $('#' + links_id + '-pause').click(function() {
+          self.pause();
+        })
+      }
+      if (this.status == 'paused') {
+        $("<a>", {
+          'id': links_id + '-resume',
+          'class': category + '-resume',
+          'href': 'javascript:void(0);',
+          'text': 'Resume',
+        }).appendTo('#' + links_id);
+        $('#' + links_id + '-resume').click(function() {
+          self.resume();
+        })
+      }
+        
+      // Add the remove link.
+      $("<a>", {
+        'id': links_id + '-remove',
+        'class': category + '-remove',
+        'href': 'javascript:void(0);',
+        'text': ' Remove',
+      }).appendTo('#' + links_id);
+      $('#' + links_id + '-remove').click(function() {
+        var parent = self.options['parent'];
+        var index = self.options['index'];
+        var tname = self.options['tname'];
+        var category = self.options['category'];
+        parent.removeFile(category, index);
+        parent.updateTable(category);
+        // Unset the parent's target field.
+        parent.setTarget(null, tname, category);
+        self.cancel();
+      })
+    }
+    /**
+     * Updates the status bar progress only.
+     */
+    this.updateProgressBar = function() {
+      var progress_id = this.options['progress'];
+      var progress = (this.curr_chunk / this.total_chunks) * 100;
+      var self = this;
+
+      // Calculate the amount of the file transferred.
+      var size_transferred = this.curr_chunk * this.chunk_size;
+      size_transferred = this._getReadableSize(size_transferred, true);
+      
+      if (this.status == 'uploading') {
+        $('#' + progress_id).html('');
+        $("<span>", {
+          'class': 'tripal-chunked-file-progress-label',
+          'text': size_transferred,
+        }).appendTo($("<div>", {
+          'id': progress_id + '-bar',
+          'class': 'tripal-chunked-file-progress',
+          'width': progress + '%'
+        }).appendTo($("<div>", {
+          'id': progress_id + '-box',
+          'class': 'tripal-chunked-file-progress',
+        }).appendTo('#' + progress_id)));
+
+      }
+      if (this.status == 'uploading' || this.status == 'checking' || this.status == 'merging') {
+        $("<img>", {
+           'src': tripal_path + '/theme/images/ajax-loader.gif',
+           'class' : 'tripal-chunked-file-progress-throbber',
+         }).appendTo('#' + progress_id);
+      }
+      
+    };
+    /**
+     * 
+     */
+    this.cancel = function() {
+      this.status = 'cancelled';
+      this.updateStatus();
+    }
+    /**
+     * 
+     */
+    this.pending = function() {
+      this.status = 'pending';
+      this.updateStatus();
+    }
+    /**
+     * 
+     */
+    this.start = function() {
+      if (this.status == 'pending') {
+        // Change the status to checking. The first thing we'll
+        // do is see what's already present on the server.
+        this.status = 'checking';
+        this.curr_chunk = this._checkUpload();
+      }
+    };
+
+    /**
+     * 
+     */
+    this.pause = function() {
+      this.status = 'paused';
+      this.updateStatus();
+    };
+    /**
+     * 
+     */
+    this.resume = function() {
+      this.status = 'uploading';
+      this.updateStatus();
+      this.updateProgressBar();
+      this._upload();
+    };
+  };
+  
+  // Export the objects to the window for use in other JS files.
+  window.TripalUploadFile = TripalUploadFile;
+  
+})(jQuery);

+ 578 - 0
tripal/theme/js/TripalUploader.js

@@ -0,0 +1,578 @@
+/**
+ * @file
+ * TripalUploader Object
+ * 
+ * To use the TripalUploader Object the following must be performed:
+ * 
+ * 1) Add a Drupal form to your code that contains the following:
+ *   * A Drupal-style table with 4 or 8 columns.  See the addUploadTable
+ *     function in this class for a description of the columns.
+ *   * A button for submitting a file for upload.
+ * 
+ * @code
+ * $headers = array(
+ *    array('data' => 'Sequence File'),
+ *    array('data' => 'Size', 'width' => '10%'),
+ *    array('data' => 'Upload Progress', 'width' => '20%'),
+ *    array('data' => 'Action', 'width' => '10%')
+ *  );
+ *  $rows = array();
+ *  $table_vars = array(
+ *    'header'      => $headers,
+ *    'rows'        => $rows,
+ *    'attributes'  => array('id' => 'sequence-file-upload-table'),
+ *    'sticky'      => TRUE,
+ *    'colgroups'   => array(),
+ *    'empty'       => t('There are currently no files added.'),
+ *  );
+ *  $form['upload']['sequence_file'] = array(
+ *    '#markup' => theme('table', $table_vars)
+ *  );
+ *  $form['upload']['sequence_fid'] = array(
+ *    '#type' => 'hidden',
+ *    '#value' => 0,
+ *    '#attributes' => array('id' => 'sequence-fid')
+ *  );
+ *  $form['upload']['sequence_file_submit'] = array(
+ *    '#type'     => 'submit',
+ *    '#value'    => 'Upload Sequence File',
+ *    '#name' => 'sequence_file_submit',
+ *    // We don't want this button to submit as the file upload
+ *    // is handled by the JavaScript code.
+ *    '#attributes' => array('onclick' => 'return (false);')
+ *  );
+ * @endcode
+ * 
+ * 
+ * 2)  Edit the theme/js/[module_name].js and in the "Drupal.behaviors.[module]" 
+ * section add a JQuery show function to the form that converts the table 
+ * created in the Drupal form to a TripalUploader table.  The 'table_id' must be
+ * the same as the 'id' attribute set for the table in the Drupal code above.
+ * The 'submit_id' must be the id of the upload button added in the Drupal
+ * code above.  The 'category' for the files.  This is the category that
+ * will be saved in Tripal for the file.  See the addUploadTable function
+ * for additional options.  Include a 'cardinality' setting to indicate
+ * the number of allowed files per upload, and set the 'target_id' to the
+ * name of the field that will contain the file ID (fid) after uploading.
+ * 
+ * @code
+ *  // The TripalUploader object used for uploading of files using the
+ *  // HTML5 File API. Large files are uploaded as chunks and a progress
+ *  // bar is provided.
+ *  var uploader = new TripalUploader();
+ *  
+ *  $('#tripal-sequences-panel-form').show(function() {
+ *    uploader.addUploadTable('sequence_file', {
+ *      'table_id' : '#sequence-file-upload-table',
+ *      'submit_id': '#edit-sequence-file-submit',
+ *      'category' : ['sequence_file'],
+ *      'cardinality' : 1,
+ *      'target_id' : 'sequence-fid',
+ *    });
+ *  });
+ * @endcode
+ *
+ *
+ * 3) Files are uploaded automatically to Tripal.  Files are saved in the
+ * Tripal user's directory.  You can retreive information about the 
+ * file by querying for the file category for the current project.
+ * 
+ * @code
+ *   $seq_files = TripalFeature::getFilesByTypes($user->uid, array('sequence_file'), $project_id);
+ * @endcode
+ * 
+ * 4) If the 'target_id' was used in array for step #2 above, then the 
+ * file ID can be retrieved in the hook_validate() and hook_submit() functions
+ * via the $form_state['input'] array (not the $form_state['values'] array.
+ */
+
+
+(function($) {
+
+  "use strict";
+  
+  /**
+   * The constructor function.
+   */
+  var TripalUploader = function() {
+
+    // Holds the list of files and organizes them by category and then
+    // by an index number.
+    this.files = {};
+    
+    // The tables array will have the following keys:
+    //
+    // tname: the name of the HTML table containing the file.
+    // category:  the category within the table to which the file belongs.
+    // index:  the index of the file in the table.
+    // url: The URL at the remote server where the file will uploaded.
+    this.tables = {};
+
+    /**
+     * Adds a file to the TripalUploader object
+     * 
+     * @param file
+     *   The HTML5 file object.
+     * @param options
+     *   A set of key value pairs of the following
+     *     - tname: the name of the HTML table containing the file.
+     *     - category:  the category within the table to which the file belongs.
+     *     - index:  the index of the file in the table.
+     *     - url: The URL at the remote server where the file will uploaded.
+     */
+    this.addFile = function(file, options) {
+      var tname = options['tname'];
+      var category = options['category'];
+      var i = options['i'];
+      var url = options['url'];
+      var self = this;
+      
+      if (!(category in this.files)) {
+        this.files[category] = {}
+      }      
+      var options = {
+        'parent' : self,
+        'index' : i,
+        'url' : url,
+        'category' : category,
+        'tname' : tname,
+        'progress' : category + '-progress-' + i,
+        'links' : category + '-links-' + i,
+        'module' : this.tables[tname]['module']
+      }
+      var guf = new TripalUploadFile(file, options)
+      this.files[category][i] = guf;
+      return guf
+    };
+    /**
+     * 
+     */
+    this.removeFile = function(category, i) {
+      if (category in this.files) {
+        if (i in this.files[category]) {
+          delete this.files[category][i];
+        }
+      }
+    }
+    /**
+     * 
+     */
+    this.getMaxIndex = function(category) {
+      var index = 0;
+      if (category in this.files) {
+        for (var i in this.files[category]) {
+          if (i > index) {
+            index = i;
+          }
+        }
+      }
+      return index;
+    }
+    /**
+     * 
+     */
+    this.getNumFiles = function(category) {
+      var count = 0;
+      if (category in this.files) {
+        for (var i in this.files[category]) {
+          count = count + 1;
+        }
+      }
+      return count;
+    }
+    /**
+     * 
+     */
+    this.getCategoryFiles = function(category) {
+      if (!(category in this.files)) {
+        return [];
+      }
+      return this.files[category];
+    };
+    /**
+     * 
+     */
+    this.cancelFile = function(category, i) {
+      if (category in this.files) {
+        this.files[category][i].cancel();
+      }
+    };
+    /**
+     * 
+     */
+    this.start = function(category) {
+      if (category in this.files) {
+        for (var i in this.files[category]) {
+          this.files[category][i].start();
+        }
+      }
+    };
+    /**
+     * 
+     */
+    this.updateProgress = function(category) {
+      if (category in this.files) {
+        for (var i in this.files[category]) {
+          this.files[category][i].updateStatus();
+        }
+      }
+    };
+    /**
+     * 
+     */
+    this.reset = function(category) {
+      if (category in this.files) {
+        for (i in this.files[category]) {
+           this.files[category][i].cancel();
+        }
+        this.files[category] = [];
+      }
+    }
+    
+    /**
+     * 
+     */
+    this.getFileButton = function(tname, category, i) {
+      var button_name = tname + '--' + category + '-upload-' + i;
+      var element = '<input id="' + button_name + '" class="tripal-chunked-file-upload" type="file">';
+      
+      return {
+        'name' : button_name,
+        'element' : element,
+      }
+    }
+    
+    /**
+     * 
+     */
+    this.parseButtonID = function(id) {
+      // Get the category and index for this file.
+      var tname = id.replace(/^(.+)--(.+)-upload-(.+)$/, '$1');
+      var category = id.replace(/^(.+)--(.+)-upload-(.+)$/, '$2');
+      var index = id.replace(/^(.+)--(.+)-upload-(.+)$/, '$3');
+      
+      return {
+       'tname' : tname,
+       'category' :  category, 
+       'index' : index
+      };
+    }
+    
+    /**
+     * Adds support for an upload table for a specific category.
+     * 
+     * The TripalUploader supports two types of tables, a table for
+     * uploading paired data (e.g. RNA-seq) and single files.  This function
+     * replaces the body of an existing table as new files and updates
+     * the table as files are uploaded.
+     * 
+     * @param tname
+     *   The name of the table. For single files it is best to name the
+     *   table the same as the file category.  For paired data it is best
+     *   to use a name that represents both categoires.
+     * @param options
+     *   An associative array that contains the following keys:
+     *   table_id: The HTML id of the table.  For single data, the table
+     *     must already have 4 columns with headers (file name,
+     *     size, progress and action). For paired data, the table
+     *     must already have 8 columns, which are the same as the
+     *     single table but with two sets.
+     *   category:  An array. It must contain the list of categories that
+     *     this table manages.  For paired data include two categories.
+     *     This is the category of the file when saved in Tripal.
+     *   submit_id: The HTML id of the submit button.
+     *   module: The name of the module managing the table.
+     *   cardinatily:  (optional) The number of files allowed.  Set to 0 for 
+     *     unlimited.  Defalt is 0.
+     *   target_id: (optional). The HTML id of the hidden field in the form 
+     *     where the file ID will be written to this field. This only 
+     *     works if cardinality is set to 1.
+     *   allowed_types: (optional). An array of allowed file extensions (e.g.
+     *     fasta, fastq, fna, gff3, etc.). 
+     */
+    this.addUploadTable = function(tname, options) {
+      var table_id = options['table_id'];
+      var categories = options['category'];
+      var submit_id = options['submit_id'];
+      var target_id = options['target_id'];
+      var cardinality = options['cardinality'];
+      var module = options['module'];
+      
+      // Save the table ID for this category
+      if (!(tname in this.tables)) {
+        this.tables[tname] = {};
+      }
+      this.tables[tname]['table_id'] = table_id;
+      this.tables[tname]['category'] = categories;
+      this.tables[tname]['submit_id'] = submit_id;
+      this.tables[tname]['target_id'] = target_id;
+      this.tables[tname]['cardinality'] = cardinality;
+      this.tables[tname]['module'] = module;
+      this.updateTable(categories[0]);
+      this.enableSubmit(submit_id);
+    }
+    
+    /**
+     * Adds a click event to the submit button that starts the upload.
+     */
+    this.enableSubmit = function(submit_id) {
+      var self = this;
+      var categories = [];
+      
+      // Iterate through all of the tables that use this submit button
+      // and collect all the categories.  We want to update them all.
+      for (var tname in this.tables) {
+        if (this.tables[tname]['submit_id'] == submit_id){
+          for (var i = 0; i < this.tables[tname]['category'].length; i++) {
+            categories.push(this.tables[tname]['category'][i])
+          } 
+        }
+      }
+      var func_name = ($.isFunction($.fn.live)) ? 'live' : 'on';
+      $(submit_id)[func_name]('click', function() {
+        for(var i = 0; i < categories.length; i++) {
+          self.start(categories[i]);
+        }
+      });
+    }
+    
+    /**
+     * Updates the table for the given file category.
+     */
+    this.updateTable = function(category) {
+      // Iterate through all of the tables that are managed by this object.
+      for (var tname in this.tables) {
+        // Iterate through all of the categories on each table.
+        for (var i = 0; i < this.tables[tname]['category'].length; i++) {
+          // If the category of the table matches then update it.
+          if (this.tables[tname]['category'][i] == category) {
+            // For single files:
+            if (this.tables[tname]['category'].length == 1) {
+              var cat = this.tables[tname]['category'][0];
+              this.updateSingleTable(tname, cat);
+              this.updateProgress(cat);
+              return;
+            }
+            // For paired (e.g. RNA-seq) files:
+            if (this.tables[tname]['category'].length == 2) {
+              var categories = this.tables[tname]['category'];
+              this.updatePairedTable(tname, categories);
+              this.updateProgress(categories[0]);
+              this.updateProgress(categories[1]);
+              return;
+            }
+          }
+        }
+      }
+    }
+
+    /**
+     * A table for non-paired single data.
+     */
+    this.updateSingleTable = function(tname, category) {
+      var i = 0;
+      var content = '';
+      var files  = this.getCategoryFiles(category);
+      var max_index = this.getMaxIndex(category);
+      var has_file = false;
+      var table_id = this.tables[tname]['table_id'];
+      var cardinality = this.tables[tname]['cardinality'];
+      var target_id = this.tables[tname]['target_id'];
+      var num_files = this.getNumFiles(category);
+      var button = null;
+
+      // Build the rows for the non paired samples.
+      has_file = false;
+      for (i = 0; i <= max_index; i++) {
+        button = this.getFileButton(tname, category, i);
+        var trclass = 'odd';
+        if (i % 2 == 0) {
+          trclass = 'even';
+        }
+        content += '<tr class="' + trclass + '">';
+        if (i in files) {
+          content += '<td>' + files[i].file.name + '</td>';
+          content += '<td>' + files[i].getFileSize(true) + '</td>';
+          content += '<td>' + files[i].getProgressBar() + '</td>';
+          content += '<td>' + files[i].getLinks() + '</td>';
+          content += '</tr>';
+          has_file = true;
+        }
+        else {
+          content += '<td colspan="4">' + button['element'] + '</td>';
+        }
+        content +=  '</tr>';
+      }
+
+      // Create an empty row with a file button.
+      if (has_file) {
+        // Only add a new row if we haven't reached our cardinality limit.
+        if (!cardinality || cardinality == 0 || cardinality < num_files) {
+          button = this.getFileButton(tname, category, i);
+          content += '<tr><td colspan="4">' + button['element'] + '</td></tr>';
+        }
+      }
+
+      // Add the body of the table to the table with the provided table_id.
+      $(table_id + ' > tbody').html(content);
+      if (button) {
+        this.enableFileButton(button['name']);
+      }
+    }
+
+    /**
+     * Sets the table's target field with the file id.
+     * 
+     * @param $file_id
+     *   The Tripal file_id
+     * @param $tname
+     *   The name of the HTML table where the file is kept.
+     * @param $category
+     *   The name of the category to which the file belongs.
+     */
+    this.setTarget = function(file_id, tname, category) {
+      var files  = this.getCategoryFiles(category);
+      var cardinality = this.tables[tname]['cardinality'];
+      var target_id = this.tables[tname]['target_id'];
+      var num_files = this.getNumFiles(category);
+         
+      // If cardinality is 1 and this is a single file and we have a
+      // target, then we want to save the file id in the hidden field target 
+      // value
+      if (cardinality && cardinality == 1 && target_id && num_files == 1) {
+        $('#' + target_id).val(files[0].file_id);
+      }
+    }
+
+    /**
+     * A table for paired data (e.g. RNA-seq).
+     */
+    this.updatePairedTable = function(tname, categories) {
+        var i = 0;
+        var table_id = this.tables[tname]['table_id'];
+        var cardinality = this.tables[tname]['cardinality'];
+
+        var category1 = categories[0];
+        var category2 = categories[1];
+
+        var paired_content = '';   
+        var category1_files = this.getCategoryFiles(category1);
+        var category2_files = this.getCategoryFiles(category2);    
+        var max_paired1 = this.getMaxIndex(category1);
+        var max_paired2 = this.getMaxIndex(category2);
+        
+        var button1 = null;
+        var button2 = null;
+
+        // Bulid the rows for the paired sample files table.
+        var has_file = false;
+        for (i = 0; i <= Math.max(max_paired1, max_paired2); i++) {
+          button1 = this.getFileButton(tname, category1, i);
+          button2 = this.getFileButton(tname, category2, i);
+
+          var trclass = 'odd';
+          if (i % 2 == 0) {
+            trclass = 'even';
+          }
+          paired_content +=  '<tr class="' + trclass + '">';
+          if (i in category1_files) {
+            paired_content += '<td>' + category1_files[i].getFileName() + '</td>';
+            paired_content += '<td>' + category1_files[i].getFileSize(true)  + '</td>';
+            paired_content += '<td>' + category1_files[i].getProgressBar() + '</td>';
+            paired_content += '<td>' + category1_files[i].getLinks() + '</td>';
+            has_file = true;
+          }
+          else {
+            paired_content += '<td colspan="4">' + button1['element'] + '</td>';
+          }
+          if (i in category2_files) {
+            paired_content += '<td>' + category2_files[i].getFileName() + '</td>';
+            paired_content += '<td>' + category2_files[i].getFileSize(true) + '</td>';
+            paired_content += '<td>' + category2_files[i].getProgressBar() + '</td>';
+            paired_content += '<td nowrap>' + category2_files[i].getLinks() + '</td>';
+            has_file = true;
+          }
+          else {
+            paired_content += '<td colspan="4">' + button2['element'] + '</td>';
+          }
+          paired_content +=  '</tr>';
+        }
+
+        // Create a new empty row of buttons if we have files.
+        if (has_file) {
+          // Only add a new row if we haven't reached our cardinality limit.
+          if (!cardinality || cardinality == 0 || cardinality < max_index) {
+            button1 = this.getFileButton(tname, category1, i);
+            button2 = this.getFileButton(tname, category2, i);
+            paired_content += '<tr class="odd"><td colspan="4">' + button1['element'] + 
+              '</td><td colspan="4">' + button2['element'] + '</td></tr>'
+          }
+        }
+
+        $(table_id + ' > tbody').html(paired_content);
+        if (button1) {
+          this.enableFileButton(button1['name']);
+        }
+        if (button2) {
+          this.enableFileButton(button2['name']);
+        }
+    }
+
+    /**
+     * Adds a function to the change event for the file button that
+     * causes a new file to be added to this object which it is clicked.
+     * The button is added by the updateUploadTable
+     */
+    this.enableFileButton = function(button_name) {
+        // When the button provided by the TripalUploader class is clicked
+        // then we need to add the files to the object.  We must have this
+        // function so that we can set the proper URL
+        var self = this;
+
+        var func_name = ($.isFunction($.fn.live)) ? 'live' : 'on';
+        $('#' + button_name)[func_name]('change', function(e) {
+          var id = this.id;
+          
+          // Get the HTML5 list of files to upload.
+          var hfiles = e.target.files;
+
+          // Let the TripalUploader object parse the button ID to give us
+          // the proper category name and index.
+          var button = self.parseButtonID(id);
+          var tname = button['tname'];
+          var category = button['category'];
+          var index = button['index'];
+
+          // Add the file(s) to the uploader object.
+          for (var i = 0; i < hfiles.length; i++) {
+            var f = hfiles[i];
+//            if (!f.name.match('^.*\.fastq$')){
+//               alert('Only FastQ files are allowed.');
+//               continue;
+//            }
+            var options = {
+              // Files are managed by tables.
+              'tname' : tname,
+              // Files can be categorized to seprate them from other files.
+              'category': category,
+              // The index is the numeric index of the file. Files are ordered
+              // by their index. The file with an index of 0 is always ordered first.
+              'i': index,
+              // The URL at the remote server where the file will uploaded. 
+              'url' : '/tripal/upload/' + category,
+            };
+            self.addFile(f, options);
+
+            // We need to update the upload table and the progress. The
+            // information for which table to update is in the self.tables
+            // array.
+            self.updateTable(category);
+          }
+        });
+    }
+  };
+
+  // Export the objects to the window for use in other JS files.
+  window.TripalUploader = TripalUploader;
+
+})(jQuery);

+ 19 - 0
tripal/theme/js/tripal_jobs.js

@@ -0,0 +1,19 @@
+// Using the closure to map jQuery to $. 
+(function ($) {
+  // Store our function as a property of Drupal.behaviors.
+  Drupal.behaviors.tripalJobs = {
+    attach: function (context, settings) {
+
+      function tripal_job_progress(percent, element) {
+        var bar = $(element);
+        var percent_width = percent * bar.width() / 100;
+        bar.find('div').animate({ width: percent_width }, 500).html(percent + "% ");
+      }
+      
+      // The progress_percent value is provided by the
+      // tripal_jobs_run_job() function as inline code that gets
+      // added to the page on load.
+      tripal_job_progress(progress_percent, '#tripal-jobs-progress-bar');
+    }
+  }
+}) (jQuery);

+ 5 - 1
tripal/tripal.info

@@ -9,12 +9,16 @@ configure = admin/tripal
 stylesheets[all][] = theme/css/tripal.css
 scripts[]          = theme/js/tripal.js
 
-files[] = views_handlers/tripal_views_handler_filter_string_selectbox.inc
+files[] = views_handlers/tripal_views_handler_field.inc
 files[] = views_handlers/tripal_views_handler_field_entity.inc
 files[] = views_handlers/tripal_views_handler_field_entity_status.inc
 files[] = views_handlers/tripal_views_handler_field_entity_default_formatter.inc
+files[] = views_handlers/tripal_views_handler_filter.inc
+files[] = views_handlers/tripal_views_handler_filter_string.inc
 files[] = views_handlers/tripal_views_handler_filter_entity_string.inc
+files[] = views_handlers/tripal_views_handler_filter_string_selectbox.inc
 files[] = views_handlers/tripal_views_handler_sort_entity_string.inc
+
 files[] = tripal_views_query.inc
 
 dependencies[] = views

+ 2 - 1
tripal/tripal.install

@@ -771,7 +771,8 @@ function tripal_update_7300() {
       'not null' => TRUE
     );
     db_change_field('tripal_vocab', 'vocabulary', 'vocabulary',$spec);
-  } catch (\PDOException $e) {
+  } 
+  catch (\PDOException $e) {
     $error = $e->getMessage();
     throw new DrupalUpdateException('Could not perform update: '. $error);
   }

+ 17 - 0
tripal/tripal.module

@@ -209,6 +209,13 @@ function tripal_menu() {
     'page arguments' => array(4),
     'access arguments' => array('administer tripal'),
     'type' => MENU_CALLBACK,
+    'file' => 'api/tripal.jobs.api.inc',
+  );
+  $items['admin/tripal/tripal_jobs/status/%'] = array(
+    'page callback' => 'tripal_jobs_status_view',
+    'page arguments' => array(4),
+    'access arguments' => array('administer tripal'),
+    'type' => MENU_CALLBACK,
     'file' => 'includes/tripal.jobs.inc',
   );
   $items['admin/tripal/tripal_jobs/rerun/%'] = array(
@@ -238,6 +245,8 @@ function tripal_menu() {
     'file' => 'includes/tripal.jobs.inc',
   );
 
+
+
   /*
    * AJAX Callbacks.
    */
@@ -308,6 +317,14 @@ function tripal_menu() {
     'file path' => drupal_get_path('module', 'tripal'),
     'type' => MENU_LOCAL_ACTION,
   );
+
+  $items['tripal/upload'] = array(
+    'page callback' => 'tripal_file_upload',
+    'access arguments' => array('upload files'),
+    'file' => '/includes/tripal.upload.inc',
+    'type' => MENU_CALLBACK,
+  );
+
   return $items;
 }
 

+ 62 - 50
tripal/tripal.views.inc

@@ -29,18 +29,56 @@ function tripal_views_plugins() {
 function tripal_views_data() {
   $data = array();
   // Job Management System
-  $data = tripal_views_data_jobs($data);
-
-  $data += tripal_entity_views_data();
+  tripal_views_data_jobs($data);
+  tripal_entity_views_data($data);
+  tripal_views_data_fields($data);
 
   return $data;
 }
 
+/**
+ * Integreates the Tripal fields with Views.
+ */
+function tripal_views_data_fields(&$data) {
+
+  // Iterate through the fields.
+  $fields = field_info_fields();
+  foreach ($fields as $field) {
+
+    // Skip fields that aren't attached to TripalEntity fields.
+    if (!array_key_exists('TripalEntity', $field['bundles'])) {
+      continue;
+    }
+
+    // Call the hook_field_views_data() but only for the tripal module.
+    // Otherwise the other modules will expect that this is an SQL-based
+    // view.
+    $result = (array) module_invoke('tripal', 'field_views_data', $field);
+
+    // Set defaults for the field if no data array was returned.
+    if (empty($result)) {
+      // Iterate through the bundles to which this field is attached and
+      // if it is a TripalField field then we'll call the viewsDataAlater function.
+      $bundles = $field['bundles']['TripalEntity'];
+      $result = array();
+      foreach ($bundles as $bundle_name) {
+        $instance = field_info_instance('TripalEntity', $field['field_name'], $bundle_name);
+        $tfield = new TripalField($field, $instance);
+        $result += $tfield->viewsData();
+      }
+    }
+
+    drupal_alter('field_views_data', $result, $field, $module);
+
+    if (is_array($result)) {
+      $data = drupal_array_merge_deep($result, $data);
+    }
+  }
+}
 /**
  * Integrates the TripalEntity entities with Drupal Views.
  */
-function tripal_entity_views_data() {
-  $data = array();
+function tripal_entity_views_data(&$data) {
 
   // Get the list of all of the bundles (entity types) and add them
   // as "base tables" for views.
@@ -52,52 +90,26 @@ function tripal_entity_views_data() {
   while ($bundle = $bundles->fetchObject()) {
 
     // Each bundle gets it's own "table".
-//     $data['tripal_entity']['table']['group'] = t($bundle->label);
-//     $data[$bundle->name]['table']['base'] = array(
-//       'query class' => 'tripal_views_query',
-//       'title' => t($bundle->label),
-//       'help' => t('Tripal ' . $bundle->label . ' pages'),
-//     );
-
-    // Now add the fields to the bundle.
-    $instances = field_info_instances('TripalEntity', $bundle->name);
-    foreach ($instances as $instance) {
-
-      // TODO: how to determine which handler to use for each field? Perhaps
-      // fields should set their type and here we use that type to determine
-      // which handler to use. If not handler is specified then we use
-      // a default string handler.
-      $field_handler = 'tripal_views_handler_field_entity_default_formatter';
-      $filter_handler = 'tripal_views_handler_filter_entity_string';
-      $sort_handler = 'tripal_views_handler_sort_entity_string';
-      $click_sortable = TRUE;
-
-      $field_name = $instance['field_name'];
-
-      if ($field_name == 'content_type') {
-        $field_handler = 'views_handler_field';
-      }
-
-      $data['tripal_entity'][$field_name] = array(
-        'group' => $bundle->label,
-        'title' => $instance['label'],
-        'help' => t(' Appears in: @bundles.', array('@bundles' => $bundle->label)) . $instance['description'],
-        'handler' => '',
-        'field' => array(
-          'handler' => $field_handler,
-          'click sortable' => $click_sortable,
-        ),
-        'filter' => array(
-          'handler' => $filter_handler,
-        ),
-        'sort' => array(
-          'handler' => $sort_handler,
-        ),
-      );
-    }
+    $data[$bundle->name]['table']['group'] = t($bundle->label);
+    $data[$bundle->name]['table']['base'] = array(
+      'query class' => 'tripal_views_query',
+      'title' => t($bundle->label),
+      'help' => t('Tripal ' . $bundle->label . ' pages'),
+    );
+    $data[$bundle->name]['entity_id'] = array(
+      'title' => t('Entity ID'),
+      'help' => t('The unique entity ID for this content type.'),
+      'field' => array(
+        'handler' => 'tripal_views_handler_field_entity',
+      ),
+      'filter' => array(
+        'handler' => 'tripal_views_handler_filter',
+      ),
+      'sort' => array(
+        'handler' => 'views_handler_sort',
+      ),
+    );
   }
-
-  return $data;
 }
 
 /**

+ 109 - 93
tripal/tripal_views_query.inc

@@ -1,32 +1,99 @@
 <?php
 
-class tripal_views_query extends views_plugin_query_default {
+class tripal_views_query extends views_plugin_query {
 
-  private $attach_fields = array();
+  // The EntityFieldQuery object.
+  var $query;
 
+  var $fields;
+
+  var $filters;
+
+
+  /**
+   * Ensure a table exists in the queue.
+   *
+   * This function overrides the views_plugin_query version of the function
+   * but does nothing other than return the "table" (or bundle) name as
+   * we won't be using aliases for bundles.
+   *
+   * @param $table
+   *   The unaliased name of the table to ensure.
+   * @param $relationship
+   *   The relationship to ensure the table links to. Each relationship will
+   *   get a unique instance of the table being added. If not specified, will
+   *   be the primary table.
+   * @param $join
+   *   A views_join object (or derived object) to join the alias in.
+   *
+   * @return
+   *   The alias used to refer to this specific table, or NULL if the table
+   *   cannot be ensured.
+   */
+  public function ensure_table($table, $relationship = NULL, $join = NULL) {
+    // Because we are not querying a table, we're querying a TripalFieldQuery
+    // object we don't need to ensure the table.
+    return $table;
+  }
   /**
    *
    */
   public function init($base_table = 'tripal_entity', $base_field = 'id', $options) {
     parent::init($base_table, $base_field, $options);
 
-    // Always add the TripaEntity id and the bundle name so we can keep
-    // track of which rows are in the SQL results
-    $this->add_field('tripal_entity', 'id', 'tripal_entity_id');
-    $this->add_field('tripal_bundle', 'name', 'tripal_bundle_name');
+    $this->fields = array();
+    $this->where = array();
 
+    // Creqte the TripalFieldQuery object.
+    $this->query = new TripalFieldQuery();
+
+    // Make suer we only query on the entities for this bundle type.
+    $this->query->entityCondition('entity_type', 'TripalEntity');
+    $this->query->entityCondition('bundle', $base_table);
   }
   /**
    *
    */
-  public function add_field($table_alias, $field, $alias = '', $params = array()) {
-    // If this is not a TripalField then allow the add_field to work as usual.
-    $f = field_info_field($field);
-    if (!$f) {
-      return parent::add_field($table_alias, $field, $alias, $params);
-    }
-    else {
-      $this->attach_fields[] = $f;
+  public function add_field($table_alias, $field_name, $alias = '', $params = array()) {
+    $this->fields[] = array(
+      'table_alias' => $table_alias,
+      'field_name' => $field_name,
+      'alias' => $alias,
+      'params' => $params
+    );
+  }
+
+  /**
+   * Add a simple WHERE clause to the query.
+   *
+   * @param $group
+   *   The WHERE group to add these to; groups are used to create AND/OR
+   *   sections. Groups cannot be nested. Use 0 as the default group. If the
+   *   group does not yet exist it will be created as an AND group.
+   * @param $field
+   *   The name of the field to check.
+   * @param $value
+   *   The value to test the field against. In most cases, this is a scalar.
+   *   For more complex options, it is an array. The meaning of each element
+   *   in the array is dependent on the $operator.
+   * @param $operator
+   *   The comparison operator, such as =, <, or >=. It also accepts more
+   *   complex options such as IN, LIKE, or BETWEEN. Defaults to IN if $value
+   *   is an array = otherwise. If $field is a string you have to use 'formula'
+   *   here.
+   */
+  public function add_where($group, $field_name, $value = NULL, $operator = NULL) {
+    // Remove the preceeding period from the $field_name
+    $field_name = preg_replace('/^\./', '', $field_name);
+
+    $this->filters[] = array(
+      'group' => $group,
+      'field_name' => $field_name,
+      'value' => $value,
+      'op' => $operator
+    );
+    if ($value) {
+      $this->query->fieldCondition($field_name, $value, $value, $op);
     }
   }
 
@@ -35,91 +102,40 @@ class tripal_views_query extends views_plugin_query_default {
    * @param  $view
    */
   function execute(&$view) {
+    $query = $this->query;
 
-    // First execute any SQL that needs to run.
-    parent::execute($view);
-
-    // Add in the entity object to the results and any additional fields
-    // that have been requested.
-    for ($i = 0; $i < count($view->result); $i++) {
-
-      // Build a simple entity stub (it's faster than trying to load the
-      // whole things!).
-      $entity_id = $view->result[$i]->tripal_entity_id;
-      $bundle_name = $view->result[$i]->tripal_bundle_name;
-      $ids = array($entity_id, 0, $bundle_name);
-      $entity = entity_create_stub_entity('TripalEntity', $ids);
-
-      // Iterate through the field and attach only those that have been
-      // requested.
-      foreach ($this->attach_fields as $field) {
-        // Don't load this field if it doesn't belong to the selected bundle
-        if (in_array($bundle_name, $field['bundles']['TripalEntity'])) {
-          $entities = array($entity_id => $entity);
-          module_invoke($field['storage']['module'], 'field_storage_load', 'TripalEntity',
-            $entities, FIELD_LOAD_CURRENT, array($field['id'] => array($entity_id)));
-        }
-      }
-      $view->result[$i]->entity = $entity;
-    }
-    return;
-
-    // The base table indicates our content type.
-    $base_table = $view->base_table;
-
-    // Get the bundle that the view base table represents.
-//    $bundle = tripal_load_bundle_entity(array('name' => $view->base_table));
+    $start = microtime(TRUE);
 
-    // The base table for the view is a bundle therefore the first condition
-    // must be with the content_type field.
-    $query = new TripalFieldQuery();
-//    $query->entityCondition('entity_type', 'TripalEntity');
-    $query->entityCondition('bundle', $bundle->name);
-
-    // Apply filters
-    foreach ($view->filter as $field_name => $handler) {
-      if (trim($handler->value)) {
-        $query->fieldCondition($field_name, $field_name, $handler->value, $handler->operator);
-      }
-    }
-    // Apply sorting
-    foreach ($view->sort as $field_name => $sort) {
-      $options = $sort->options;
-      $query->fieldOrderBy($field_name, $options['order']);
-    }
+    // Execute the count query
+    $cquery = clone $query;
+    $cquery->count();
+    $num_records = $cquery->execute();
+    $views->total_rows = count($num_records['TripalEntity']);
 
     $results = $query->execute();
 
-    if (count($results) > 0) {
-      foreach ($results['TripalEntity'] as $entity_id => $stub) {
-        // Begin a new row for Views output.
-        $row = new stdClass;
-
-        // Get the entity object.
-        $entity = tripal_load_entity('TripalEntity', array('id' => $entity_id));
-        $entity = reset($entity);
-
-        // Iterate through the fields that are added to the view and attach those
-        // to the entity.  After attaching we can get the value and include
-        // it in the output results.
-        foreach($view->field as $field_name => $handler) {
-          $field = field_info_field($field_name);
-          field_attach_load($entity->type, array($entity->id => $entity), FIELD_LOAD_CURRENT,
-              array('field_id' => $field['id']));
-          $items = field_get_items('TripalEntity', $entity, $field_name);
-          $value = $items[0]['value'];
-
-          $row->entity = $entity;
-          $row->$field_name = $value;
-        }
-
-        // Add the row to the results list.
-        $view->result[] = $row;
-
+    // Iterate through the entities that were returned and get the field
+    // values that are requested.  Those go in the view->result array.
+    $i = 0;
+    $view->result = array();
+    foreach ($results['TripalEntity'] as $entity_id => $stub) {
+      $entities = array($entity_id => $stub);
+      $view->result[$i] = new stdClass();
+      $view->result[$i]->entity = $stub;
+      foreach ($this->fields as $details) {
+        $field_name = $details['field_name'];
+        $field = field_info_field($field_name);
+        module_invoke($field['storage']['module'], 'field_storage_load', 'TripalEntity',
+            $entities, FIELD_LOAD_CURRENT, array($field['id'] => array($entity_id)));
+        $view->result[$i]->$field_name = $entities[$entity_id]->$field_name['und'][0]['value'];
       }
+      $view->result[$i]->entity_id = $stub->id;
+      $i++;
     }
-
-    $view->total_rows = count($view->result);
-    $view->pager['current_page'] = 0;
+    $view->execute_time = microtime(TRUE) - $start;
+    $view->current_page = 0;
+    //dpm($view->query);
+    //dpm($view->result);
   }
+
 }

+ 63 - 0
tripal/views_handlers/tripal_views_handler_field.inc

@@ -0,0 +1,63 @@
+<?php
+/**
+ * @file
+ *   Views field handler for basic TripalFields fields.
+ */
+
+/**
+ * Views field handler for basic TripalFields fields.
+ */
+class tripal_views_handler_field extends views_handler_field {
+
+  /**
+   *
+   */
+  function query() {
+    parent::query();
+    // We need to add an alias to our TripalFields so that the
+    // views can find the results.  With SQL it sets the alias for each
+    // field and expects to find that alias in the results array.  Without
+    // setting this alias Views can't find our results from our
+    // tripal_views_query plugin.
+    $this->field_alias = $this->real_field;
+  }
+
+  /**
+   * Get the value that's supposed to be rendered.
+   *
+   * This api exists so that other modules can easy set the values of the field
+   * without having the need to change the render method as well.
+   *
+   * @param $values
+   *   An object containing all retrieved values.
+   * @param $field
+   *   Optional name of the field where the value is stored.
+   */
+  function get_value($values, $field = NULL) {
+    $alias = isset($field) ? $this->aliases[$field] : $this->field_alias;
+
+    // For some reason the alias isn't being added to the $this->aliases
+    // variable when the user clicks the checkbox 'Link this field to the
+    // original piece of content'.  That may need to be investigated and is
+    // probably a side effect of using the  views_handler_field as a parent
+    // class that is expecting something more for SQL. We don't use aliases
+    // for fields so the following if statement will fix the problem.
+    if (!$alias) {
+      $alias = $this->field_alias;
+    }
+    if (isset($values->{$alias})) {
+      return $values->{$alias};
+    }
+  }
+
+  /**
+   * Render the field.
+   *
+   * @param $values
+   *   The values retrieved from the database.
+   */
+  function render($values) {
+    $value = $this->get_value($values);
+    return $this->sanitize_value($value);
+  }
+}

+ 1 - 1
tripal/views_handlers/tripal_views_handler_field_entity.inc

@@ -12,7 +12,7 @@
  *
  * @ingroup views_field_handlers
  */
-class tripal_views_handler_field_entity extends views_handler_field {
+class tripal_views_handler_field_entity extends tripal_views_handler_field {
 
   function init(&$view, &$options) {
     parent::init($view, $options);

+ 17 - 0
tripal/views_handlers/tripal_views_handler_filter.inc

@@ -0,0 +1,17 @@
+<?php
+
+class tripal_views_handler_filter extends views_handler_filter {
+
+  /**
+   * Add this filter to the query.
+   *
+   * Due to the nature of fapi, the value and the operator have an unintended
+   * level of indirection. You will find them in $this->operator
+   * and $this->value respectively.
+   */
+  function query() {
+    $this->ensure_my_table();
+    $this->query->add_where($this->options['group'], $this->real_field, $this->value, $this->operator);
+  }
+
+}

+ 1 - 1
tripal/views_handlers/tripal_views_handler_filter_select_string.inc

@@ -323,7 +323,7 @@ class tripal_views_handler_filter_string_selectbox extends views_handler_filter_
     }
 
     $this->ensure_my_table();
-    $field = $this->table_alias . "." . $this->real_field;
+    $field = $this->real_field;
     $table = $this->query->get_table_info($this->table);
 
     $this->options['values_form_type'] = (isset($this->options['values_form_type'])) ? $this->options['values_form_type'] : 'textfield';

+ 326 - 0
tripal/views_handlers/tripal_views_handler_filter_string.inc

@@ -0,0 +1,326 @@
+<?php
+class tripal_views_handler_filter_string extends tripal_views_handler_filter {
+  // exposed filter options
+  var $always_multiple = TRUE;
+
+  function option_definition() {
+    $options = parent::option_definition();
+
+    $options['expose']['contains']['required'] = array('default' => FALSE, 'bool' => TRUE);
+
+    return $options;
+  }
+
+  /**
+   * This kind of construct makes it relatively easy for a child class
+   * to add or remove functionality by overriding this function and
+   * adding/removing items from this array.
+   */
+  function operators() {
+    $operators = array(
+      '=' => array(
+        'title' => t('Is equal to'),
+        'short' => t('='),
+        'method' => 'op_equal',
+        'values' => 1,
+      ),
+      '!=' => array(
+        'title' => t('Is not equal to'),
+        'short' => t('!='),
+        'method' => 'op_equal',
+        'values' => 1,
+      ),
+      'contains' => array(
+        'title' => t('Contains'),
+        'short' => t('contains'),
+        'method' => 'op_contains',
+        'values' => 1,
+      ),
+      'word' => array(
+        'title' => t('Contains any word'),
+        'short' => t('has word'),
+        'method' => 'op_word',
+        'values' => 1,
+      ),
+      'allwords' => array(
+        'title' => t('Contains all words'),
+        'short' => t('has all'),
+        'method' => 'op_word',
+        'values' => 1,
+      ),
+      'starts' => array(
+        'title' => t('Starts with'),
+        'short' => t('begins'),
+        'method' => 'op_starts',
+        'values' => 1,
+      ),
+      'not_starts' => array(
+        'title' => t('Does not start with'),
+        'short' => t('not_begins'),
+        'method' => 'op_not_starts',
+        'values' => 1,
+      ),
+      'ends' => array(
+        'title' => t('Ends with'),
+        'short' => t('ends'),
+        'method' => 'op_ends',
+        'values' => 1,
+      ),
+      'not_ends' => array(
+        'title' => t('Does not end with'),
+        'short' => t('not_ends'),
+        'method' => 'op_not_ends',
+        'values' => 1,
+      ),
+      'not' => array(
+        'title' => t('Does not contain'),
+        'short' => t('!has'),
+        'method' => 'op_not',
+        'values' => 1,
+      ),
+      'shorterthan' => array(
+        'title' => t('Length is shorter than'),
+        'short' => t('shorter than'),
+        'method' => 'op_shorter',
+        'values' => 1,
+      ),
+      'longerthan' => array(
+        'title' => t('Length is longer than'),
+        'short' => t('longer than'),
+        'method' => 'op_longer',
+        'values' => 1,
+      ),
+    );
+    // if the definition allows for the empty operator, add it.
+    if (!empty($this->definition['allow empty'])) {
+      $operators += array(
+        'empty' => array(
+          'title' => t('Is empty (NULL)'),
+          'method' => 'op_empty',
+          'short' => t('empty'),
+          'values' => 0,
+        ),
+        'not empty' => array(
+          'title' => t('Is not empty (NOT NULL)'),
+          'method' => 'op_empty',
+          'short' => t('not empty'),
+          'values' => 0,
+        ),
+      );
+    }
+    // Add regexp support for MySQL.
+    if (Database::getConnection()->databaseType() == 'mysql') {
+      $operators += array(
+        'regular_expression' => array(
+          'title' => t('Regular expression'),
+          'short' => t('regex'),
+          'method' => 'op_regex',
+          'values' => 1,
+        ),
+      );
+    }
+
+    return $operators;
+  }
+
+  /**
+   * Build strings from the operators() for 'select' options
+   */
+  function operator_options($which = 'title') {
+    $options = array();
+    foreach ($this->operators() as $id => $info) {
+      $options[$id] = $info[$which];
+    }
+
+    return $options;
+  }
+
+  function admin_summary() {
+    if ($this->is_a_group()) {
+      return t('grouped');
+    }
+    if (!empty($this->options['exposed'])) {
+      return t('exposed');
+    }
+
+    $options = $this->operator_options('short');
+    $output = '';
+    if (!empty($options[$this->operator])) {
+      $output = check_plain($options[$this->operator]);
+    }
+    if (in_array($this->operator, $this->operator_values(1))) {
+      $output .= ' ' . check_plain($this->value);
+    }
+    return $output;
+  }
+
+  function operator_values($values = 1) {
+    $options = array();
+    foreach ($this->operators() as $id => $info) {
+      if (isset($info['values']) && $info['values'] == $values) {
+        $options[] = $id;
+      }
+    }
+
+    return $options;
+  }
+
+  /**
+   * Provide a simple textfield for equality
+   */
+  function value_form(&$form, &$form_state) {
+    // We have to make some choices when creating this as an exposed
+    // filter form. For example, if the operator is locked and thus
+    // not rendered, we can't render dependencies; instead we only
+    // render the form items we need.
+    $which = 'all';
+    if (!empty($form['operator'])) {
+      $source = ($form['operator']['#type'] == 'radios') ? 'radio:options[operator]' : 'edit-options-operator';
+    }
+    if (!empty($form_state['exposed'])) {
+      $identifier = $this->options['expose']['identifier'];
+
+      if (empty($this->options['expose']['use_operator']) || empty($this->options['expose']['operator_id'])) {
+        // exposed and locked.
+        $which = in_array($this->operator, $this->operator_values(1)) ? 'value' : 'none';
+      }
+      else {
+        $source = 'edit-' . drupal_html_id($this->options['expose']['operator_id']);
+      }
+    }
+
+    if ($which == 'all' || $which == 'value') {
+      $form['value'] = array(
+        '#type' => 'textfield',
+        '#title' => t('Value'),
+        '#size' => 30,
+        '#default_value' => $this->value,
+      );
+      if (!empty($form_state['exposed']) && !isset($form_state['input'][$identifier])) {
+        $form_state['input'][$identifier] = $this->value;
+      }
+
+      if ($which == 'all') {
+        $form['value'] += array(
+          '#dependency' => array($source => $this->operator_values(1)),
+        );
+      }
+    }
+
+    if (!isset($form['value'])) {
+      // Ensure there is something in the 'value'.
+      $form['value'] = array(
+        '#type' => 'value',
+        '#value' => NULL
+      );
+    }
+  }
+
+  function operator() {
+    return $this->operator == '=' ? 'LIKE' : 'NOT LIKE';
+  }
+
+  /**
+   * Add this filter to the query.
+   *
+   * Due to the nature of fapi, the value and the operator have an unintended
+   * level of indirection. You will find them in $this->operator
+   * and $this->value respectively.
+   */
+  function query() {
+    $this->ensure_my_table();
+    $field = $this->real_field;
+
+    $info = $this->operators();
+    if (!empty($info[$this->operator]['method'])) {
+      $this->{$info[$this->operator]['method']}($field);
+    }
+  }
+
+  function op_equal($field) {
+    $this->query->add_where($this->options['group'], $field, $this->value, $this->operator());
+  }
+
+  function op_contains($field) {
+    $this->query->add_where($this->options['group'], $field, '%' . db_like($this->value) . '%', 'LIKE');
+  }
+
+  function op_word($field) {
+    $where = $this->operator == 'word' ? db_or() : db_and();
+
+    // Don't filter on empty strings.
+    if (empty($this->value)) {
+      return;
+    }
+
+    preg_match_all('/ (-?)("[^"]+"|[^" ]+)/i', ' ' . $this->value, $matches, PREG_SET_ORDER);
+    foreach ($matches as $match) {
+      $phrase = false;
+      // Strip off phrase quotes
+      if ($match[2]{0} == '"') {
+        $match[2] = substr($match[2], 1, -1);
+        $phrase = true;
+      }
+      $words = trim($match[2], ',?!();:-');
+      $words = $phrase ? array($words) : preg_split('/ /', $words, -1, PREG_SPLIT_NO_EMPTY);
+      foreach ($words as $word) {
+        $placeholder = $this->placeholder();
+        $where->condition($field, '%' . db_like(trim($word, " ,!?")) . '%', 'LIKE');
+      }
+    }
+
+    if (!$where) {
+      return;
+    }
+
+    // previously this was a call_user_func_array but that's unnecessary
+    // as views will unpack an array that is a single arg.
+    $this->query->add_where($this->options['group'], $where);
+  }
+
+  function op_starts($field) {
+    $this->query->add_where($this->options['group'], $field, db_like($this->value) . '%', 'LIKE');
+  }
+
+  function op_not_starts($field) {
+    $this->query->add_where($this->options['group'], $field, db_like($this->value) . '%', 'NOT LIKE');
+  }
+
+  function op_ends($field) {
+    $this->query->add_where($this->options['group'], $field, '%' . db_like($this->value), 'LIKE');
+  }
+
+  function op_not_ends($field) {
+    $this->query->add_where($this->options['group'], $field, '%' . db_like($this->value), 'NOT LIKE');
+  }
+
+  function op_not($field) {
+    $this->query->add_where($this->options['group'], $field, '%' . db_like($this->value) . '%', 'NOT LIKE');
+  }
+
+  function op_shorter($field) {
+    $placeholder = $this->placeholder();
+    $this->query->add_where_expression($this->options['group'], "LENGTH($field) < $placeholder", array($placeholder => $this->value));
+  }
+
+  function op_longer($field) {
+    $placeholder = $this->placeholder();
+    $this->query->add_where_expression($this->options['group'], "LENGTH($field) > $placeholder", array($placeholder => $this->value));
+  }
+
+  function op_regex($field) {
+    $this->query->add_where($this->options['group'], $field, $this->value, 'RLIKE');
+  }
+
+  function op_empty($field) {
+    if ($this->operator == 'empty') {
+      $operator = "IS NULL";
+    }
+    else {
+      $operator = "IS NOT NULL";
+    }
+
+    $this->query->add_where($this->options['group'], $field, NULL, $operator);
+  }
+
+}

+ 32 - 9
tripal_chado/api/modules/tripal_chado.feature.api.inc

@@ -1091,6 +1091,9 @@ function chado_get_aggregate_feature_relationships($feature_id, $substitute=1,
  *
  */
 function chado_get_feature_relationships($feature_id, $side = 'as_subject') {
+
+  $feature = chado_generate_var('feature', array('feature_id' => $feature_id));
+
   // get the relationships for this feature.  The query below is used for both
   // querying the object and subject relationships
   $sql = "
@@ -1119,20 +1122,24 @@ function chado_get_feature_relationships($feature_id, $side = 'as_subject') {
   // get the relationships
   $results = chado_query($sql, array(':feature_id' => $feature_id));
 
+  // Get the bundle for this feature type, if one exists.
+  $term = tripal_load_term_entity(array(
+    'vocabulary' => $feature->type_id->dbxref_id->db_id->name,
+    'accession' => $feature->type_id->dbxref_id->accession,
+  ));
+  $bundle = tripal_load_bundle_entity(array('term_id' => $term->id));
+
   // iterate through the relationships, put these in an array and add
   // in the Drupal node id if one exists
   $i=0;
-  $esql = "
-    SELECT entity_id
-    FROM {chado_entity}
-    WHERE record_id = :feature_id";
   $relationships = array();
   while ($rel = $results->fetchObject()) {
-    $entity = db_query($esql, array(':feature_id' => $rel->subject_id))->fetchObject();
+
+    $entity = tripal_chado_get_record_entity($bundle, $rel->subject_id);
     if ($entity) {
       $rel->subject_entity_id = $entity->entity_id;
     }
-    $entity = db_query($esql, array(':feature_id' => $rel->object_id))->fetchObject();
+    $entity = tripal_chado_get_record_entity($bundle, $rel->object_id);
     if ($entity) {
       $rel->object_entity_id = $entity->entity_id;
     }
@@ -1181,11 +1188,27 @@ function chado_get_featurelocs($feature_id, $side = 'as_parent', $aggregate = 1)
   $i=0;
   $featurelocs = array();
   while ($loc = $flresults->fetchObject()) {
-    // if a drupal node exists for this feature then add the nid to the
+    // if a drupal entity exists for this feature then add the nid to the
     // results object
 
-    $loc->feid = tripal_get_chado_entity_id('feature', $loc->feature_id);
-    $loc->seid = tripal_get_chado_entity_id('feature', $loc->src_feature_id);
+
+    // Get the bundle for this feature type, if one exists.
+    $ffeature = chado_generate_var('feature', array('feature_id' => $loc->feature_id));
+    $sfeature = chado_generate_var('feature', array('feature_id' => $loc->src_feature_id));
+    $fterm = tripal_load_term_entity(array(
+      'vocabulary' => $ffeature->type_id->dbxref_id->db_id->name,
+      'accession' => $ffeature->type_id->dbxref_id->accession,
+    ));
+    $sterm = tripal_load_term_entity(array(
+      'vocabulary' => $sfeature->type_id->dbxref_id->db_id->name,
+      'accession' => $sfeature->type_id->dbxref_id->accession,
+    ));
+    $fbundle = tripal_load_bundle_entity(array('term_id' => $fterm->id));
+    $sbundle = tripal_load_bundle_entity(array('term_id' => $sterm->id));
+
+    $loc->feid = tripal_chado_get_record_entity($fbundle, $loc->feature_id);
+    $loc->seid = tripal_chado_get_record_entity($sbundle, $loc->src_feature_id);
+
     // add the result to the array
     $featurelocs[$i++] = $loc;
   }

+ 133 - 89
tripal_chado/api/tripal_chado.api.inc

@@ -1,44 +1,5 @@
 <?php
 
-/**
- * Retrieves an entity that matches the given table and record id.
- *
- * @param $table
- *   The name of the Chado table.
- * @param $record_id
- *   The record's primary key in the table specified by $table.
- *
- * @return
- *   A chado_entity object.
- */
-function tripal_load_chado_entity($table, $record_id) {
-   $entity_id = db_select('chado_entity', 'ce')
-     ->fields('ce', array('entity_id'))
-     ->condition('ce.record_id', $record_id)
-     ->condition('ce.data_table', $table)
-     ->execute()
-     ->fetchField();
-   if ($entity_id) {
-     $entity = entity_load('TripalEntity', array($entity_id));
-     return reset($entity);
-   }
-   return NULL;
-}
-
-/**
- * Retrieves the entity ID using a record ID.
- *
- * @param unknown $data_table
- * @param unknown $record_id
- */
-function tripal_get_chado_entity_id($data_table, $record_id) {
-   return db_select('chado_entity', 'ce')
-     ->fields('ce', array('entity_id'))
-     ->condition('data_table', $data_table)
-     ->condition('record_id', $record_id)
-     ->execute()
-     ->fetchField();
-}
 
 /**
  * Publishes content in Chado as a new TripalEntity entity.
@@ -79,11 +40,25 @@ function tripal_chado_publish_records($values, $job_id = NULL) {
         array('@error' => 'The bundle name must be provided'));
     return FALSE;
   }
+  $chado_entity_table = tripal_chado_get_bundle_entity_table($bundle);
 
-  $table = $bundle->data_table;
-  $type_column = $bundle->type_column;
-  $type_linker_table = $bundle->type_linker_table;
-  $cvterm_id  = $bundle->type_id;
+
+  // Get the mapping of the bio data type to the Chado table.
+  $chado_bundle = db_select('chado_bundle', 'cb')
+    ->fields('cb')
+    ->condition('bundle_id', $bundle->id)
+    ->execute()
+    ->fetchObject();
+  if(!$chado_bundle) {
+    tripal_report_error('tripal_chado', TRIPAL_ERROR,
+        "Cannot find mapping of bundle to Chado tables. Could not publish record.");
+    return FALSE;
+  }
+
+  $table = $chado_bundle->data_table;
+  $type_column = $chado_bundle->type_column;
+  $type_linker_table = $chado_bundle->type_linker_table;
+  $cvterm_id  = $chado_bundle->type_id;
 
   // Get the table information for the Chado table.
   $table_schema = chado_get_schema($table);
@@ -94,8 +69,7 @@ function tripal_chado_publish_records($values, $job_id = NULL) {
   $select = "SELECT $pkey_field as record_id ";
   $from = "
     FROM {" . $table . "} T
-      LEFT JOIN public.chado_entity CE on CE.record_id = T.$pkey_field
-         AND CE.data_table = :table
+      LEFT JOIN public.$chado_entity_table CE on CE.record_id = T.$pkey_field
   ";
 
   // For migration of Tripal v2 nodes to entities we want to include the
@@ -105,7 +79,6 @@ function tripal_chado_publish_records($values, $job_id = NULL) {
     $from .= " INNER JOIN public.chado_$table CT ON CT.$pkey_field = T.$pkey_field";
   }
   $where = " WHERE CE.record_id IS NULL ";
-  $args[':table'] = $table;
 
   // Handle bundles that use a linker property table for identifying the type
   // of record to publish.
@@ -154,12 +127,6 @@ function tripal_chado_publish_records($values, $job_id = NULL) {
   $result = chado_query($sql, $args);
   $count = $result->fetchField();
 
-  //If this is the publication table remove one record, record_id = 1
-  // which is the null publication.
-  if($table == 'pub'){
-    $count = $count - 1;
-  }
-
   // calculate the interval for updates
   $interval = intval($count / 1000);
   if ($interval < 1) {
@@ -169,7 +136,7 @@ function tripal_chado_publish_records($values, $job_id = NULL) {
   // Perform the query.
   $sql = $select . $from . $where;
   $records = chado_query($sql, $args);
-  //$transaction = db_transaction();
+  $transaction = db_transaction();
 
   print "\nNOTE: publishing records is performed using a database transaction. \n" .
       "If the load fails or is terminated prematurely then the entire set of \n" .
@@ -179,46 +146,49 @@ function tripal_chado_publish_records($values, $job_id = NULL) {
   try {
     $i = 0;
     while($record = $records->fetchObject()) {
-      if(($table == 'pub' && $record->record_id == 1) || ($table == 'contact' && $record->record_id == 1)){
-        // Do not create the chado entity.
-      }
-      else {
-        // update the job status every interval
-        //if ($jobid and $i % $interval == 0) {
+
+      // update the job status every interval
+      //if ($jobid and $i % $interval == 0) {
         $complete = ($i / $count) * 33.33333333;
         //tripal_set_job_progress($jobid, intval($complete + 33.33333333));
         printf("%d of %d records. (%0.2f%%) Memory: %s bytes\r", $i, $count, $complete * 3, number_format(memory_get_usage()));
-        //}
-
-        // First save the tripal_entity record.
-        $record_id = $record->record_id;
-        $ec = entity_get_controller('TripalEntity');
-        $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,
-        ));
-
-        $entity = $entity->save();
-        if (!$entity) {
-          throw new Exception('Could not create entity.');
-        }
+      //}
+
+      // First save the tripal_entity record.
+      $record_id = $record->record_id;
+      $ec = entity_get_controller('TripalEntity');
+      $entity = $ec->create(array(
+        'bundle' => $bundle_name,
+        'term_id' => $bundle->term_id,
+        // Add in the Chaod details for when the hook_entity_create()
+        // is called and our tripal_cahdo_entity_create() implementation
+        // can deal with it.
+        'chado_record' => chado_generate_var($table, array($pkey_field => $record_id)),
+        'chado_record_id' => $record_id,
+      ));
+      $entity = $entity->save();
+      if (!$entity) {
+        throw new Exception('Could not create entity.');
+      }
 
-        // Next save the chado_entity record.
-        $entity_record = array(
-          'entity_id' => $entity->id,
-          'record_id' => $record_id,
-          'data_table' => $table,
-        );
-
-        // For the Tv2 to Tv3 migration we want to add the nid to the
-        // entity so we can associate the node with the entity.
-        if (property_exists($record, 'nid')) {
-          $entity_record['nid'] = $record->nid;
-        }
-        $success = drupal_write_record('chado_entity', $entity_record);
+      // Next save the chado entity record.
+      $entity_record = array(
+        'entity_id' => $entity->id,
+        'record_id' => $record_id,
+      );
+
+      // For the Tv2 to Tv3 migration we want to add the nid to the
+      // entity so we can associate the node with the entity.
+      if (property_exists($record, 'nid')) {
+        $entity_record['nid'] = $record->nid;
+      }
+      $result = db_insert($chado_entity_table)
+        ->fields($entity_record)
+        ->execute();
+      if(!$result){
+        throw new Exception('Could not create mapping of entity to Chado record.');
       }
+
       $i++;
     }
   }
@@ -346,4 +316,78 @@ function tripal_replace_chado_tokens($string, $record) {
   return $string;
 }
 
-
+/**
+ * Retrieve entity_id for a chado record
+ * 
+ * @param string $chado_table
+ *   the chado_table where the record is stored
+ * @param integer $record_id
+ *   the record_id which is the primary key of the chado_table
+ *   
+ * @return
+ *   Return an integer representing the entity_id or NULL if not found. The record is then 
+ *   accessible on the website through URL /bio_data/<entity_id>
+ */
+function tripal_get_chado_entity_id ($chado_table, $record_id) {
+  // To find the bundle_table, check if type_column is used for the chado_table
+  $type_column = 
+    db_select('chado_bundle', 'CB')
+    ->fields('CB', array('type_column'))
+    ->condition('data_table', $chado_table)
+    ->execute()
+    ->fetchField();
+  
+  // if there is a type_column, get bundle_id by specifying the data_table,  type_column, 
+  // and type_id
+  $bundle_id = NULL;
+  if ($type_column) {
+    $schema = chado_get_schema($chado_table);
+    $pkey = is_array($schema['primary key']) ? $schema['primary key'][0] : $schema['primary key'];
+    $type_id = NULL;
+    if (key_exists($type_column, $schema['fields'])) {
+      $type_id =
+        db_select('chado.' . $chado_table, 'C')
+        ->fields('C', array($type_column))
+        ->condition($pkey, $record_id)
+        ->execute()
+        ->fetchField();
+    }
+    if ($type_id) {
+      $bundle_id =
+        db_select('chado_bundle', 'CB')
+        ->fields('CB', array('bundle_id'))
+        ->condition('data_table', $chado_table)
+        ->condition('type_column', $type_column)
+        ->condition('type_id', $type_id)
+        ->execute()
+        ->fetchField();
+    }
+  }
+  // if type_column is not used, get bundle_id by specifying the data_table
+  else {
+    $bundle_id = 
+      db_select('chado_bundle', 'CB')
+      ->fields('CB', array('bundle_id'))
+      ->condition('data_table', $chado_table)
+      ->execute()
+      ->fetchField();
+  }
+  
+  // if bundle_id is found, find the bundle table name and return the entity_id
+  $entity_id = NULL;
+  if ($bundle_id) {
+    $table_name = 
+      db_select('tripal_bundle', 'TB')
+      ->fields('TB', array('name'))
+      ->condition('id', $bundle_id)
+      ->execute()
+      ->fetchField();
+    $entity_id = 
+      db_select('chado_' . $table_name, 'CBD')
+      ->fields('CBD', array('entity_id'))
+      ->condition('record_id', $record_id)
+      ->execute()
+      ->fetchField();
+  }  
+  return $entity_id;
+}

+ 46 - 0
tripal_chado/api/tripal_chado.entity.api.inc

@@ -0,0 +1,46 @@
+<?php
+/**
+ * A helper function to retreive the entity_id of a given record_id.
+ *
+ * @param $bundle
+ *   A bundle object (as retreieved from tripal_load_bundle_entity().
+ * @param $record_id
+ *   The ID of the record in the Chado table. The record must belong to
+ *   the table to which the bundle is associated in chado.
+ *
+ * @return
+ *   A database result object.
+ */
+function tripal_chado_get_record_entity($bundle, $record_id) {
+  if (!$bundle or !$record_id) {
+    return NULL;
+  }
+  $chado_entity_table = tripal_chado_get_bundle_entity_table($bundle);
+  return db_select($chado_entity_table, 'CE')
+    ->condition('CE.record_id', $record_id)
+    ->execute()
+    ->fetchObject();
+}
+
+/**
+ * A helper function that provides the Chado mapping table for the bundle.
+ *
+ * The tripal_chado module must map entities to their corresponding record
+ * in Chado.  Each bundl type has their own table for this mapping.  This
+ * function provides the name of the table given the bundle name.  A mapping
+ * table will only map to one table in Chado so the record_id's of the mapping
+ * table should always be unique.
+ *
+ * @param $bundle
+ *   A bundle object (as retreieved from tripal_load_bundle_entity().
+ *
+ * @return
+ *   The name of the mapping table that Chado uses to map entities to records.
+ */
+function tripal_chado_get_bundle_entity_table($bundle) {
+  if (!$bundle) {
+    return '';
+  }
+  return 'chado_' . $bundle->name;
+}
+

+ 18 - 9
tripal_chado/api/tripal_chado.variables.api.inc

@@ -309,15 +309,24 @@ function chado_generate_var($table, $values, $base_options = array()) {
         }
       }
 
-      // Check to see if the current table maps to an entity
-      $entity_id = db_select('chado_entity', 'ce')
-        ->fields('ce', array('entity_id'))
-        ->condition('data_table', $table)
-        ->condition('record_id', $object->{$table_primary_key})
-        ->execute()
-        ->fetchField();
-      if ($entity_id) {
-        $object->entity_id = $entity_id;
+      // Check to see if the current record maps to an entity.  Because
+      // multiple bundles can map to the same table we have to check
+      // all bundles for this table.
+      $bundles = db_select('chado_bundle', 'cb');
+      $bundles->fields('tb', array('name'));
+      $bundles->join('tripal_bundle', 'tb', 'tb.id = cb.bundle_id');
+      $bundles->condition('cb.data_table', $table);
+      $bundles->execute();
+      foreach ($bundles as $bundle) {
+        $cbundle_table = tripal_chado_get_bundle_entity_table($bundle);
+        $record = $db_select($cbundle_table, 'ce')
+          ->fields('ce', 'entity_id')
+          ->condition('record_id', $object->{$table_primary_key})
+          ->execute()
+          ->fetchObject();
+        if ($record) {
+          $object->entity_id = $record->entity_id;
+        }
       }
 
       // remove any fields where criteria needs to be evalulated---------------------------------------

+ 6 - 23
tripal_chado/includes/TripalFields/ChadoField.inc

@@ -48,27 +48,15 @@ class ChadoField extends TripalField {
   public static $module = 'tripal_chado';
 
   /**
-   * Used to filter records that match a given condition.
+   * @see TripalField::query()
+   *
+   * In addition to the rules to follow for the TripalField::query function
+   * these should also be followed for the ChadoField::query implementation.
    *
-   * Entities can be filtered using the fields.  This function should be
-   * implemented if the field  supports filtering.  To provide filtering,
-   * the $query object should be updated to including any joins and
-   * conditions necessary. The following rules should be followed when
-   * implementing this function:
-   * - Try to implement a filter for every element of the 'value' array
-   *   returned by the load() function.
-   * - However, avoid making filteres for non-indexed database columns.
    * - When giving alias to joined tables be sure to use aliases that are
    *   unique to avoid conflicts with other fields.
    * - When joining with the base table its alias is 'base'.
-   * - This function should never set the fields that should be returned
-   *   nor ordering or group by.
    * - You may join to materialized views if need be to help speed queries.
-   *
-   * @param $query
-   *   A SelectQuery object.
-   * @param $condition
-   *   The field specific condition as set in the TripalFieldQuery object.
    */
   public function query($query, $condition) {
     // If we are here it is because the child class did not implement the
@@ -94,13 +82,7 @@ class ChadoField extends TripalField {
   }
 
   /**
-   * Used to sort records that have been filtered.
-   *
-   * @param $query
-   *   A SelectQuery object.
-   * @param $order
-   *   The field ordering as set in the TripalFieldQuery object.  This function
-   *   should handle the ordering request as specified by this object.
+   * @see TripalField::queryOrder()
    */
   public function queryOrder($query, $order) {
 
@@ -127,4 +109,5 @@ class ChadoField extends TripalField {
     );
     return $element;
   }
+
 }

+ 1 - 1
tripal_chado/includes/TripalFields/obi__organism/obi__organism.inc

@@ -6,7 +6,7 @@ class obi__organism extends ChadoField {
   public static $default_label = 'Organism';
 
   // The default description for this field.
-  public static $description = 'The organism to which this resource is sssociated.';
+  public static $description = 'The organism to which this resource is associated.';
 
   // Provide a list of instance specific settings. These can be access within
   // the instanceSettingsForm.  When the instanceSettingsForm is submitted

+ 1 - 1
tripal_chado/includes/TripalFields/sbo__relationship/sbo__relationship_formatter.inc

@@ -119,7 +119,7 @@ class sbo__relationship_formatter extends ChadoFieldFormatter {
 
     $table = array(
       'header' => $headers,
-      'rows' => $chunks[$current_page],
+      'rows' => $current_page ? $chunks[$current_page] : array(),
       'attributes' => array(
         'id' => 'sbo--relationship-table',
       ),

+ 1 - 3
tripal_chado/includes/TripalFields/schema__publication/schema__publication_formatter.inc

@@ -51,9 +51,7 @@ class schema__publication_formatter extends ChadoFieldFormatter {
       );
       $list = theme_item_list($list);
     }
-    else {
-      $list = $list_items[0];
-    }
+
     $element[0] = array(
       '#type' => 'markup',
       '#markup' => $list,

+ 1 - 1
tripal_chado/includes/TripalFields/so__transcript/so__transcript.inc

@@ -112,7 +112,7 @@ class so__transcript extends ChadoField {
         'data:0842' => $transcript->uniquename,
         'SO:0000735' => $loc,
       );
-      $entity_id = tripal_get_chado_entity_id($field_table, $record->feature_id);
+      $entity_id = tripal_chado_get_record_entity($entity->bundle, $record_id);
       if ($entity_id) {
          $entity->{$field_name}['und'][$i]['value']['entity'] = 'TripalEntity:' . $entity_id;
        }

+ 71 - 1
tripal_chado/includes/tripal_chado.bundle.inc

@@ -58,4 +58,74 @@ function tripal_chado_bundle_create($bundle, $storage_args) {
       throw new Exception('Cannot create content type. Problem associating type with Chado.');
     }
   }
-}
+
+  tripal_chado_create_bundle_table($bundle);
+}
+
+
+/**
+ * Creates the table that tripal_chado uses to link Chado records with entities.
+ *
+ * @param $bundle
+ *   A bundle object (as retreieved from tripal_load_bundle_entity().
+ */
+function tripal_chado_create_bundle_table($bundle) {
+
+  // Now create the table where the bundle's records will go
+  $schema = array(
+    'description' => 'The linker table that associates TripalEntities with Chado records for entities of type ' . $bundle->name . '.',
+    'fields' => array(
+      'mapping_id' => array(
+        'type' => 'serial',
+        'not null' => TRUE
+      ),
+      'entity_id' => array(
+        'description' => 'The unique entity id.',
+        'type' => 'int',
+        'not null' => TRUE,
+      ),
+      'record_id' => array(
+        'description' => 'The unique numerical identifier for the record that this entity is associated with (e.g. feature_id, stock_id, library_id, etc.).',
+        'type' => 'int',
+        'not null' => TRUE,
+      ),
+      'nid' => array(
+        'description' => 'Optional. For linking nid to the entity when migrating Tripal v2 content',
+        'type' => 'int',
+      )
+    ),
+    'primary key' => array(
+      'mapping_id',
+    ),
+    'indexes' => array(
+      'record_id' => array('record_id'),
+      'entity_id' => array('entity_id'),
+      'nid' => array('nid'),
+    ),
+    'unique keys' => array(
+      'table_record' => array('record_id'),
+      'entity_id' => array('entity_id'),
+    ),
+  );
+  $chado_entity_table = tripal_chado_get_bundle_entity_table($bundle);
+  db_create_table($chado_entity_table, $schema);
+}
+
+/**
+ * Implements hook_bundle_delete().
+ *
+ */
+function tripal_chado_bundle_delete($bundle) {
+
+  // Remove the entries in the appropriate chado entity table
+  // and tripal_entity
+  $chado_entity_table = tripal_chado_get_bundle_entity_table($bundle);
+  $sql = "DROP TABLE {$chado_entity_table}";
+  db_query($sql);
+
+  // Remove the entry from the chado_bundle table.
+  db_delete('chado_bundle')
+    ->condition('bundle_id', $bundle->id)
+    ->execute();
+}
+

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

@@ -87,7 +87,8 @@ function tripal_chado_entity_load($entities, $type) {
         $entity->chado_table = $bundle->data_table;
         $entity->chado_column = $bundle->type_column;
 
-        $chado_entity = db_select('chado_entity' ,'ce')
+        $chado_entity_table = tripal_chado_get_bundle_entity_table($bundle);
+        $chado_entity = db_select($chado_entity_table, 'ce')
           ->fields('ce')
           ->condition('ce.entity_id', $entity->id)
           ->execute()
@@ -124,7 +125,9 @@ function tripal_chado_entity_update($entity, $type) {
  * Implements hook_entity_delete().
  */
 function tripal_chado_entity_delete($entity, $type) {
+  if ($type == 'TripalEntity') {
 
+  }
 }
 
 /**

+ 10 - 10
tripal_chado/includes/tripal_chado.field_storage.inc

@@ -57,14 +57,13 @@ function tripal_chado_field_storage_write($entity_type, $entity, $op, $fields) {
 
   // If this is an insert then add the chado_entity record.
   if ($op == FIELD_STORAGE_INSERT) {
-    // 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.
+    // Add the record to the proper chado entity table
+    $chado_entity_table = tripal_chado_get_bundle_entity_table($bundle);
     $record = array(
       'entity_id' => $entity->id,
       'record_id' => $base_record_id,
-      'data_table' => $base_table,
     );
-    $success = drupal_write_record('chado_entity', $record);
+    $success = drupal_write_record($chado_entity_table, $record);
     if (!$success) {
       drupal_set_message('Unable to insert new Chado entity.', 'error');
     }
@@ -201,8 +200,9 @@ function tripal_chado_field_storage_load($entity_type, $entities, $age,
       $base_table = $bundle->data_table;
       $type_field = $bundle->type_column;
 
-      // Get the base table and record id for the fields of this entity.
-      $details = db_select('chado_entity', 'ce')
+      // Get the record id for the fields of this entity.
+      $chado_entity_table = tripal_chado_get_bundle_entity_table($bundle);
+      $details = db_select($chado_entity_table, 'ce')
         ->fields('ce')
         ->condition('entity_id', $entity->id)
         ->execute()
@@ -415,7 +415,7 @@ function tripal_chado_field_storage_write_merge_fields($fields, $entity_type, $e
  * Implements hook_field_storage_query().
  */
 function tripal_chado_field_storage_query($query) {
-
+dpm($query);
   // Initialize the result array.
   $result = array(
     'TripalEntity' => array()
@@ -501,12 +501,12 @@ function tripal_chado_field_storage_query($query) {
     }
   } // end foreach ($query->fieldConditions as $index => $condition) {
 
-  // Now join with the chado_entity table to get published records only.
-  $cquery->join('chado_entity', 'CE', "CE.record_id = base.$pkey");
+  // Now join with the chado entity table to get published records only.
+  $chado_entity_table = tripal_chado_get_bundle_entity_table($bundle);
+  $cquery->join($chado_entity_table, 'CE', "CE.record_id = base.$pkey");
   $cquery->join('tripal_entity', 'TE', "CE.entity_id = TE.id");
   $cquery->fields('CE', array('entity_id'));
   $cquery->fields('TE', array('bundle'));
-  $cquery->condition('CE.data_table', $data_table);
   if (array_key_exists('start', $query->range)) {
     $cquery->range($query->range['start'], $query->range['length']);
   }

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

@@ -1,7 +1,7 @@
 <?php
 
 /**
- * Implements hook_field_create_info().
+ * Implements hook_bundle_create_fields().
  *
  * This is a Tripal defined hook that supports integration with the
  * TripalEntity field.
@@ -103,6 +103,7 @@ function tripal_chado_bundle_create_fields_base(&$info, $details, $entity_type,
       'locked' => FALSE,
       'storage' => array(
         'type' => 'field_chado_storage',
+        'sql' => array(),
       ),
     );
 
@@ -162,8 +163,6 @@ function tripal_chado_bundle_create_fields_base(&$info, $details, $entity_type,
       $base_info['settings']['text_processing'] = 0;
     }
 
-
-
     $info[$field_name] = $base_info;
   }
 }
@@ -1261,7 +1260,7 @@ function tripal_chado_bundle_create_instances_linker(&$info, $entity_type, $bund
       'field_name' =>  $field_name,
       'entity_type' => $entity_type,
       'bundle' => $bundle->name,
-      'label' => 'Database Cross Reference',
+      'label' => 'Cross Reference',
       'description' => 'The IDs where this record may be available in other external online databases.',
       'required' => FALSE,
       'settings' => array(
@@ -1681,7 +1680,7 @@ function tripal_chado_bundle_create_instances_linker(&$info, $entity_type, $bund
  *
  * A priviledged user has the ability to add new fields to the bundle. The
  * chado_linker__prop and chado_linker__cvterm fields are allowed to be
- * added dynamically by the user.  But, Drupal doesn't know whot to deal with
+ * added dynamically by the user.  But, Drupal doesn't know how to deal with
  * it, so this function is called for any field attached to a TripalEntity
  * bundle type. Any fields whose TripalField::$module argument is set to
  * 'tripal_chado' and that can be added dynamically will result in a call

+ 0 - 1684
tripal_chado/includes/tripal_chado.fields.inc.orig

@@ -1,1684 +0,0 @@
-<?php
-
-/**
- * Implements hook_field_create_info().
- *
- * This is a Tripal defined hook that supports integration with the
- * TripalEntity field.
- */
-function tripal_chado_bundle_create_fields($entity_type, $bundle, $chado_bundle) {
-
-  // Get the details about the mapping of this bundle to the Chado table:
-  $details = array(
-    'chado_cvterm_id' => $chado_bundle['type_id'],
-    'chado_table' => $chado_bundle['data_table'],
-    'chado_type_table' => $chado_bundle['type_linker_table'],
-    'chado_type_column' => $chado_bundle['type_column'],
-  );
-
-  $info = array();
-
-  // Create the fields for each column in the table.
-  tripal_chado_bundle_create_fields_base($info, $details, $entity_type, $bundle);
-
-  // Create custom fields.
-  tripal_chado_bundle_create_fields_custom($info, $details, $entity_type, $bundle);
-
-  // Create fields for linking tables.
-  tripal_chado_bundle_create_fields_linker($info, $details, $entity_type, $bundle);
-
-  foreach ($info as $field_name => $details) {
-    $field_type = $details['type'];
-
-    // If the field already exists then skip it.
-    $field = field_info_field($details['field_name']);
-    if ($field) {
-      continue;
-    }
-
-    // Create the field.
-    $field = field_create_field($details);
-    if (!$field) {
-      tripal_set_message(t("Could not create new field: %field.",
-          array('%field' =>  $details['field_name'])), TRIPAL_ERROR);
-    }
-  }
-}
-/**
- *
- * @param unknown $details
- */
-function tripal_chado_bundle_create_fields_base(&$info, $details, $entity_type, $bundle) {
-
-  $table_name = $details['chado_table'];
-  $type_table = $details['chado_type_table'];
-  $type_field = $details['chado_type_column'];
-  $cvterm_id  = $details['chado_cvterm_id'];
-
-  // Iterate through the columns of the table and see if fields have been
-  // created for each one. If not, then create them.
-  $schema = chado_get_schema($table_name);
-  if (!$schema) {
-    return;
-  }
-
-  $pkey = $schema['primary key'][0];
-
-
-  // Get the list of columns for this table and create a new field for each one.
-  $columns = $schema['fields'];
-  foreach ($columns as $column_name => $details) {
-    // Don't create base fields for the primary key and the type_id field.
-    if ($column_name == $pkey or $column_name == $type_field) {
-      continue;
-    }
-    $cvterm = tripal_get_chado_semweb_term($table_name, $column_name, array('return_object' => TRUE));
-    if (!$cvterm) {
-      tripal_report_error('tripal', TRIPAL_ERROR,
-        'Cannot create field for "%table_name.%column_name". Missing an appropriate vocabulary term',
-         array('%table_name' => $table_name, '%column_name' => $column_name));
-      drupal_set_message(t('Cannot create field for "%table_name.%column_name". Missing an appropriate vocabulary term',
-        array('%table_name' => $table_name, '%column_name' => $column_name)), 'error');
-      continue;
-    }
-    $field_name = strtolower($cvterm->dbxref_id->db_id->name . '__' . preg_replace('/ /', '_', $cvterm->name));
-
-    // Skip the primary key field.
-    if ($column_name == $schema['primary key'][0]) {
-      continue;
-    }
-
-    // Skip the type field.
-    if ($table_name == $type_table and $column_name == $type_field) {
-      continue;
-    }
-
-    // Set some defaults for the field.
-    $base_info = array(
-      'field_name' => $field_name,
-      'type' => '',
-      'cardinality' => 1,
-      'locked' => TRUE,
-      'storage' => array(
-        'type' => 'field_chado_storage',
-      ),
-    );
-
-    // Alter the field info array depending on the column details.
-    switch($details['type']) {
-      case 'char':
-        $base_info['type'] = 'text';
-        $base_info['settings']['max_length'] = $details['length'];
-        break;
-      case 'varchar':
-        $base_info['type'] = 'text';
-        $base_info['settings']['max_length'] = $details['length'];
-        break;
-      case 'text':
-        $base_info['type'] = 'text';
-        $base_info['settings']['max_length'] = 17179869184;
-        $base_info['settings']['text_processing'] = 1;
-        break;
-      case 'blob':
-        // not sure how to support a blob field.
-        continue;
-        break;
-      case 'int':
-        $base_info['type'] = 'number_integer';
-        break;
-      case 'float':
-        $base_info['type'] = 'number_float';
-        $base_info['settings']['precision'] = 10;
-        $base_info['settings']['scale'] = 2;
-        $base_info['settings']['decimal_separator'] = '.';
-        break;
-      case 'numeric':
-        $base_info['type'] = 'number_decimal';
-        break;
-      case 'serial':
-        // Serial fields are most likely not needed as a field.
-        break;
-      case 'boolean':
-        $base_info['type'] = 'list_boolean';
-        $base_info['settings']['allowed_values'] = array(0 => "No", 1 => "Yes");
-        break;
-      case 'datetime':
-        // Use the Drupal Date and Date API to create the field/widget
-        $base_info['type'] = 'datetime';
-        break;
-    }
-
-    // Set some default semantic web information
-    if ($column_name == 'uniquename') {
-      $base_info['settings']['text_processing'] = 0;
-    }
-    //
-    // PUB TABLE
-    //
-    elseif ($table_name == 'pub' and $column_name == 'uniquename') {
-      $base_info['type'] = 'text';
-      $base_info['settings']['text_processing'] = 0;
-    }
-
-    //
-    // ANALYSIS TABLE
-    //
-    elseif ($table_name == 'analysis' and $column_name == 'sourceuri') {
-      $base_info['type'] = 'text';
-      $base_info['settings']['text_processing'] = 0;
-    }
-
-    $info[$field_name] = $base_info;
-  }
-}
-
-/**
- *
- * @param unknown $details
- */
-function tripal_chado_bundle_create_fields_custom(&$info, $details, $entity_type, $bundle) {
-  $table_name = $details['chado_table'];
-  $type_table = $details['chado_type_table'];
-  $type_field = $details['chado_type_column'];
-  $cvterm_id  = $details['chado_cvterm_id'];
-
-  $schema = chado_get_schema($table_name);
-
-  // BASE ORGANISM_ID
-  if ($table_name != 'organism' and
-      array_key_exists('organism_id', $schema['fields'])) {
-    $field_name = 'obi__organism';
-    $field_type = 'obi__organism';
-    $info[$field_name] = array(
-      'field_name' => $field_name,
-      'type' => $field_type,
-      'cardinality' => 1,
-      'locked' => TRUE,
-      'storage' => array(
-        'type' => 'field_chado_storage',
-      ),
-    );
-  }
-
-  // BASE DBXREF
-  if (array_key_exists('dbxref_id', $schema['fields'])) {
-    $field_name = 'data__accession';
-    $field_type = 'data__accession';
-    $info[$field_name] = array(
-      'field_name' => $field_name,
-      'type' => $field_type,
-      'cardinality' => 1,
-      'locked' => TRUE,
-      'storage' => array(
-        'type' => 'field_chado_storage',
-      ),
-    );
-  }
-
-  // FEATURE MD5CHECKSUM
-  if ($table_name == 'feature') {
-    $field_name = 'data__sequence_checksum';
-    $field_type = 'data__sequence_checksum';
-    $info[$field_name] = array(
-      'field_name' => $field_name,
-      'type' => $field_type,
-      'cardinality' => 1,
-      'locked' => TRUE,
-      'storage' => array(
-        'type' => 'field_chado_storage',
-      ),
-    );
-  }
-
-  // FEATURE RESIDUES
-  if ($table_name == 'feature') {
-    $field_name = 'data__sequence';
-    $field_type = 'data__sequence';
-    $info[$field_name] = array(
-      'field_name' => $field_name,
-      'type' => $field_type,
-      'cardinality' => 1,
-      'locked' => TRUE,
-      'storage' => array(
-        'type' => 'field_chado_storage',
-      ),
-    );
-  }
-
-  // FEATURE SEQLEN
-  if ($table_name == 'feature') {
-    $field_name = 'data__sequence_length';
-    $field_type = 'data__sequence_length';
-    $info[$field_name] = array(
-      'field_name' => $field_name,
-      'type' => $field_type,
-      'cardinality' => 1,
-      'locked' => TRUE,
-      'storage' => array(
-        'type' => 'field_chado_storage',
-      ),
-    );
-  }
-
-  // GENE TRANSCRIPTS
-  $rel_table = $table_name . '_relationship';
-  if (chado_table_exists($rel_table) and $bundle->label == 'gene') {
-    $field_name = 'so__transcript';
-    $field_type = 'so__transcript';
-    $info[$field_name] = array(
-      'field_name' => $field_name,
-      'type' => $field_type,
-      'cardinality' => FIELD_CARDINALITY_UNLIMITED,
-      'locked' => TRUE,
-      'storage' => array(
-        'type' => 'field_chado_storage',
-      ),
-    );
-  }
-
-  // ORGANISM TYPE_ID
-//   if ($table_name == 'organism' and array_key_exists('type_id', $schema['fields'])) {
-//     $field_name = 'taxarank__infraspecific_taxon';
-//     $field_type = 'taxarank__infraspecific_taxon';
-//     $info[$field_name] = array(
-//       'field_name' => $field_name,
-//       'type' => $field_type,
-//       'cardinality' => 1,
-//       'locked' => TRUE,
-//       'storage' => array(
-//         'type' => 'field_chado_storage',
-//       ),
-//       'settings' => array(
-//       ),
-//     );
-//   }
-}
-
-/**
- *
- * @param unknown $details
- */
-function tripal_chado_bundle_create_fields_linker(&$info, $details, $entity_type, $bundle) {
-
-  $table_name = $details['chado_table'];
-  $type_table = $details['chado_type_table'];
-  $type_field = $details['chado_type_column'];
-  $cvterm_id  = $details['chado_cvterm_id'];
-
-  // CONTACTS
-  $contact_table = $table_name . '_contact';
-  if (chado_table_exists($contact_table)) {
-    $schema = chado_get_schema($contact_table);
-    $pkey = $schema['primary key'][0];
-    $field_name = $table_name . '_contact';
-    $field_type = 'chado_linker__contact';
-    $info[$field_name] = array(
-      'field_name' => $field_name,
-      'type' => $field_type,
-      'cardinality' => 1,
-      'locked' => TRUE,
-      'storage' => array(
-        'type' => 'field_chado_storage',
-      ),
-    );
-  }
-
-  // DBXREF
-  $dbxref_table = $table_name . '_dbxref';
-  if (chado_table_exists($dbxref_table)) {
-    $field_name = 'sbo__database_cross_reference';
-    $field_type = 'sbo__database_cross_reference';
-    $info[$field_name] = array(
-      'field_name' =>  $field_name,
-      'type' => $field_type,
-      'cardinality' => FIELD_CARDINALITY_UNLIMITED,
-      'locked' => TRUE,
-      'storage' => array(
-        'type' => 'field_chado_storage',
-      ),
-    );
-  }
-
-  // EXPRESSION
-  $expression_table = $table_name . '_expression';
-  if (chado_table_exists($expression_table)) {
-    $field_name = 'go__gene_expression';
-    $field_type = 'go__gene_expression';
-    $info[$field_name] = array(
-      'field_name' => $field_name,
-      'type' => $field_type,
-      'cardinality' => FIELD_CARDINALITY_UNLIMITED,
-      'locked' => TRUE,
-      'storage' => array(
-        'type' => 'field_chado_storage',
-      ),
-    );
-  }
-
-  // FEATURELOC
-  if ($table_name == 'feature') {
-    $field_name = 'data__sequence_coordinates';
-    $field_type = 'data__sequence_coordinates';
-    $info[$field_name] = array(
-      'field_name' => $field_name,
-      'type' => $field_type,
-      'cardinality' => FIELD_CARDINALITY_UNLIMITED,
-      'locked' => TRUE,
-      'storage' => array(
-        'type' => 'field_chado_storage',
-      ),
-    );
-  }
-
-  // FEATUREPOS
-  if ($table_name == 'feature') {
-    $field_name = 'ogi__location_on_map';
-    $field_type = 'ogi__location_on_map';
-    $info[$field_name] = array(
-      'field_name' => $field_name,
-      'type' => $field_type,
-      'cardinality' => FIELD_CARDINALITY_UNLIMITED,
-      'locked' => TRUE,
-      'storage' => array(
-        'type' => 'field_chado_storage',
-      ),
-    );
-  }
-
-  // GENOTYPE
-  $genotype_table = $table_name . '_genotype';
-  if (chado_table_exists($genotype_table)) {
-    $field_name = 'so__genotype';
-    $field_type = 'so__genotype';
-    $info[$field_name] = array(
-      'field_name' => $field_name,
-      'type' => $field_type,
-      'cardinality' => FIELD_CARDINALITY_UNLIMITED,
-      'locked' => TRUE,
-      'storage' => array(
-        'type' => 'field_chado_storage',
-      ),
-    );
-  }
-
-  // PHENOTYPE
-  $phenotype_table = $table_name . '_phenotype';
-  if (chado_table_exists($phenotype_table)) {
-    $field_name = 'sbo__phenotype';
-    $field_type = 'sbo__phenotype';
-    $info[$field_name] = array(
-      'field_name' => $field_name,
-      'type' => $field_type,
-      'cardinality' => FIELD_CARDINALITY_UNLIMITED,
-      'locked' => TRUE,
-      'storage' => array(
-        'type' => 'field_chado_storage',
-      ),
-    );
-  }
-
-  // PROPERTIES
-  $prop_table = $table_name . 'prop';
-  if (chado_table_exists($prop_table)) {
-    // Get the list of existing property types for this table.
-    $sql = 'SELECT DISTINCT type_id FROM {' . $prop_table . '}';
-    $props = chado_query($sql);
-    while ($prop = $props->fetchObject()) {
-      $term = chado_generate_var('cvterm', array('cvterm_id' => $prop->type_id));
-      $field_name = strtolower(preg_replace('/[^\w]/','_', $term->dbxref_id->db_id->name . '__' . $term->name));
-      $field_type = 'chado_linker__prop';
-      $info[$field_name] = array(
-        'field_name' => $field_name,
-        'type' => $field_type,
-        'cardinality' => 1,
-        'locked' => FALSE,
-        'storage' => array(
-          'type' => 'field_chado_storage',
-        ),
-      );
-    }
-  }
-
-  // PUBLICATIONS
-  $pub_table = $table_name . '_pub';
-  if (chado_table_exists($pub_table)) {
-    $field_name = 'schema__publication';
-    $field_type = 'schema__publication';
-    $info[$field_name] =  array(
-      'field_name' => $field_name,
-      'type' => $field_type,
-      'cardinality' => FIELD_CARDINALITY_UNLIMITED,
-      'locked' => TRUE,
-      'storage' => array(
-        'type' => 'field_chado_storage',
-      ),
-    );
-  }
-
-  // RELATIONSHIPS
-  // If the linker table does not exists then we don't want to add attach.
-  $rel_table = $table_name . '_relationship';
-  if (chado_table_exists($rel_table)) {
-    $field_name = 'sbo__relationship';
-    $field_type = 'sbo__relationship';
-    $info[$field_name] =  array(
-      'field_name' => $field_name,
-      'type' => $field_type,
-      'cardinality' => FIELD_CARDINALITY_UNLIMITED,
-      'locked' => TRUE,
-      'storage' => array(
-        'type' => 'field_chado_storage',
-      ),
-    );
-  }
-
-  // SYNONYMS
-  $syn_table = $table_name . '_synonym';
-  if (chado_table_exists($syn_table)) {
-    $field_name = 'schema__alternate_name';
-    $field_type = 'schema__alternate_name';
-    $info[$field_name] =  array(
-      'field_name' => $field_name,
-      'type' => $field_type,
-      'cardinality' => FIELD_CARDINALITY_UNLIMITED,
-      'locked' => TRUE,
-      'storage' => array(
-        'type' => 'field_chado_storage',
-      ),
-      'settings' => array(
-      ),
-    );
-  }
-}
-
-/**
- * Impelments hook_create_tripalfield_instance().
- *
- * This is a Tripal defined hook that supports integration with the
- * TripalEntity field.
- */
-function tripal_chado_bundle_create_instances($entity_type, $bundle, $chado_bundle) {
-
-  $details = array(
-    'chado_cvterm_id' => $chado_bundle['type_id'],
-    'chado_table' => $chado_bundle['data_table'],
-    'chado_type_table' => $chado_bundle['type_linker_table'],
-    'chado_type_column' => $chado_bundle['type_column'],
-  );
-
-  tripal_chado_bundle_create_instances_base($info, $entity_type, $bundle, $details);
-  tripal_chado_bundle_create_instances_custom($info, $entity_type, $bundle, $details);
-  tripal_chado_bundle_create_instances_linker($info, $entity_type, $bundle, $details);
-
-  foreach ($info as $field_name => $details) {
-    // If the field is already attached to this bundle then skip it.
-    $field = field_info_field($details['field_name']);
-    if ($field and array_key_exists('bundles', $field) and
-        array_key_exists('TripalEntity', $field['bundles']) and
-        in_array($bundle->name, $field['bundles']['TripalEntity'])) {
-      continue;
-    }
-    // Create the field instance.
-    $instance = field_create_instance($details);
-  }
-
-}
-/**
- * Helper function for the hook_create_tripalfield_instance().
- *
- * Add the field instances that corresond to the columns of the base table.
- *
- * @param $entity_type
- * @param $bundle
- * @param $details
- */
-function tripal_chado_bundle_create_instances_base(&$info, $entity_type, $bundle, $details) {
-  $fields = array();
-
-  // Get Chado information
-  $table_name = $details['chado_table'];
-  $type_table = $details['chado_type_table'];
-  $type_field = $details['chado_type_column'];
-  $cvterm_id  = $details['chado_cvterm_id'];
-
-  // Iterate through the columns of the table and see if fields have been
-  // created for each one. If not, then create them.
-  $schema = chado_get_schema($table_name);
-  if (!$schema) {
-    return;
-  }
-
-  $pkey = $schema['primary key'][0];
-
-  $columns = $schema['fields'];
-  foreach ($columns as $column_name => $details) {
-    // Don't create base fields for the primary key and the type_id field.
-    if ($column_name == $pkey or $column_name == $type_field) {
-      continue;
-    }
-    $cvterm = tripal_get_chado_semweb_term($table_name, $column_name, array('return_object' => TRUE));
-    if (!$cvterm) {
-      // We already provided an error when creating the base field.  So
-      // don't create another one here.
-      continue;
-    }
-
-    $field_name = strtolower($cvterm->dbxref_id->db_id->name . '__' . preg_replace('/ /', '_', $cvterm->name));
-
-    // Skip the primary key field.
-    if ($column_name == $schema['primary key'][0]) {
-      continue;
-    }
-
-    // Skip the type field.
-    if ($table_name == $type_table and $column_name == $type_field) {
-      continue;
-    }
-
-    $base_info =  array(
-      'field_name' => $field_name,
-      'entity_type' => 'TripalEntity',
-      'bundle' => $bundle->name,
-      'label' => ucwords(preg_replace('/_/', ' ', $column_name)),
-      'description' => '',
-      'required' => FALSE,
-      'settings' => array(
-        'auto_attach' => TRUE,
-        'term_vocabulary' => $cvterm->dbxref_id->db_id->name,
-        'term_name' => $cvterm->name,
-        'term_accession' => $cvterm->dbxref_id->accession,
-        'chado_table' => $table_name,
-        'chado_column' => $column_name,
-        'base_table' => $table_name,
-      ),
-      'widget' => array(
-        'settings' => array(
-          'display_label' => 1,
-        ),
-      ),
-      'display' => array(
-        'default' => array(
-          'label' => 'inline',
-          'settings' => array(),
-        ),
-      ),
-    );
-
-    // Determine if the field is required.
-    if (array_key_exists('not null', $details) and $details['not null'] === TRUE) {
-      $base_info['required'] = TRUE;
-    }
-
-    // Alter the field info array depending on the column details.
-    switch($details['type']) {
-      case 'char':
-        $base_info['widget']['type'] = 'text_textfield';
-        break;
-      case 'varchar':
-        $base_info['widget']['type'] = 'text_textfield';
-        break;
-      case 'text':
-        $base_info['widget']['type'] = 'text_textarea';
-        $base_info['widget']['settings']['format'] = filter_default_format();
-        break;
-      case 'blob':
-        // not sure how to support a blob field.
-        continue;
-        break;
-      case 'int':
-        $base_info['widget']['type'] = 'number';
-        break;
-      case 'float':
-        $base_info['widget']['type'] = 'number';
-        break;
-      case 'numeric':
-        $base_info['widget']['type'] = 'number';
-        break;
-      case 'serial':
-        // Serial fields are most likely not needed as a field.
-        break;
-      case 'boolean':
-        $base_info['widget']['type'] = 'options_onoff';
-        $base_info['required'] = FALSE;
-        break;
-      case 'datetime':
-        $base_info['widget']['type'] = 'date_select';
-        $base_info['widget']['settings']['increment'] = 1;
-        $base_info['widget']['settings']['tz_handling'] = 'none';
-        $base_info['widget']['settings']['collapsible'] = TRUE;
-
-        // TODO: Add settings so that the minutes increment by 1.
-        // And turn off the timezone, as the Chado field doesn't support it.
-        break;
-    }
-
-    // Set some default semantic web information
-    if ($column_name == 'uniquename') {
-      $base_info['label'] = 'Identifier';
-      $base_info['widget_type'] = 'text_textfield';
-    }
-    elseif ($base_info['label'] == 'Timeaccessioned') {
-      $base_info['label'] = 'Time Accessioned';
-      $base_info['description'] = 'Please enter the time that this record was first added to the database.';
-    }
-    elseif ($base_info['label'] == 'Timelastmodified') {
-      $base_info['label'] = 'Time Last Modified';
-      $base_info['description'] = 'Please enter the time that this record was last modified. The default is the current time.';
-    }
-    //
-    // ORGANISM TABLE
-    //
-    elseif ($table_name == 'organism' and $column_name == 'comment') {
-      $base_info['label'] = 'Description';
-    }
-    //
-    // PUB TABLE
-    //
-    elseif ($table_name == 'pub' and $column_name == 'uniquename') {
-      $base_info['widget_type'] = 'text_textfield';
-    }
-
-    //
-    // ANALYSIS TABLE
-    //
-    elseif ($table_name == 'analysis' and $column_name == 'program') {
-      $base_info['description'] = 'The program name (e.g. blastx, blastp, sim4, genscan. If the analysis was not derived from a software package then provide a very brief description of the pipeline, workflow or method.';
-      $base_info['label'] = 'Program, Pipeline, Workflow or Method Name.';
-    }
-    elseif ($table_name == 'analysis' and $column_name == 'sourceuri') {
-      $base_info['widget_type'] = 'text_textfield';
-      $base_info['label'] = 'Source URL';
-      $base_info['description'] = 'The URL where the original source data was derived.  Ideally, this should link to the page where more information about the source data can be found.';
-    }
-    elseif ($table_name == 'analysis' and $column_name == 'sourcename') {
-      $base_info['label'] = 'Source Name';
-      $base_info['description'] = 'The name of the source data. This could be a file name, data set or a small description for how the data was collected. For long descriptions use the larger description field.';
-    }
-    elseif ($table_name == 'analysis' and $column_name == 'sourceversion') {
-      $base_info['label'] = 'Source Version';
-      $base_info['description'] = 'If hte source data set has a version include it here.';
-    }
-    elseif ($table_name == 'analysis' and $column_name == 'algorithm') {
-      $base_info['label'] = 'Source Version';
-      $base_info['description'] = 'The name of the algorithm used to produce the dataset if different from the program.';
-    }
-    elseif ($table_name == 'analysis' and $column_name == 'programversion') {
-      $base_info['label'] = 'Program Version';
-      $base_info['description'] = 'The version of the program used to perform this analysis. (e.g. TBLASTX 2.0MP-WashU [09-Nov-2000]. Enter "n/a" if no version is available or applicable.';
-    }
-    //
-    // PROJECT TABLE
-    //
-    elseif ($table_name == 'project' and $column_name == 'description') {
-      $base_info['label'] = 'Short Description';
-    }
-    $info[$field_name] = $base_info;
-  }
-}
-
-/**
- * Helper function for the hook_create_tripalfield_instance().
- *
- * Adds custom fields for base fields.  These override the settings provided
- * in the tripal_chado_create_tripalfield_instance_base() function.
- *
- * @param $entity_type
- * @param $bundle
- * @param $details
- */
-function tripal_chado_bundle_create_instances_custom(&$info, $entity_type, $bundle, $details) {
-  $table_name = $details['chado_table'];
-  $type_table = $details['chado_type_table'];
-  $type_field = $details['chado_type_column'];
-  $cvterm_id  = $details['chado_cvterm_id'];
-  $schema = chado_get_schema($table_name);
-
-  // BASE ORGANISM_ID
-  if ($table_name != 'organism' and array_key_exists('organism_id', $schema['fields'])) {
-    $field_name = 'obi__organism';
-    $is_required = FALSE;
-    if (array_key_exists('not null', $schema['fields']['organism_id']) and
-        $schema['fields']['organism_id']['not null']) {
-      $is_required = TRUE;
-    }
-    $info[$field_name] =  array(
-      'field_name' => $field_name,
-      'entity_type' => $entity_type,
-      'bundle' => $bundle->name,
-      'label' => 'Organism',
-      'description' => 'Select an organism.',
-      'required' => $is_required,
-      'settings' => array(
-        'auto_attach' => TRUE,
-        'chado_table' => $table_name,
-        'chado_column' => 'organism_id',
-        'base_table' => $table_name,
-      ),
-      'widget' => array(
-        'type' => 'obi__organism_widget',
-        'settings' => array(
-          'display_label' => 1,
-        ),
-      ),
-      'display' => array(
-        'default' => array(
-          'label' => 'inline',
-          'type' => 'obi__organism_formatter',
-          'settings' => array(),
-        ),
-      ),
-    );
-  }
-
-  // BASE DBXREF
-  if (array_key_exists('dbxref_id', $schema['fields'])) {
-    $field_name = 'data__accession';
-    $info[$field_name] = array(
-      'field_name' => $field_name,
-      'entity_type' => $entity_type,
-      'bundle' => $bundle->name,
-      'label' => 'Accession',
-      '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(
-        'auto_attach' => TRUE,
-        'chado_table' => $table_name,
-        'chado_column' => 'dbxref_id',
-        'base_table' => $table_name,
-      ),
-      'widget' => array(
-        'type' => 'data__accession_widget',
-        'settings' => array(
-          'display_label' => 1,
-        ),
-      ),
-      'display' => array(
-        'default' => array(
-          'label' => 'inline',
-          'type' => 'data__accession_formatter',
-          'settings' => array(),
-        ),
-      ),
-    );
-  }
-
-  // FEATURE MD5CHECKSUM
-  if ($table_name == 'feature') {
-    $field_name = 'data__sequence_checksum';
-    $info[$field_name] = array(
-      'field_name' => $field_name,
-      'entity_type' => $entity_type,
-      'bundle' => $bundle->name,
-      'label' => 'Sequence Checksum',
-      'description' => 'The MD5 checksum for the sequence. The checksum here
-        will always be unique for the raw unformatted sequence. To verify that the
-        sequence has not been corrupted, download the raw sequence and use an MD5 tool
-        to calculate the value. If the value calculated is identical the one shown
-        here, then the downloaded sequence is uncorrupted.',
-      'required' => FALSE,
-      'settings' => array(
-        'auto_attach' => TRUE,
-        'chado_table' => $table_name,
-        'chado_column' => 'md5checksum',
-        'base_table' => $table_name,
-      ),
-      'widget' => array(
-        'type' => 'data__sequence_checksum_widget',
-        'settings' => array(
-          'display_label' => 1,
-          'md5_fieldname' => 'feature__md5checksum',
-        ),
-      ),
-      'display' => array(
-        'default' => array(
-          'label' => 'inline',
-          'type' => 'data__sequence_checksum_formatter',
-          'settings' => array(),
-        ),
-      ),
-    );
-  }
-
-  // FEATURE RESIDUES
-  if ($table_name == 'feature') {
-    $field_name = 'data__sequence';
-    $info[$field_name] = array(
-      'field_name' => $field_name,
-      'entity_type' => $entity_type,
-      'bundle' => $bundle->name,
-      'label' => 'Sequence',
-      'description' => 'All available sequences for this record.',
-      'required' => FALSE,
-      'settings' => array(
-        'auto_attach' => FALSE,
-        'chado_table' => $table_name,
-        'chado_column' => 'residues',
-        'base_table' => $table_name,
-      ),
-      'widget' => array(
-        'type' => 'data__sequence_widget',
-        'settings' => array(
-          'display_label' => 1,
-        ),
-      ),
-      'display' => array(
-        'default' => array(
-          'label' => 'above',
-          'type' => 'data__sequence_formatter',
-          'settings' => array(),
-        ),
-      ),
-    );
-  }
-
-  // FEATURE SEQLEN
-  if ($table_name == 'feature') {
-    $field_name = 'data__sequence_length';
-    $info[$field_name] = array(
-      'field_name' => $field_name,
-      'entity_type' => $entity_type,
-      'bundle' => $bundle->name,
-      'label' => 'Sequence Length',
-      'description' => 'The number of residues in the raw sequence.  This length
-        is only for the assigned raw sequence and does not represent the length of any
-        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(
-        'auto_attach' => TRUE,
-        'chado_table' => $table_name,
-        'chado_column' => 'seqlen',
-        'base_table' => $table_name,
-      ),
-      'widget' => array(
-        'type' => 'data__sequence_length_widget',
-        'settings' => array(
-          'display_label' => 1,
-        ),
-      ),
-      'display' => array(
-        'default' => array(
-          'label' => 'inline',
-          'type' => 'data__sequence_length_formatter',
-          'settings' => array(),
-        ),
-      ),
-    );
-  }
-
-  // GENE TRANSCRIPTS
-  $rel_table = $table_name . '_relationship';
-  if (chado_table_exists($rel_table) and $bundle->label == 'gene') {
-    $field_name = 'so__transcript';
-    $info[$field_name] = array(
-      'field_name' => $field_name,
-      'entity_type' => $entity_type,
-      'bundle' => $bundle->name,
-      'label' => 'Transcripts',
-      'description' => 'Transcripts that are part of this gene.',
-      'required' => FALSE,
-      'settings' => array(
-        'auto_attach' => FALSE,
-        'chado_table' => $rel_table,
-        'chado_column' => '',
-        'base_table' => $table_name,
-      ),
-      'widget' => array(
-        'type' => 'so__transcript_widget',
-        'settings' => array(
-          'display_label' => 1,
-        ),
-      ),
-      'display' => array(
-        'default' => array(
-          'label' => 'above',
-          'type' => 'so__transcript_formatter',
-          'settings' => array(),
-        ),
-      ),
-    );
-  }
-
-  // ORGANISM TYPE_ID
-//   if ($table_name == 'organism' and array_key_exists('type_id', $schema['fields'])) {
-//     $field_name = 'taxarank__infraspecific_taxon';
-//     $info[$field_name] = array(
-//       'field_name' => $field_name,
-//       'entity_type' => $entity_type,
-//       'bundle' => $bundle->name,
-//       'label' => 'Infraspecific Taxon',
-//       'description' => 'The Infraspecific Taxon.',
-//       'required' => FALSE,
-//       'settings' => array(
-//         'auto_attach' => TRUE,
-//         'chado_table' => 'organism',
-//         'chado_column' => 'type_id',
-//         'base_table' => 'organism',
-//       ),
-//       'widget' => array(
-//         'type' => 'taxarank__infraspecific_taxon_widget',
-//         'settings' => array(
-//           'display_label' => 1,
-//         ),
-//       ),
-//       'display' => array(
-//         'default' => array(
-//           'label' => 'inline',
-//           'type' => 'taxarank__infraspecific_taxon_formatter',
-//           'settings' => array(),
-//         ),
-//       ),
-//     );
-//   }
-}
-
-/**
- *
- * @param unknown $entity_type
- * @param unknown $bundle
- * @param unknown $details
- */
-function tripal_chado_bundle_create_instances_linker(&$info, $entity_type, $bundle, $details) {
-
-  $table_name = $details['chado_table'];
-  $type_table = $details['chado_type_table'];
-  $type_field = $details['chado_type_column'];
-  $cvterm_id  = $details['chado_cvterm_id'];
-
-  // CONTACTS
-  $contact_table = $table_name . '_contact';
-  if (chado_table_exists($contact_table)) {
-    $field_name = $table_name . '_contact';
-    $info[$field_name] =     $info[$field_name] = array(
-      'field_name' => $field_name,
-      'entity_type' => $entity_type,
-      'bundle' => $bundle->name,
-      'label' => 'Contact',
-      'description' => 'Associates an indviddual or organization with this record',
-      'required' => FALSE,
-      'settings' => array(
-        'auto_attach' => FALSE,
-        'chado_table' => $contact_table,
-        'base_table' => $table_name,
-        'chado_column' => 'contact_id',
-      ),
-      'widget' => array(
-        'type' => 'local__contact_widget',
-        'settings' => array(
-          'display_label' => 1,
-        ),
-      ),
-      'display' => array(
-        'default' => array(
-          'label' => 'above',
-          'type' => 'local__contact_formatter',
-          'settings' => array(),
-        ),
-      ),
-    );
-  }
-
-  // DBXREF
-  $dbxref_table = $table_name . '_dbxref';
-  if (chado_table_exists($dbxref_table)) {
-    $field_name = 'sbo__database_cross_reference';
-    $schema = chado_get_schema($dbxref_table);
-    $pkey = $schema['primary key'][0];
-    $info[$field_name] =  array(
-      'field_name' =>  $field_name,
-      'entity_type' => $entity_type,
-      'bundle' => $bundle->name,
-      'label' => 'Database Cross Reference',
-      'description' => 'The IDs where this record may be available in other external online databases.',
-      'required' => FALSE,
-      'settings' => array(
-        'auto_attach' => FALSE,
-        'chado_table' => $dbxref_table,
-        'chado_column' => $pkey,
-        'base_table' => $table_name,
-      ),
-      'widget' => array(
-        'type' => 'sbo__database_cross_reference_widget',
-        'settings' => array(
-          'display_label' => 1,
-        ),
-      ),
-      'display' => array(
-        'default' => array(
-          'label' => 'inline',
-          'type' => 'sbo__database_cross_reference_formatter',
-          'settings' => array(),
-        ),
-      ),
-    );
-  }
-
-  // EXPRESSION
-  $expression_table = $table_name . '_expression';
-  if (chado_table_exists($expression_table)) {
-    $field_name = 'go__gene_expression';
-    $schema = chado_get_schema($expression_table);
-    $pkey = $schema['primary key'][0];
-    $info[$field_name] = array(
-      'field_name' => $field_name,
-      'entity_type' => $entity_type,
-      'bundle' => $bundle->name,
-      'label' => 'Gene expression',
-      'description' => 'Information about the expression of this record.',
-      'required' => FALSE,
-      'settings' => array(
-        'auto_attach' => FALSE,
-        'chado_table' => $expression_table,
-        'chado_column' => $pkey,
-        'base_table' => $table_name,
-      ),
-      'widget' => array(
-        'type' => 'go__gene_expression_widget',
-        'settings' => array(
-          'display_label' => 1,
-        ),
-      ),
-      'display' => array(
-        'default' => array(
-          'label' => 'above',
-          'type' => 'go__gene_expression_formatter',
-          'settings' => array(),
-        ),
-      ),
-    );
-  }
-
-  // FEATURELOC
-  if ($table_name == 'feature') {
-    $field_name = 'data__sequence_coordinates';
-    $schema = chado_get_schema('featureloc');
-    $pkey = $schema['primary key'][0];
-    $info[$field_name] = array(
-      'field_name' => $field_name,
-      'entity_type' => $entity_type,
-      'bundle' => $bundle->name,
-      'label' => 'Sequence Coordinates',
-      'description' => 'The locations on other genomic sequences where this
-        record has been aligned.',
-      'required' => FALSE,
-      'settings' => array(
-        'auto_attach' => FALSE,
-        'chado_table' => 'featureloc',
-        'chado_column' => $pkey,
-        'base_table' => 'feature',
-      ),
-      'widget' => array(
-        'type' => 'data__sequence_coordinates_widget',
-        'settings' => array(
-          'display_label' => 1,
-        ),
-      ),
-      'display' => array(
-        'default' => array(
-          'label' => 'above',
-          'type' => 'data__sequence_coordinates_formatter',
-          'settings' => array(),
-        ),
-      ),
-    );
-  }
-
-  // FEATUREPOS
-  if ($table_name == 'feature') {
-    $field_name = 'ogi__location_on_map';
-    $schema = chado_get_schema('featurepos');
-    $pkey = $schema['primary key'][0];
-    $info[$field_name] = array(
-      'field_name' => $field_name,
-      'entity_type' => $entity_type,
-      'bundle' => $bundle->name,
-      'label' => 'Location on Map',
-      'description' => 'The positions on a genetic map.',
-      'required' => FALSE,
-      'settings' => array(
-        'auto_attach' => FALSE,
-        'chado_table' => 'featurepos',
-        'chado_column' => $pkey,
-        'base_table' => 'feature',
-      ),
-      'widget' => array(
-        'type' => 'ogi__location_on_map_widget',
-        'settings' => array(
-          'display_label' => 1,
-        ),
-      ),
-      'display' => array(
-        'default' => array(
-          'label' => 'above',
-          'type' => 'ogi__location_on_map_formatter',
-          'settings' => array(),
-        ),
-      ),
-    );
-  }
-
-  // GENOTYPE
-  $genotype_table = $table_name . '_genotype';
-  if (chado_table_exists($genotype_table)) {
-    $field_name = 'so__genotype';
-    $schema = chado_get_schema($genotype_table);
-    $pkey = $schema['primary key'][0];
-    $info[$field_name] = array(
-      'field_name' => $field_name,
-      'entity_type' => $entity_type,
-      'bundle' => $bundle->name,
-      'label' => 'Genotype',
-      'description' => 'The genotypes associated with this record.',
-      'required' => FALSE,
-      'settings' => array(
-        'auto_attach' => FALSE,
-        'chado_table' => $genotype_table,
-        'chado_column' => $pkey,
-        'base_table' => $table_name,
-      ),
-      'widget' => array(
-        'type' => 'so__genotype_widget',
-        'settings' => array(
-          'display_label' => 1,
-        ),
-      ),
-      'display' => array(
-        'default' => array(
-          'label' => 'above',
-          'type' => 'so__genotype_formatter',
-          'settings' => array(),
-        ),
-      ),
-    );
-  }
-
-  // PHENOTYPE
-  $phenotype_table = $table_name . '_phenotype';
-  if (chado_table_exists($phenotype_table)) {
-    $field_name = 'sbo__phenotype';
-    $schema = chado_get_schema($phenotype_table);
-    $pkey = $schema['primary key'][0];
-    $info[$field_name] = array(
-      'field_name' => $field_name,
-      'entity_type' => $entity_type,
-      'bundle' => $bundle->name,
-      'label' => 'Phenotype',
-      'description' => 'The phenotypes associated with this record.',
-      'required' => FALSE,
-      'settings' => array(
-        'auto_attach' => FALSE,
-        'chado_table' => $phenotype_table,
-        'chado_column' => $pkey,
-        'base_table' => $table_name,
-      ),
-      'widget' => array(
-        'type' => 'sbo__phenotype_widget',
-        'settings' => array(
-          'display_label' => 1,
-        ),
-      ),
-      'display' => array(
-        'default' => array(
-          'label' => 'above',
-          'type' => 'sbo__phenotype_formatter',
-          'settings' => array(),
-        ),
-      ),
-    );
-  }
-
-  // PROPERTIES
-  $prop_table = $table_name . 'prop';
-  if (chado_table_exists($prop_table)) {
-     // Get the list of existing property types for this table.
-     $sql = 'SELECT DISTINCT type_id FROM {' . $prop_table . '}';
-     $props = chado_query($sql);
-     $schema = chado_get_schema($prop_table);
-     $pkey = $schema['primary key'][0];
-     while ($prop = $props->fetchObject()) {
-       $term = chado_generate_var('cvterm', array('cvterm_id' => $prop->type_id));
-       $field_name = strtolower(preg_replace('/[^\w]/','_', $term->dbxref_id->db_id->name . '__' . $term->name));
-       $info[$field_name] = array(
-         'field_name' => $field_name,
-         'entity_type' => $entity_type,
-         'bundle' => $bundle->name,
-         'label' => ucwords(preg_replace('/_/', ' ', $term->name)),
-         'description' => $term->definition,
-         'required' => FALSE,
-         'settings' => array(
-           'auto_attach' => TRUE,
-           'term_vocabulary' => $term->dbxref_id->db_id->name,
-           'term_accession' => $term->dbxref_id->accession,
-           'term_name' => $term->name,
-           'base_table' => $table_name,
-           'chado_table' => $prop_table,
-           'chado_column' => $pkey,
-         ),
-         'widget' => array(
-           'type' => 'chado_linker__prop_widget',
-           'settings' => array(
-             'display_label' => 1,
-           ),
-         ),
-         'display' => array(
-           'default' => array(
-             'label' => 'inline',
-             'type' => 'chado_linker__prop_formatter',
-             'settings' => array(),
-           ),
-         ),
-       );
-     }
-   }
-
-
-  // PUBLICATIONS
-  $pub_table = $table_name . '_pub';
-  if (chado_table_exists($pub_table)) {
-    $field_name = 'schema__publication';
-    $schema = chado_get_schema($pub_table);
-    $pkey = $schema['primary key'][0];
-    $info[$field_name] = array(
-      'field_name' => $field_name,
-      'entity_type' => $entity_type,
-      'bundle' => $bundle->name,
-      'label' => 'Publication',
-      'description' => 'This record has been referenced or is sourced from these publications.',
-      'required' => FALSE,
-      'settings' => array(
-        'auto_attach' => FALSE,
-        'chado_table' => $pub_table,
-        'chado_column' => $pkey,
-        'base_table' => $table_name,
-      ),
-      'widget' => array(
-        'type' => 'schema__publication_widget',
-        'settings' => array(
-          'display_label' => 1,
-        ),
-      ),
-      'display' => array(
-        'default' => array(
-          'label' => 'above',
-          'type' => 'schema__publication_formatter',
-          'settings' => array(),
-        ),
-      ),
-    );
-  }
-
-  // RELATIONSHIPS
-  // If the linker table does not exists then we don't want to add attach.
-  $rel_table = $table_name . '_relationship';
-  if (chado_table_exists($rel_table)) {
-    $field_name = 'sbo__relationship';
-    $schema = chado_get_schema($rel_table);
-    $pkey = $schema['primary key'][0];
-    $info[$field_name] = array(
-      'field_name' => $field_name,
-      'entity_type' => $entity_type,
-      'bundle' => $bundle->name,
-      'label' => 'Relationship',
-      'description' => 'Other records with relationships to this record.',
-      'required' => FALSE,
-      'settings' => array(
-        'auto_attach' => FALSE,
-        'chado_table' => $rel_table,
-        'chado_column' => $pkey,
-        'base_table' => $table_name,
-      ),
-      'widget' => array(
-        'type' => 'sbo__relationship_widget',
-        'settings' => array(
-          'display_label' => 1,
-        ),
-      ),
-      'display' => array(
-        'default' => array(
-          'label' => 'above',
-          'type' => 'sbo__relationship_formatter',
-          'settings' => array(),
-        ),
-      ),
-    );
-  }
-
-  // SYNONYMS
-  $syn_table = $table_name . '_synonym';
-  if (chado_table_exists($syn_table)) {
-    $field_name = 'schema__alternate_name';
-    $schema = chado_get_schema($syn_table);
-    $pkey = $schema['primary key'][0];
-    $info[$field_name] = array(
-      'field_name' => $field_name,
-      'entity_type' => $entity_type,
-      'bundle' => $bundle->name,
-      'label' => 'Synonyms',
-      'description' => 'Alternate names, aliases or synonyms for this record.',
-      'required' => FALSE,
-      'settings' => array(
-        'auto_attach' => FALSE,
-        'chado_table' => $syn_table,
-        'chado_column' => $pkey,
-        'base_table' => $table_name,
-      ),
-      'widget' => array(
-        'type' => 'schema__alternate_name_widget',
-        'settings' => array(
-          'display_label' => 1,
-        ),
-      ),
-      'display' => array(
-        'default' => array(
-          'label' => 'inline',
-          'type' => 'schema__alternate_name_formatter',
-          'settings' => array(),
-        ),
-      ),
-    );
-  }
-}
-
-/**
- * Implements hook_form_FORM_ID_alter().
- *
- * The field_ui_field_overview_form is used for ordering and configuring the
- * fields attached to an entity.
- *
- * This function removes the property adder field as that is really not meant
- * for users to show or manage.
- */
-function tripal_chado_form_field_ui_field_overview_form_alter(&$form, &$form_state, $form_id) {
-
-  // Remove the kvproperty_addr field as it isn't ever displayed. It's just used
-  // on the add/edit form of an entity for adding new property fields.
-  $fields_names = element_children($form['fields']);
-  foreach ($fields_names as $field_name) {
-    $field_info = field_info_field($field_name);
-    if ($field_info['type'] == 'kvproperty_adder') {
-      unset($form['fields'][$field_name]);
-    }
-    if ($field_info['type'] == 'cvterm_class_adder') {
-      unset($form['fields'][$field_name]);
-    }
-  }
-}
-
-/**
- * Implements hook_form_field_ui_field_overview_add_new().
- */
-function tripal_chado_form_field_ui_field_overview_add_new($new_field, $bundle) {
-  // Get the table this bundle is mapped to.
-  $term = tripal_load_term_entity(array('term_id' => $bundle->term_id));
-  $vocab = $term->vocab;
-  $params = array(
-    'vocabulary' => $vocab->vocabulary,
-    'accession' => $term->accession,
-  );
-  $mapped_table = chado_get_cvterm_mapping($params);
-  $chado_table = $mapped_table->chado_table;
-  $chado_type_table = $mapped_table->chado_table;
-  $chado_type_column = $mapped_table->chado_field;
-
-  // We allow site admins to add new chado_linker__prop fields to an entity.
-  // This function will allow us to properly add them.  But at this point we
-  // don't know the controlled vocabulary term.  We'll have to use the
-  // defaults and let the user set it using the interface.
-  if ($new_field['type'] == 'chado_linker__prop') {
-    $table_name = $chado_table . 'prop';
-
-    if (chado_table_exists($table_name)) {
-      $schema = chado_get_schema($table_name);
-      $pkey = $schema['primary key'][0];
-      $field_name = $new_field['field_name'];
-      $field_type = 'chado_linker__prop';
-
-      // First add the field.
-      field_create_field(array(
-        'field_name' => $field_name,
-        'type' => $field_type,
-        'cardinality' => FIELD_CARDINALITY_UNLIMITED,
-        'locked' => FALSE,
-        'storage' => array(
-          'type' => 'field_chado_storage',
-        ),
-        'settings' => array(
-          'base_table' => $chado_table,
-          'chado_table' => $table_name,
-          'chado_column' => $pkey,
-        ),
-      ));
-
-      // Now add the instance
-      field_create_instance(array(
-        'field_name' => $field_name,
-        'entity_type' => 'TripalEntity',
-        'bundle' => $bundle->name,
-        'label' => $new_field['label'],
-        'description' => '',
-        'required' => FALSE,
-        'settings' => array(
-          'auto_attach' => TRUE,
-        ),
-        'widget' => array(
-          'type' => 'chado_linker__prop_widget',
-          'settings' => array(
-            'display_label' => 1,
-          ),
-        ),
-        'display' => array(
-          'default' => array(
-            'label' => 'inline',
-            'type' => 'chado_linker__prop_formatter',
-            'settings' => array(),
-          ),
-        ),
-      ));
-    }
-    else {
-      drupal_set_message('Cannot add a property field to this entity. Chado does not support properties for this data type.', 'error');
-    }
-  }
-
-  // We allow site admins to add new chado_linker__cvterm fields to an entity.
-  // This function will allow us to properly add them.  But at this point we
-  // don't know the controlled vocabulary term.  We'll have to use the
-  // defaults and let the user set it using the interface.
-
-  if ($new_field['type'] == 'chado_linker__cvterm') {
-    $table_name = $chado_table . '_cvterm';
-
-    if (chado_table_exists($table_name)) {
-      $schema = chado_get_schema($table_name);
-      $pkey = $schema['primary key'][0];
-      $field_name = $new_field['field_name'];
-      $field_type = 'chado_linker__cvterm';
-
-      // First add the field.
-      field_create_field(array(
-        'field_name' => $field_name,
-        'type' => $field_type,
-        'cardinality' => FIELD_CARDINALITY_UNLIMITED,
-        'locked' => FALSE,
-        'storage' => array(
-          'type' => 'field_chado_storage',
-        ),
-        'settings' => array(
-          'base_table' => $chado_table,
-          'chado_table' => $table_name,
-          'chado_column' => $pkey,
-        ),
-      ));
-
-      // Now add the instance
-      field_create_instance(array(
-        'field_name' => $field_name,
-        'entity_type' => 'TripalEntity',
-        'bundle' => $bundle->name,
-        'label' => $new_field['label'],
-        'description' => '',
-        'required' => FALSE,
-        'settings' => array(
-          'auto_attach' => TRUE,
-        ),
-        'widget' => array(
-          'type' => 'chado_linker__cvterm_widget',
-          'settings' => array(
-            'display_label' => 1,
-          ),
-        ),
-        'display' => array(
-          'default' => array(
-            'label' => 'above',
-            'type' => 'chado_linker__cvterm_formatter',
-            'settings' => array(),
-          ),
-        ),
-      ));
-    }
-    else {
-      drupal_set_message('Cannot add a property field to this entity. Chado does not support annotations for this data type.', 'error');
-    }
-  }
-}
-
-
-/**
- * Allows for altering of a field's instance setting form.
- *
- * This appears to be a Drupal hook but is actually a custom function created
- * by this module. It is called by the tripal_form_alter() function of this
- * module.
- *
- * Here we put additional form elements for any field, regardless if it is
- * a tripalField or not.
- *
- * @param $form
- *   The form array.  Alterations to the form can be made within this array.
- * @param $form_state
- *   The form state array.
- */
-function tripal_chado_field_instance_settings_form_alter(&$form, $form_state) {
-  global $language;
-  $field = $form['#field'];
-  $instance = $form['#instance'];
-
-  // Only show the Chado mapping information for field instances that map
-  // to Chado.
-  if (!array_key_exists('chado_table',$instance['settings'])) {
-    return;
-  }
-
-  // Construct a table for the vocabulary information.
-  $headers = array();
-  $rows = array();
-  $rows[] = array(
-    array(
-      'data' => 'Base Table',
-      'header' => TRUE,
-      'width' => '20%',
-    ),
-    $instance['settings']['base_table']
-  );
-  $rows[] = array(
-    array(
-      'data' => 'Record Table',
-      'header' => TRUE,
-      'width' => '20%',
-    ),
-    $instance['settings']['chado_table']
-  );
-  $rows[] = array(
-    array(
-      'data' => 'ID Column',
-      'header' => TRUE,
-      'width' => '20%',
-    ),
-    $instance['settings']['chado_column']
-  );
-  $table = array(
-    'header' => $headers,
-    'rows' => $rows,
-    'attributes' => array(
-    ),
-    'sticky' => FALSE,
-    'caption' => '',
-    'colgroups' => array(),
-    'empty' => '',
-  );
-
-  $form['chado_mapping'] = array(
-    '#type' => 'fieldset',
-    '#title' => 'Chado Mapping',
-    '#description' => t('This field maps to data in Chado to the following table:'),
-  );
-  $form['chado_mapping']['details'] = array(
-    '#type' => 'item',
-    '#markup' => theme_table($table),
-  );
-
-}
-<<<<<<< HEAD
-=======
-
-/**
- * Implements hook_form_FROM_ID_alter()
- */
-function tripal_chado_form_tripalbundle_form_alter(&$form, $form_state) {
-  global $language;
-  $bundle = $form['#bundle'];
-
-  $term = entity_load('TripalTerm', array('id' => $bundle->term_id));
-  $term = reset($term);
-  $vocab = $term->vocab;
-  $params = array(
-    'vocabulary' => $vocab->vocabulary,
-    'accession' => $term->accession,
-  );
-  $mapped_table = chado_get_cvterm_mapping($params);
-  $chado_table = $mapped_table->chado_table;
-  $chado_column = $mapped_table->chado_field;
-
-  // Construct a table for the vocabulary information.
-  $headers = array();
-  $rows = array();
-  $rows[] = array(
-    array(
-      'data' => 'Chado Table',
-      'header' => TRUE,
-      'width' => '20%',
-    ),
-    $chado_table
-  );
-  $rows[] = array(
-    array(
-      'data' => 'Type Column',
-      'header' => TRUE,
-      'width' => '20%',
-    ),
-    $chado_column
-  );
-  $table = array(
-    'header' => $headers,
-    'rows' => $rows,
-    'attributes' => array(
-    ),
-    'sticky' => FALSE,
-    'caption' => '',
-    'colgroups' => array(),
-    'empty' => '',
-  );
-
-  $form['chado_mapping'] = array(
-    '#type' => 'item',
-    '#title' => 'Chado Mapping',
-    '#markup' => theme_table($table),
-    '#description' => t('This content type maps to the table in Chado
-        listed above.  Chado allows multiple data types to be housed
-        in a single table. Therefore, the column that is used to
-        differentiate between data types is also listed above.'),
-    '#weight' => 0,
-  );
-}
->>>>>>> a584591704c14877292a457afa4b1e793853f9f6

+ 7 - 0
tripal_chado/includes/tripal_chado.semweb.inc

@@ -316,6 +316,13 @@ function tripal_chado_populate_vocab_EDAM() {
     'cv_name' => 'EDAM',
     'definition' => 'The name of a biological or bioinformatics database.',
   ));
+
+  $term = tripal_insert_cvterm(array(
+    'id' => 'data:1048',
+    'name' => 'Database ID',
+    'cv_name' => 'EDAM',
+    'definition' => 'An identifier of a biological or bioinformatics database.',
+  ));
   tripal_associate_chado_semweb_term('db', 'name', $term);
 
   $term = tripal_insert_cvterm(array(

+ 56 - 57
tripal_chado/tripal_chado.install

@@ -155,7 +155,6 @@ function tripal_chado_schema() {
   }
 
   // Links TripalEntity entities to the chado record.
-  $schema['chado_entity'] = tripal_chado_chado_entity_schema();
   $schema['chado_bundle'] = tripal_chado_chado_bundle_schema();
   $schema['chado_semweb'] = tripal_chado_chado_semweb_schema();
 
@@ -564,59 +563,6 @@ function tripal_chado_tripal_mviews_schema() {
   );
 }
 
-/**
- * Links Biological Data Entities to the chado "base" table the data is stored in.
- * This is where we would specify that a particular gene maps to the record in the
- * chado.feature table with a feature_id=2432;
- */
-function tripal_chado_chado_entity_schema() {
-
-  $schema = array(
-    'description' => 'The linker table that associates an enitity from the public.tripal_entity table with a "base" record in Chado',
-    'fields' => array(
-      'chado_entity_id' => array(
-        'description' => 'The primary identifier for this table.',
-        'type' => 'serial',
-        'unsigned' => TRUE,
-        'not null' => TRUE,
-      ),
-      'entity_id' => array(
-        'description' => 'The unique entity id.',
-        'type' => 'int',
-        'not null' => TRUE,
-      ),
-      'data_table' => array(
-        'description' => 'The table in that this record belongs to',
-        'type' => 'varchar',
-        'length' => 128,
-        'not null' => TRUE,
-        'default' => '',
-      ),
-      'record_id' => array(
-        'description' => 'The unique numerical identifier for the record that this entity is associated with (e.g. feature_id, stock_id, library_id, etc.).',
-        'type' => 'int',
-        'not null' => TRUE,
-      ),
-      'nid' => array(
-        'description' => 'Optional. For linking nid to the entity when migrating Tripal v2 content',
-        'type' => 'int',
-      )
-    ),
-    'indexes' => array(
-      'record_id' => array('record_id'),
-      'entity_id' => array('entity_id'),
-      'data_table' => array('data_table'),
-      'nid' => array('nid'),
-    ),
-    'unique keys' => array(
-      'table_record' => array('data_table', 'record_id'),
-      'entity_id' => array('entity_id'),
-    ),
-    'primary key' => array('chado_entity_id'),
-  );
-  return $schema;
-}
-
 /**
  * Links Biological Data Entities to the chado "base" table the data is stored in.
  * This is where we would specify that a particular gene maps to the record in the
@@ -729,17 +675,70 @@ function tripal_chado_chado_cvterm_mapping_schema() {
 }
 
 /**
- * Fixes the phase on the tripal_gffcds_temp table used for importing GFF files.
+ * Fixes the phase on the tripal_gffcds_temp table used for importing GFF files, and fixes the db.name term mapping.
  *
  */
-function tripal_chado_update_7200() {
+function tripal_chado_update_7300() {
   try {
     if (chado_table_exists('tripal_gffcds_temp')) {
       chado_query("ALTER TABLE {tripal_gffcds_temp} ALTER COLUMN phase DROP NOT NULL;");
     }
+
+    $term = tripal_insert_cvterm(array(
+      'id' => 'data:1048',
+      'name' => 'Database ID',
+      'cv_name' => 'EDAM',
+      'definition' => 'An identifier of a biological or bioinformatics database.',
+    ));
+    tripal_associate_chado_semweb_term('db', 'name', $term);
   }
   catch (\PDOException $e) {
     $error = $e->getMessage();
     throw new DrupalUpdateException('Could not fix phase on tripal_gffcds_temp table: '. $error);
   }
-}
+}
+
+/**
+ * Divides chado_entity table for better integration with views.
+ */
+function tripal_chado_update_7301() {
+
+  module_load_include('inc', 'tripal_chado', 'includes/tripal_chado.bundle');
+  try {
+    $transaction = db_transaction();
+    $query = db_select('chado_bundle', 'CB');
+    $query->join('tripal_bundle', 'TB', 'TB.id = CB.bundle_id');
+    $query->fields('CB', array('data_table'));
+    $query->fields('TB', array('name'));
+    $cbundles = $query->execute();
+
+    // If the table for the bundle doesn't exist then create one, and then
+    // move all of the records from the chado_entity table to it.
+    while($cbundle = $cbundles->fetchObject()) {
+      $cbundle_table = tripal_chado_get_bundle_entity_table($cbundle);
+
+      if (!db_table_exists($cbundle_table)) {
+        // Create the bundle table.
+        tripal_chado_create_bundle_table($cbundle);
+
+        // Now move the records over.
+        $sql = "
+          INSERT INTO {$cbundle_table} (entity_id, record_id, nid)
+           SELECT CE.entity_id, CE.record_id, CE.nid
+            FROM {chado_entity} CE
+              INNER JOIN {tripal_entity} TE ON CE.entity_id = TE.id
+            WHERE TE.bundle = :bundle
+        ";
+        db_query($sql, array(':bundle' => $cbundle->name));
+      }
+    }
+
+    // Now remove the chado_entity table.
+    db_drop_table('chado_entity');
+  }
+  catch (\PDOException $e) {
+    $transaction->rollback();
+    $error = $e->getMessage();
+    throw new DrupalUpdateException('Could not perform update: '. $error);
+  }
+}

+ 15 - 14
tripal_chado/tripal_chado.module

@@ -8,6 +8,7 @@
 require_once "api/tripal_chado.api.inc";
 require_once 'api/tripal_chado.property.api.inc';
 require_once 'api/tripal_chado.query.api.inc';
+require_once 'api/tripal_chado.entity.api.inc';
 require_once 'api/tripal_chado.variables.api.inc';
 require_once 'api/tripal_chado.schema.api.inc';
 require_once 'api/tripal_chado.custom_tables.api.inc';
@@ -361,7 +362,7 @@ function tripal_chado_menu() {
     'description' => 'Load sequences from a multi-FASTA file into Chado',
     'page callback' => 'drupal_get_form',
     'page arguments' => array('tripal_feature_fasta_load_form'),
-    'access arguments' => array('administer tripal feature'),
+    'access arguments' => array('administer tripal'),
     'file' => 'includes/loaders/tripal_chado.fasta_loader.inc',
     'file path' => drupal_get_path('module', 'tripal_chado'),
     'type' => MENU_NORMAL_ITEM,
@@ -371,7 +372,7 @@ function tripal_chado_menu() {
     'description' => 'Import a GFF3 file into Chado',
     'page callback' => 'drupal_get_form',
     'page arguments' => array('tripal_feature_gff3_load_form'),
-    'access arguments' => array('administer tripal feature'),
+    'access arguments' => array('administer tripal'),
     'file' => 'includes/loaders/tripal_chado.gff_loader.inc',
     'file path' => drupal_get_path('module', 'tripal_chado'),
     'type' => MENU_NORMAL_ITEM,
@@ -381,7 +382,7 @@ function tripal_chado_menu() {
     'description' => 'Loads taxonomic details about installed organisms.',
     'page callback' => 'drupal_get_form',
     'page arguments' => array('tripal_chado_taxonomy_load_form'),
-    'access arguments' => array('administer tripal phylotree'),
+    'access arguments' => array('administer tripal'),
     'file' => 'includes/loaders/tripal_chado.taxonomy_importer.inc',
     'file path' => drupal_get_path('module', 'tripal_chado'),
     'type' => MENU_NORMAL_ITEM,
@@ -393,7 +394,7 @@ function tripal_chado_menu() {
     'description' => 'Loads phylogenetic trees in Newic format.',
     'page callback' => 'drupal_goto',
     'page arguments' => array('node/add/chado-phylotree'),
-    'access arguments' => array('administer tripal phylotree'),
+    'access arguments' => array('administer tripal'),
     'type' => MENU_NORMAL_ITEM,
   );
 
@@ -401,7 +402,7 @@ function tripal_chado_menu() {
     'title' => t('Publication Importers'),
     'description' => t('Create and modify importers that can connect to and retreive publications from remote databases.'),
     'page callback' => 'tripal_pub_importers_list',
-    'access arguments' => array('administer tripal pub'),
+    'access arguments' => array('administer tripal'),
     'file' => 'includes/loaders/tripal_chado.pub_importers.inc',
     'file path' => drupal_get_path('module', 'tripal_chado'),
     'type' => MENU_NORMAL_ITEM,
@@ -412,7 +413,7 @@ function tripal_chado_menu() {
     'title' => t('Add an Importer'),
     'description' => t('Add a new publication importer.'),
     'page callback' => 'tripal_pub_importer_setup_page',
-    'access arguments' => array('administer tripal pub'),
+    'access arguments' => array('administer tripal'),
     'type ' => MENU_CALLBACK,
     'file' => 'includes/loaders/tripal_chado.pub_importers.inc',
     'file path' => drupal_get_path('module', 'tripal_chado'),
@@ -420,7 +421,7 @@ function tripal_chado_menu() {
   $items['admin/tripal/storage/chado/loaders/pub/edit/%'] = array(
     'page callback' => 'tripal_pub_importer_setup_page',
     'page arguments' => array(6, 7),
-    'access arguments' => array('administer tripal pub'),
+    'access arguments' => array('administer tripal'),
     'type ' => MENU_CALLBACK,
     'file' => 'includes/loaders/tripal_chado.pub_importers.inc',
     'file path' => drupal_get_path('module', 'tripal_chado'),
@@ -429,7 +430,7 @@ function tripal_chado_menu() {
     'title' => t('Raw Data From Publication Import'),
     'page callback' => 'tripal_get_remote_pub_raw_page',
     'page arguments' => array(6),
-    'access arguments' => array('administer tripal pub'),
+    'access arguments' => array('administer tripal'),
     'type ' => MENU_CALLBACK,
     'file' => 'includes/loaders/tripal_chado.pub_importers.inc',
     'file path' => drupal_get_path('module', 'tripal_chado'),
@@ -439,7 +440,7 @@ function tripal_chado_menu() {
   $items['admin/tripal/storage/chado/loaders/pub/import'] = array(
     'title' => t('Publication Importers'),
     'page callback' => 'tripal_pub_importers_list',
-    'access arguments' => array('administer tripal pub'),
+    'access arguments' => array('administer tripal'),
     'type' => MENU_CALLBACK,
     'file' => 'includes/loaders/tripal_chado.pub_importers.inc',
     'file path' => drupal_get_path('module', 'tripal_chado'),
@@ -448,7 +449,7 @@ function tripal_chado_menu() {
   $items['admin/tripal/storage/chado/loaders/pub/submit/%'] = array(
     'page callback' => 'tripal_pub_importer_submit_job',
     'page arguments' => array(7),
-    'access arguments' => array('administer tripal pub'),
+    'access arguments' => array('administer tripal'),
     'type ' => MENU_CALLBACK,
     'file' => 'includes/loaders/tripal_chado.pub_importers.inc',
     'file path' => drupal_get_path('module', 'tripal_chado'),
@@ -457,7 +458,7 @@ function tripal_chado_menu() {
   $items['admin/tripal/storage/chado/loaders/pub/delete/%'] = array(
     'page callback' => 'tripal_pub_importer_delete',
     'page arguments' => array(7),
-    'access arguments' => array('administer tripal pub'),
+    'access arguments' => array('administer tripal'),
     'type ' => MENU_CALLBACK,
     'file' => 'includes/loaders/tripal_chado.pub_importers.inc',
     'file path' => drupal_get_path('module', 'tripal_chado'),
@@ -465,7 +466,7 @@ function tripal_chado_menu() {
   $items['admin/tripal/storage/chado/loaders/pub/changedb'] = array(
     'page callback' => 'tripal_pub_importer_setup_page_update_remotedb',
     'page arguments' => array(),
-    'access arguments' => array('administer tripal pub'),
+    'access arguments' => array('administer tripal'),
     'type ' => MENU_CALLBACK,
     'file' => 'includes/loaders/tripal_chado.pub_importers.inc',
     'file path' => drupal_get_path('module', 'tripal_chado'),
@@ -474,7 +475,7 @@ function tripal_chado_menu() {
   $items['admin/tripal/storage/chado/loaders/pub/criteria/%/%'] = array(
     'page callback' => 'tripal_pub_importer_setup_page_update_criteria',
     'page arguments' => array(7, 8),
-    'access arguments' => array('administer tripal pub'),
+    'access arguments' => array('administer tripal'),
     'type ' => MENU_CALLBACK,
     'file' => 'includes/loaders/tripal_chado.pub_importers.inc',
     'file path' => drupal_get_path('module', 'tripal_chado'),
@@ -807,7 +808,7 @@ function tripal_chado_job_describe_args($callback, $args) {
 function tripal_chado_node_delete($node) {
   $nid = $node->nid;
   $sql = "UPDATE chado_entity SET nid = NULL WHERE nid = :nid";
-  db_query($sql, array('nid' => $nid));
+  //db_query($sql, array('nid' => $nid));
 }
 
 

+ 132 - 132
tripal_chado/tripal_chado.views.inc

@@ -5,8 +5,8 @@
  */
 
 /**
- * Describe various Tripal Core systems to Views
- *   for the creation of administrative views.
+ * Describe various Tripal Core systems to Views for the creation of
+ * administrative views.
  *
  * @ingroup tripal
  */
@@ -22,136 +22,136 @@ function tripal_chado_views_data() {
   return $data;
 }
 
-/**
- * Implements hook_views_data_alter().
- */
-function tripal_chado_views_data_alter(&$data) {
-
-  // Adds integration for chado-based fields.
-  tripal_chado_add_field_views_data($data);
-
-  return $data;
-}
-
-/**
- * Adds integration for chado-based fields.
- *
- * We can't use hook_field_view_data since this only works when the
- * storage engine is of type 'field_sql_storage' and of course,
- * ours is not. Thus we create our own implementation of field_views_data()
- * for our storage engine.
- */
-function tripal_chado_add_field_views_data(&$data) {
-  foreach (field_info_fields() as $field) {
-    if ($field['storage']['type'] != 'field_chado_storage') {
-      continue;
-    }
-
-    $field_name = $field['field_name'];
-    $field_type = $field['type'];
-
-
-    // Currently, we only handle integration of chado fields with TripalEntity.
-    // @todo: extend this to work with other entities in the future.
-    if (isset($field['bundles']['TripalEntity']) AND isset($field['settings']['chado_column'])) {
-
-      // We currently don't support prop tables for views integration due
-      // in part to the multiple values but also b/c we can't indicate which
-      // type of property to show. Thus, instead of warning the user,
-      // we just won't integrate it at this time.
-      // @todo: Handle property fields.
-      if (preg_match('/prop$/', $field['settings']['chado_table'])) {
-        continue;
-      }
-
-      // Get some information about the chado table in order to make good
-      // default choices for handlers.
-      $table_desc = chado_get_schema($field['settings']['chado_table']);
-      $field_defn = $table_desc['fields'][ $field['settings']['chado_column'] ];
-
-      // We also need to know if this field is a foreign key.
-      $fk_defn = FALSE;
-      foreach ($table_desc['foreign keys'] as $details) {
-        foreach ($details['columns'] as $left_field => $right_field) {
-          if ($left_field == $field['settings']['chado_column']) {
-            $fk_defn = array(
-              'left_table' => $field['settings']['chado_table'],
-              'left_field' => $left_field,
-              'right_table' => $details['table'],
-              'right_field' => $right_field,
-            );
-          }
-        }
-      }
-
-      // Unfortunatly we can't use the field label since that is set at the
-      // instance level and fields are integrated at the field level (independant of bundle).
-      // Thus we will simply make the most readable and informative field name we can.
-      $data['tripal_entity'][$field_name]['title'] = ucfirst(str_replace('_',' ',$field['settings']['chado_table']))
-        . ': ' .ucfirst(str_replace('_',' ',$field['settings']['chado_column']));
-
-      // The help should be 'Appears in: TripalEntity: gene, organism'
-      // so that users know where they can use it. This requires a little extra work since all
-      // we have access to at this point is bio_data_2, bio_data_4 but since that's not very
-      // informative, extra work is worth it ;-).
-      $entity_info = entity_get_info('TripalEntity');
-      $bundle_labels = array();
-      foreach ($field['bundles']['TripalEntity'] as $bundle_id) {
-        $bundle_labels[] = $entity_info['bundles'][$bundle_id]['label'];
-      }
-      $data['tripal_entity'][$field_name]['help'] = 'Appears in: TripalEntity:' . implode(', ', $bundle_labels);
-
-      // Define the field.
-      $data['tripal_entity'][$field_name]['field']['chado_field'] = $field['settings']['chado_column'];
-      $data['tripal_entity'][$field_name]['field']['chado_table'] = $field['settings']['chado_table'];
-      $data['tripal_entity'][$field_name]['field']['field_name'] = $field['field_name'];
-      $data['tripal_entity'][$field_name]['field']['entity_table'] = 'tripal_entity';
-      $data['tripal_entity'][$field_name]['field']['entity_type'] = 'TripalEntity';
-      $data['tripal_entity'][$field_name]['field']['bundles'] = $field['bundles']['TripalEntity'];
-      $data['tripal_entity'][$field_name]['field']['handler'] = 'chado_views_handler_field';
-      $data['tripal_entity'][$field_name]['field']['click sortable'] = FALSE;
-
-      // Define the Filter.
-      $data['tripal_entity'][$field_name]['filter']['chado_field'] = $field['settings']['chado_column'];
-      $data['tripal_entity'][$field_name]['filter']['chado_table'] = $field['settings']['chado_table'];
-      $data['tripal_entity'][$field_name]['filter']['field_name'] = $field['field_name'];
-      $data['tripal_entity'][$field_name]['filter']['entity_table'] = 'tripal_entity';
-      $data['tripal_entity'][$field_name]['filter']['entity_type'] = 'TripalEntity';
-      $data['tripal_entity'][$field_name]['filter']['bundles'] = $field['bundles']['TripalEntity'];
-      $data['tripal_entity'][$field_name]['filter']['handler'] = 'chado_views_handler_filter_string';
-
-      // Define sorting.
-      $data['tripal_entity'][$field_name]['sort']['chado_field'] = $field['settings']['chado_column'];
-      $data['tripal_entity'][$field_name]['sort']['chado_table'] = $field['settings']['chado_table'];
-      $data['tripal_entity'][$field_name]['sort']['field_name'] = $field['field_name'];
-      $data['tripal_entity'][$field_name]['sort']['entity_table'] = 'tripal_entity';
-      $data['tripal_entity'][$field_name]['sort']['entity_type'] = 'TripalEntity';
-      $data['tripal_entity'][$field_name]['sort']['bundles'] = $field['bundles']['TripalEntity'];
-      $data['tripal_entity'][$field_name]['sort']['handler'] = 'chado_views_handler_sort';
-
-      // Specify special handlers.
-      if ($fk_defn) {
-        $data['tripal_entity'][$field_name]['filter']['handler'] = 'chado_views_handler_filter_fk';
-        $data['tripal_entity'][$field_name]['filter']['foreign_key'] = $fk_defn;
-      }
-      if ($field_defn['type'] == 'boolean') {
-        $data['tripal_entity'][$field_name]['filter']['handler'] = 'chado_views_handler_filter_boolean';
-        $data['tripal_entity'][$field_name]['filter']['label'] = $field['settings']['chado_column'];
-        $data['tripal_entity'][$field_name]['filter']['type'] = 'yes-no';
-      }
-      elseif ($field_defn['type'] == 'datetime') {
-        $data['tripal_entity'][$field_name]['filter']['handler'] = 'chado_views_handler_filter_date';
-      }
-
-      // Allow the fields to alter the default selections from above.
-      tripal_load_include_field_type($field_type);
-      if (preg_match('/^chado/', $field_type) and class_exists($field_type)) {
-        $field_obj = new $field_type($field);
-        $field_obj->views_data_alter($data['tripal_entity'][$field_name], $field, $entity_info);
-      }
-    }
-  }
-}
+// /**
+//  * Implements hook_views_data_alter().
+//  */
+// function tripal_chado_views_data_alter(&$data) {
+
+//   // Adds integration for chado-based fields.
+//   tripal_chado_add_field_views_data($data);
+
+//   return $data;
+// }
+
+// /**
+//  * Adds integration for chado-based fields.
+//  *
+//  * We can't use hook_field_view_data since this only works when the
+//  * storage engine is of type 'field_sql_storage' and of course,
+//  * ours is not. Thus we create our own implementation of field_views_data()
+//  * for our storage engine.
+//  */
+// function tripal_chado_add_field_views_data(&$data) {
+//   foreach (field_info_fields() as $field) {
+//     if ($field['storage']['type'] != 'field_chado_storage') {
+//       continue;
+//     }
+
+//     $field_name = $field['field_name'];
+//     $field_type = $field['type'];
+
+
+//     // Currently, we only handle integration of chado fields with TripalEntity.
+//     // @todo: extend this to work with other entities in the future.
+//     if (isset($field['bundles']['TripalEntity']) AND isset($field['settings']['chado_column'])) {
+
+//       // We currently don't support prop tables for views integration due
+//       // in part to the multiple values but also b/c we can't indicate which
+//       // type of property to show. Thus, instead of warning the user,
+//       // we just won't integrate it at this time.
+//       // @todo: Handle property fields.
+//       if (preg_match('/prop$/', $field['settings']['chado_table'])) {
+//         continue;
+//       }
+
+//       // Get some information about the chado table in order to make good
+//       // default choices for handlers.
+//       $table_desc = chado_get_schema($field['settings']['chado_table']);
+//       $field_defn = $table_desc['fields'][ $field['settings']['chado_column'] ];
+
+//       // We also need to know if this field is a foreign key.
+//       $fk_defn = FALSE;
+//       foreach ($table_desc['foreign keys'] as $details) {
+//         foreach ($details['columns'] as $left_field => $right_field) {
+//           if ($left_field == $field['settings']['chado_column']) {
+//             $fk_defn = array(
+//               'left_table' => $field['settings']['chado_table'],
+//               'left_field' => $left_field,
+//               'right_table' => $details['table'],
+//               'right_field' => $right_field,
+//             );
+//           }
+//         }
+//       }
+
+//       // Unfortunatly we can't use the field label since that is set at the
+//       // instance level and fields are integrated at the field level (independant of bundle).
+//       // Thus we will simply make the most readable and informative field name we can.
+//       $data['tripal_entity'][$field_name]['title'] = ucfirst(str_replace('_',' ',$field['settings']['chado_table']))
+//         . ': ' .ucfirst(str_replace('_',' ',$field['settings']['chado_column']));
+
+//       // The help should be 'Appears in: TripalEntity: gene, organism'
+//       // so that users know where they can use it. This requires a little extra work since all
+//       // we have access to at this point is bio_data_2, bio_data_4 but since that's not very
+//       // informative, extra work is worth it ;-).
+//       $entity_info = entity_get_info('TripalEntity');
+//       $bundle_labels = array();
+//       foreach ($field['bundles']['TripalEntity'] as $bundle_id) {
+//         $bundle_labels[] = $entity_info['bundles'][$bundle_id]['label'];
+//       }
+//       $data['tripal_entity'][$field_name]['help'] = 'Appears in: TripalEntity:' . implode(', ', $bundle_labels);
+
+//       // Define the field.
+//       $data['tripal_entity'][$field_name]['field']['chado_field'] = $field['settings']['chado_column'];
+//       $data['tripal_entity'][$field_name]['field']['chado_table'] = $field['settings']['chado_table'];
+//       $data['tripal_entity'][$field_name]['field']['field_name'] = $field['field_name'];
+//       $data['tripal_entity'][$field_name]['field']['entity_table'] = 'tripal_entity';
+//       $data['tripal_entity'][$field_name]['field']['entity_type'] = 'TripalEntity';
+//       $data['tripal_entity'][$field_name]['field']['bundles'] = $field['bundles']['TripalEntity'];
+//       $data['tripal_entity'][$field_name]['field']['handler'] = 'chado_views_handler_field';
+//       $data['tripal_entity'][$field_name]['field']['click sortable'] = FALSE;
+
+//       // Define the Filter.
+//       $data['tripal_entity'][$field_name]['filter']['chado_field'] = $field['settings']['chado_column'];
+//       $data['tripal_entity'][$field_name]['filter']['chado_table'] = $field['settings']['chado_table'];
+//       $data['tripal_entity'][$field_name]['filter']['field_name'] = $field['field_name'];
+//       $data['tripal_entity'][$field_name]['filter']['entity_table'] = 'tripal_entity';
+//       $data['tripal_entity'][$field_name]['filter']['entity_type'] = 'TripalEntity';
+//       $data['tripal_entity'][$field_name]['filter']['bundles'] = $field['bundles']['TripalEntity'];
+//       $data['tripal_entity'][$field_name]['filter']['handler'] = 'chado_views_handler_filter_string';
+
+//       // Define sorting.
+//       $data['tripal_entity'][$field_name]['sort']['chado_field'] = $field['settings']['chado_column'];
+//       $data['tripal_entity'][$field_name]['sort']['chado_table'] = $field['settings']['chado_table'];
+//       $data['tripal_entity'][$field_name]['sort']['field_name'] = $field['field_name'];
+//       $data['tripal_entity'][$field_name]['sort']['entity_table'] = 'tripal_entity';
+//       $data['tripal_entity'][$field_name]['sort']['entity_type'] = 'TripalEntity';
+//       $data['tripal_entity'][$field_name]['sort']['bundles'] = $field['bundles']['TripalEntity'];
+//       $data['tripal_entity'][$field_name]['sort']['handler'] = 'chado_views_handler_sort';
+
+//       // Specify special handlers.
+//       if ($fk_defn) {
+//         $data['tripal_entity'][$field_name]['filter']['handler'] = 'chado_views_handler_filter_fk';
+//         $data['tripal_entity'][$field_name]['filter']['foreign_key'] = $fk_defn;
+//       }
+//       if ($field_defn['type'] == 'boolean') {
+//         $data['tripal_entity'][$field_name]['filter']['handler'] = 'chado_views_handler_filter_boolean';
+//         $data['tripal_entity'][$field_name]['filter']['label'] = $field['settings']['chado_column'];
+//         $data['tripal_entity'][$field_name]['filter']['type'] = 'yes-no';
+//       }
+//       elseif ($field_defn['type'] == 'datetime') {
+//         $data['tripal_entity'][$field_name]['filter']['handler'] = 'chado_views_handler_filter_date';
+//       }
+
+//       // Allow the fields to alter the default selections from above.
+//       tripal_load_include_field_type($field_type);
+//       if (preg_match('/^chado/', $field_type) and class_exists($field_type)) {
+//         $field_obj = new $field_type($field);
+//         $field_obj->views_data_alter($data['tripal_entity'][$field_name], $field, $entity_info);
+//       }
+//     }
+//   }
+// }
 
 /**
  * Provides the data array for the tripal custom tables management

+ 212 - 232
tripal_chado/tripal_chado.views_default.inc

@@ -641,241 +641,221 @@ function tripal_chado_defaultview_admin_cvs_listing() {
  */
 function tripal_chado_defaultview_admin_cvterms_listing() {
 
-  $view = new view();
-  $view->name = 'tripal_cv_admin_cvterms';
-  $view->description = 'DO NOT DISABLE';
-  $view->tag = 'tripal admin';
-  $view->base_table = 'cvterm';
-  $view->human_name = 'CV Terms Admin';
-  $view->core = 0;
-  $view->api_version = '3.0';
-  $view->disabled = FALSE; /* Edit this to true to make a default view disabled initially */
-
-  /* Display: Defaults */
-  $handler = $view->new_display('default', 'Defaults', 'default');
-  $handler->display->display_options['title'] = 'Controlled Vocabulary Terms';
-  $handler->display->display_options['use_more_always'] = FALSE;
-  $handler->display->display_options['access']['type'] = 'perm';
-  $handler->display->display_options['access']['perm'] = 'administer tripal';
-  $handler->display->display_options['cache']['type'] = 'none';
-  $handler->display->display_options['query']['type'] = 'views_query';
-  $handler->display->display_options['exposed_form']['type'] = 'input_required';
-  $handler->display->display_options['exposed_form']['options']['submit_button'] = 'Search';
-  $handler->display->display_options['exposed_form']['options']['text_input_required'] = 'Click search to see a listing of controlled vocabulary terms that meet the filter requirements. Use the filters to restrict this set to a more reasonable number of terms or to find a specific term.';
-  $handler->display->display_options['exposed_form']['options']['text_input_required_format'] = 'full_html';
-  $handler->display->display_options['pager']['type'] = 'full';
-  $handler->display->display_options['pager']['options']['items_per_page'] = '25';
-  $handler->display->display_options['pager']['options']['offset'] = '0';
-  $handler->display->display_options['pager']['options']['id'] = '0';
-  $handler->display->display_options['pager']['options']['quantity'] = '9';
-  $handler->display->display_options['style_plugin'] = 'table';
-  $handler->display->display_options['style_options']['grouping'] = '';
-  $handler->display->display_options['style_options']['columns'] = array(
-    'name_1' => 'name_1',
-    'name' => 'name',
-    'definition' => 'definition',
-    'is_obsolete' => 'is_obsolete',
-    'is_relationshiptype' => 'is_relationshiptype',
-  );
-  $handler->display->display_options['style_options']['default'] = '-1';
-  $handler->display->display_options['style_options']['info'] = array(
-    'name_1' => array(
-      'sortable' => 1,
-      'separator' => '',
-    ),
-    'name' => array(
-      'sortable' => 1,
-      'separator' => '',
-    ),
-    'definition' => array(
-      'sortable' => 0,
-      'separator' => '',
-    ),
-    'is_obsolete' => array(
-      'sortable' => 1,
-      'separator' => '',
-    ),
-    'is_relationshiptype' => array(
-      'sortable' => 1,
-      'separator' => '',
-    ),
-  );
-  /* Header: Global: Action Links */
-  $handler->display->display_options['header']['action_links_area']['id'] = 'action_links_area';
-  $handler->display->display_options['header']['action_links_area']['table'] = 'views';
-  $handler->display->display_options['header']['action_links_area']['field'] = 'action_links_area';
-  $handler->display->display_options['header']['action_links_area']['label'] = 'Action Links';
-  $handler->display->display_options['header']['action_links_area']['empty'] = TRUE;
-  $handler->display->display_options['header']['action_links_area']['link-1'] = array(
-    'label-1' => 'Add Term',
-    'path-1' => 'admin/tripal/vocab/cvterm/add',
-  );
-  /* No results behavior: Global: Text area */
-  $handler->display->display_options['empty']['text']['id'] = 'area';
-  $handler->display->display_options['empty']['text']['table'] = 'views';
-  $handler->display->display_options['empty']['text']['field'] = 'area';
-  $handler->display->display_options['empty']['text']['content'] = 'There are no terms associated with the selected controlled vocabulary. Please select a different vocabulary from the list above.';
-  $handler->display->display_options['empty']['text']['format'] = '1';
-  /* Field: Chado Cv: Cv Id */
-  $handler->display->display_options['fields']['cv_id']['id'] = 'cv_id';
-  $handler->display->display_options['fields']['cv_id']['table'] = 'cv';
-  $handler->display->display_options['fields']['cv_id']['field'] = 'cv_id';
-  $handler->display->display_options['fields']['cv_id']['exclude'] = TRUE;
-  $handler->display->display_options['fields']['cv_id']['separator'] = '';
-  /* Field: Chado Cv: Name */
-  $handler->display->display_options['fields']['name_1']['id'] = 'name_1';
-  $handler->display->display_options['fields']['name_1']['table'] = 'cv';
-  $handler->display->display_options['fields']['name_1']['field'] = 'name';
-  $handler->display->display_options['fields']['name_1']['label'] = 'Vocabulary';
-  $handler->display->display_options['fields']['name_1']['alter']['make_link'] = TRUE;
-  $handler->display->display_options['fields']['name_1']['alter']['path'] = 'admin/tripal/vocab/cvs?name=[name_1]';
-  /* Field: Chado Cvterm: Cvterm Id */
-  $handler->display->display_options['fields']['cvterm_id']['id'] = 'cvterm_id';
-  $handler->display->display_options['fields']['cvterm_id']['table'] = 'cvterm';
-  $handler->display->display_options['fields']['cvterm_id']['field'] = 'cvterm_id';
-  $handler->display->display_options['fields']['cvterm_id']['exclude'] = TRUE;
-  $handler->display->display_options['fields']['cvterm_id']['separator'] = '';
-  /* Field: Chado Cvterm: Name */
-  $handler->display->display_options['fields']['name']['id'] = 'name';
-  $handler->display->display_options['fields']['name']['table'] = 'cvterm';
-  $handler->display->display_options['fields']['name']['field'] = 'name';
-  /* Field: Chado Cvterm: Definition */
-  $handler->display->display_options['fields']['definition']['id'] = 'definition';
-  $handler->display->display_options['fields']['definition']['table'] = 'cvterm';
-  $handler->display->display_options['fields']['definition']['field'] = 'definition';
-  $handler->display->display_options['fields']['definition']['element_class'] = 'wide-column';
-  $handler->display->display_options['fields']['definition']['element_label_class'] = 'wide-column';
-  /* Field: Chado Cvterm: Is Obsolete */
-  $handler->display->display_options['fields']['is_obsolete']['id'] = 'is_obsolete';
-  $handler->display->display_options['fields']['is_obsolete']['table'] = 'cvterm';
-  $handler->display->display_options['fields']['is_obsolete']['field'] = 'is_obsolete';
-  $handler->display->display_options['fields']['is_obsolete']['label'] = 'Obsolete?';
-  $handler->display->display_options['fields']['is_obsolete']['alter']['alter_text'] = TRUE;
-  $handler->display->display_options['fields']['is_obsolete']['alter']['text'] = 'Yes';
-  $handler->display->display_options['fields']['is_obsolete']['element_class'] = 'short-column';
-  $handler->display->display_options['fields']['is_obsolete']['element_label_class'] = 'short-column';
-  $handler->display->display_options['fields']['is_obsolete']['empty'] = 'No';
-  $handler->display->display_options['fields']['is_obsolete']['empty_zero'] = TRUE;
-  $handler->display->display_options['fields']['is_obsolete']['separator'] = '';
-  /* Field: Chado Cvterm: Is Relationshiptype */
-  $handler->display->display_options['fields']['is_relationshiptype']['id'] = 'is_relationshiptype';
-  $handler->display->display_options['fields']['is_relationshiptype']['table'] = 'cvterm';
-  $handler->display->display_options['fields']['is_relationshiptype']['field'] = 'is_relationshiptype';
-  $handler->display->display_options['fields']['is_relationshiptype']['label'] = 'Relation-ship?';
-  $handler->display->display_options['fields']['is_relationshiptype']['alter']['alter_text'] = TRUE;
-  $handler->display->display_options['fields']['is_relationshiptype']['alter']['text'] = 'Yes';
-  $handler->display->display_options['fields']['is_relationshiptype']['element_class'] = 'short-column';
-  $handler->display->display_options['fields']['is_relationshiptype']['element_label_class'] = 'short-column';
-  $handler->display->display_options['fields']['is_relationshiptype']['empty'] = 'No';
-  $handler->display->display_options['fields']['is_relationshiptype']['empty_zero'] = TRUE;
-  $handler->display->display_options['fields']['is_relationshiptype']['separator'] = '';
-  /* Field: Global: Custom text */
-  $handler->display->display_options['fields']['nothing']['id'] = 'nothing';
-  $handler->display->display_options['fields']['nothing']['table'] = 'views';
-  $handler->display->display_options['fields']['nothing']['field'] = 'nothing';
-  $handler->display->display_options['fields']['nothing']['label'] = 'Edit Link';
-  $handler->display->display_options['fields']['nothing']['exclude'] = TRUE;
-  $handler->display->display_options['fields']['nothing']['alter']['text'] = 'edit';
-  $handler->display->display_options['fields']['nothing']['alter']['make_link'] = TRUE;
-  $handler->display->display_options['fields']['nothing']['alter']['path'] = 'admin/tripal/vocab/cv/[cv_id]/cvterm/edit/[cvterm_id]';
-  /* Field: Global: Custom text */
-  $handler->display->display_options['fields']['nothing_1']['id'] = 'nothing_1';
-  $handler->display->display_options['fields']['nothing_1']['table'] = 'views';
-  $handler->display->display_options['fields']['nothing_1']['field'] = 'nothing';
-  $handler->display->display_options['fields']['nothing_1']['label'] = '';
-  $handler->display->display_options['fields']['nothing_1']['alter']['text'] = '[nothing]';
-  $handler->display->display_options['fields']['nothing_1']['element_class'] = 'short-column';
-  $handler->display->display_options['fields']['nothing_1']['element_label_class'] = 'short-column';
-  $handler->display->display_options['fields']['nothing_1']['element_label_colon'] = FALSE;
-  /* Sort criterion: Chado Cv: Name */
-  $handler->display->display_options['sorts']['name']['id'] = 'name';
-  $handler->display->display_options['sorts']['name']['table'] = 'cv';
-  $handler->display->display_options['sorts']['name']['field'] = 'name';
-  /* Sort criterion: Chado Cvterm: Name */
-  $handler->display->display_options['sorts']['name_1']['id'] = 'name_1';
-  $handler->display->display_options['sorts']['name_1']['table'] = 'cvterm';
-  $handler->display->display_options['sorts']['name_1']['field'] = 'name';
-  /* Filter criterion: Chado Cv: Name */
-  $handler->display->display_options['filters']['name']['id'] = 'name';
-  $handler->display->display_options['filters']['name']['table'] = 'cv';
-  $handler->display->display_options['filters']['name']['field'] = 'name';
-  $handler->display->display_options['filters']['name']['value'] = 'All';
-  $handler->display->display_options['filters']['name']['group'] = '0';
-  $handler->display->display_options['filters']['name']['exposed'] = TRUE;
-  $handler->display->display_options['filters']['name']['expose']['operator_id'] = 'name_op';
-  $handler->display->display_options['filters']['name']['expose']['label'] = 'Vocabulary';
-  $handler->display->display_options['filters']['name']['expose']['operator'] = 'name_op';
-  $handler->display->display_options['filters']['name']['expose']['identifier'] = 'cv';
-  $handler->display->display_options['filters']['name']['expose']['remember_roles'] = array(
-    2 => '2',
-    1 => 0,
-    3 => 0,
-  );
-  /* Filter criterion: Chado Cvterm: Name */
-  $handler->display->display_options['filters']['name_1']['id'] = 'name_1';
-  $handler->display->display_options['filters']['name_1']['table'] = 'cvterm';
-  $handler->display->display_options['filters']['name_1']['field'] = 'name';
-  $handler->display->display_options['filters']['name_1']['operator'] = 'contains';
-  $handler->display->display_options['filters']['name_1']['group'] = '0';
-  $handler->display->display_options['filters']['name_1']['exposed'] = TRUE;
-  $handler->display->display_options['filters']['name_1']['expose']['operator_id'] = '';
-  $handler->display->display_options['filters']['name_1']['expose']['label'] = 'Name Contains';
-  $handler->display->display_options['filters']['name_1']['expose']['identifier'] = 'name';
-  $handler->display->display_options['filters']['name_1']['expose']['remember_roles'] = array(
-    2 => '2',
-    1 => 0,
-    3 => 0,
-  );
-  /* Filter criterion: Chado Cvterm: Definition */
-  $handler->display->display_options['filters']['definition']['id'] = 'definition';
-  $handler->display->display_options['filters']['definition']['table'] = 'cvterm';
-  $handler->display->display_options['filters']['definition']['field'] = 'definition';
-  $handler->display->display_options['filters']['definition']['operator'] = 'contains';
-  $handler->display->display_options['filters']['definition']['group'] = '0';
-  $handler->display->display_options['filters']['definition']['exposed'] = TRUE;
-  $handler->display->display_options['filters']['definition']['expose']['operator_id'] = 'definition_op';
-  $handler->display->display_options['filters']['definition']['expose']['label'] = 'Definition Contains';
-  $handler->display->display_options['filters']['definition']['expose']['operator'] = 'definition_op';
-  $handler->display->display_options['filters']['definition']['expose']['identifier'] = 'definition';
-  $handler->display->display_options['filters']['definition']['expose']['remember_roles'] = array(
-    2 => '2',
-    1 => 0,
-    3 => 0,
-  );
+$view = new view();
+$view->name = 'tripal_cv_admin_cvterms';
+$view->description = 'DO NOT DISABLE';
+$view->tag = 'tripal admin';
+$view->base_table = 'cvterm';
+$view->human_name = 'CV Terms Admin';
+$view->core = 0;
+$view->api_version = '3.0';
+$view->disabled = FALSE; /* Edit this to true to make a default view disabled initially */
 
-  /** MANUALLY ADDED since filter handler no exporting correctly */
-  $handler->display->display_options['filters']['name']['expose']['values_form_type'] = 'select';
-  $handler->display->display_options['filters']['name']['expose']['select_multiple'] = FALSE;
-  $handler->display->display_options['filters']['name']['expose']['select_optional'] = TRUE;
-  $handler->display->display_options['filters']['name']['expose']['max_length'] = 40;
-
-  $handler->display->display_options['filters']['name_1']['expose']['values_form_type'] = 'textfield';
-  $handler->display->display_options['filters']['name_1']['expose']['select_multiple'] = FALSE;
-  $handler->display->display_options['filters']['name_1']['expose']['select_optional'] = FALSE;
-  $handler->display->display_options['filters']['name_1']['expose']['max_length'] = 40;
-
-  /* Display: Page */
-  $handler = $view->new_display('page', 'Page', 'page_1');
-  $handler->display->display_options['path'] = 'admin/tripal/vocab/cvterms';
-  $handler->display->display_options['menu']['type'] = 'tab';
-  $handler->display->display_options['menu']['title'] = 'Terms';
-  $handler->display->display_options['menu']['description'] = 'A listing of a controlled vocabulary terms for a given vocabulary';
-  $handler->display->display_options['menu']['weight'] = '-8';
-  $handler->display->display_options['menu']['name'] = 'management';
-  $handler->display->display_options['menu']['context'] = 0;
-  $handler->display->display_options['menu']['context_only_inline'] = 0;
+/* Display: Defaults */
+$handler = $view->new_display('default', 'Defaults', 'default');
+$handler->display->display_options['title'] = 'Controlled Vocabulary Terms';
+$handler->display->display_options['use_more_always'] = FALSE;
+$handler->display->display_options['access']['type'] = 'perm';
+$handler->display->display_options['access']['perm'] = 'administer tripal';
+$handler->display->display_options['cache']['type'] = 'none';
+$handler->display->display_options['query']['type'] = 'views_query';
+$handler->display->display_options['exposed_form']['type'] = 'input_required';
+$handler->display->display_options['exposed_form']['options']['submit_button'] = 'Search';
+$handler->display->display_options['exposed_form']['options']['text_input_required'] = 'Click search to see a listing of controlled vocabulary terms that meet the filter requirements. Use the filters to restrict this set to a more reasonable number of terms or to find a specific term.';
+$handler->display->display_options['exposed_form']['options']['text_input_required_format'] = 'full_html';
+$handler->display->display_options['pager']['type'] = 'full';
+$handler->display->display_options['pager']['options']['items_per_page'] = '25';
+$handler->display->display_options['pager']['options']['offset'] = '0';
+$handler->display->display_options['pager']['options']['id'] = '0';
+$handler->display->display_options['pager']['options']['quantity'] = '9';
+$handler->display->display_options['style_plugin'] = 'table';
+$handler->display->display_options['style_options']['grouping'] = '';
+$handler->display->display_options['style_options']['columns'] = array(
+  'name_1' => 'name_1',
+  'name' => 'name',
+  'definition' => 'definition',
+  'is_obsolete' => 'is_obsolete',
+  'is_relationshiptype' => 'is_relationshiptype',
+);
+$handler->display->display_options['style_options']['default'] = '-1';
+$handler->display->display_options['style_options']['info'] = array(
+  'name_1' => array(
+    'sortable' => 1,
+    'separator' => '',
+  ),
+  'name' => array(
+    'sortable' => 1,
+    'separator' => '',
+  ),
+  'definition' => array(
+    'sortable' => 0,
+    'separator' => '',
+  ),
+  'is_obsolete' => array(
+    'sortable' => 1,
+    'separator' => '',
+  ),
+  'is_relationshiptype' => array(
+    'sortable' => 1,
+    'separator' => '',
+  ),
+);
+/* Header: Global: Action Links */
+$handler->display->display_options['header']['action_links_area']['id'] = 'action_links_area';
+$handler->display->display_options['header']['action_links_area']['table'] = 'views';
+$handler->display->display_options['header']['action_links_area']['field'] = 'action_links_area';
+$handler->display->display_options['header']['action_links_area']['label'] = 'Action Links';
+$handler->display->display_options['header']['action_links_area']['empty'] = TRUE;
+$handler->display->display_options['header']['action_links_area']['link-1'] = array(
+  'label-1' => 'Add Term',
+  'path-1' => 'admin/tripal/vocab/cvterm/add',
+);
+/* No results behavior: Global: Text area */
+$handler->display->display_options['empty']['text']['id'] = 'area';
+$handler->display->display_options['empty']['text']['table'] = 'views';
+$handler->display->display_options['empty']['text']['field'] = 'area';
+$handler->display->display_options['empty']['text']['content'] = 'There are no terms associated with the selected controlled vocabulary. Please select a different vocabulary from the list above.';
+$handler->display->display_options['empty']['text']['format'] = '1';
+/* Field: Chado Cv: Cv Id */
+$handler->display->display_options['fields']['cv_id']['id'] = 'cv_id';
+$handler->display->display_options['fields']['cv_id']['table'] = 'cv';
+$handler->display->display_options['fields']['cv_id']['field'] = 'cv_id';
+$handler->display->display_options['fields']['cv_id']['exclude'] = TRUE;
+$handler->display->display_options['fields']['cv_id']['separator'] = '';
+/* Field: Chado Cv: Name */
+$handler->display->display_options['fields']['name_1']['id'] = 'name_1';
+$handler->display->display_options['fields']['name_1']['table'] = 'cv';
+$handler->display->display_options['fields']['name_1']['field'] = 'name';
+$handler->display->display_options['fields']['name_1']['label'] = 'Vocabulary';
+$handler->display->display_options['fields']['name_1']['alter']['make_link'] = TRUE;
+$handler->display->display_options['fields']['name_1']['alter']['path'] = 'admin/tripal/vocab/cvs?name=[name_1]';
+/* Field: Chado Cvterm: Cvterm Id */
+$handler->display->display_options['fields']['cvterm_id']['id'] = 'cvterm_id';
+$handler->display->display_options['fields']['cvterm_id']['table'] = 'cvterm';
+$handler->display->display_options['fields']['cvterm_id']['field'] = 'cvterm_id';
+$handler->display->display_options['fields']['cvterm_id']['exclude'] = TRUE;
+$handler->display->display_options['fields']['cvterm_id']['separator'] = '';
+/* Field: Chado Cvterm: Name */
+$handler->display->display_options['fields']['name']['id'] = 'name';
+$handler->display->display_options['fields']['name']['table'] = 'cvterm';
+$handler->display->display_options['fields']['name']['field'] = 'name';
+/* Field: Chado Cvterm: Definition */
+$handler->display->display_options['fields']['definition']['id'] = 'definition';
+$handler->display->display_options['fields']['definition']['table'] = 'cvterm';
+$handler->display->display_options['fields']['definition']['field'] = 'definition';
+$handler->display->display_options['fields']['definition']['element_class'] = 'wide-column';
+$handler->display->display_options['fields']['definition']['element_label_class'] = 'wide-column';
+/* Field: Chado Cvterm: Is Obsolete */
+$handler->display->display_options['fields']['is_obsolete']['id'] = 'is_obsolete';
+$handler->display->display_options['fields']['is_obsolete']['table'] = 'cvterm';
+$handler->display->display_options['fields']['is_obsolete']['field'] = 'is_obsolete';
+$handler->display->display_options['fields']['is_obsolete']['label'] = 'Obsolete?';
+$handler->display->display_options['fields']['is_obsolete']['alter']['alter_text'] = TRUE;
+$handler->display->display_options['fields']['is_obsolete']['alter']['text'] = 'Yes';
+$handler->display->display_options['fields']['is_obsolete']['element_class'] = 'short-column';
+$handler->display->display_options['fields']['is_obsolete']['element_label_class'] = 'short-column';
+$handler->display->display_options['fields']['is_obsolete']['empty'] = 'No';
+$handler->display->display_options['fields']['is_obsolete']['empty_zero'] = TRUE;
+$handler->display->display_options['fields']['is_obsolete']['separator'] = '';
+/* Field: Chado Cvterm: Is Relationshiptype */
+$handler->display->display_options['fields']['is_relationshiptype']['id'] = 'is_relationshiptype';
+$handler->display->display_options['fields']['is_relationshiptype']['table'] = 'cvterm';
+$handler->display->display_options['fields']['is_relationshiptype']['field'] = 'is_relationshiptype';
+$handler->display->display_options['fields']['is_relationshiptype']['label'] = 'Relation-ship?';
+$handler->display->display_options['fields']['is_relationshiptype']['alter']['alter_text'] = TRUE;
+$handler->display->display_options['fields']['is_relationshiptype']['alter']['text'] = 'Yes';
+$handler->display->display_options['fields']['is_relationshiptype']['element_class'] = 'short-column';
+$handler->display->display_options['fields']['is_relationshiptype']['element_label_class'] = 'short-column';
+$handler->display->display_options['fields']['is_relationshiptype']['empty'] = 'No';
+$handler->display->display_options['fields']['is_relationshiptype']['empty_zero'] = TRUE;
+$handler->display->display_options['fields']['is_relationshiptype']['separator'] = '';
+/* Field: Global: Custom text */
+$handler->display->display_options['fields']['nothing']['id'] = 'nothing';
+$handler->display->display_options['fields']['nothing']['table'] = 'views';
+$handler->display->display_options['fields']['nothing']['field'] = 'nothing';
+$handler->display->display_options['fields']['nothing']['label'] = 'Edit Link';
+$handler->display->display_options['fields']['nothing']['exclude'] = TRUE;
+$handler->display->display_options['fields']['nothing']['alter']['text'] = 'edit';
+$handler->display->display_options['fields']['nothing']['alter']['make_link'] = TRUE;
+$handler->display->display_options['fields']['nothing']['alter']['path'] = 'admin/tripal/vocab/cv/[cv_id]/cvterm/edit/[cvterm_id]';
+/* Field: Global: Custom text */
+$handler->display->display_options['fields']['nothing_1']['id'] = 'nothing_1';
+$handler->display->display_options['fields']['nothing_1']['table'] = 'views';
+$handler->display->display_options['fields']['nothing_1']['field'] = 'nothing';
+$handler->display->display_options['fields']['nothing_1']['label'] = '';
+$handler->display->display_options['fields']['nothing_1']['alter']['text'] = '[nothing]';
+$handler->display->display_options['fields']['nothing_1']['element_class'] = 'short-column';
+$handler->display->display_options['fields']['nothing_1']['element_label_class'] = 'short-column';
+$handler->display->display_options['fields']['nothing_1']['element_label_colon'] = FALSE;
+/* Sort criterion: Chado Cv: Name */
+$handler->display->display_options['sorts']['name']['id'] = 'name';
+$handler->display->display_options['sorts']['name']['table'] = 'cv';
+$handler->display->display_options['sorts']['name']['field'] = 'name';
+/* Sort criterion: Chado Cvterm: Name */
+$handler->display->display_options['sorts']['name_1']['id'] = 'name_1';
+$handler->display->display_options['sorts']['name_1']['table'] = 'cvterm';
+$handler->display->display_options['sorts']['name_1']['field'] = 'name';
+/* Filter criterion: Chado Cv: Name */
+$handler->display->display_options['filters']['name']['id'] = 'name';
+$handler->display->display_options['filters']['name']['table'] = 'cv';
+$handler->display->display_options['filters']['name']['field'] = 'name';
+$handler->display->display_options['filters']['name']['value'] = 'All';
+$handler->display->display_options['filters']['name']['group'] = '0';
+$handler->display->display_options['filters']['name']['exposed'] = TRUE;
+$handler->display->display_options['filters']['name']['expose']['operator_id'] = 'name_op';
+$handler->display->display_options['filters']['name']['expose']['label'] = 'Vocabulary';
+$handler->display->display_options['filters']['name']['expose']['operator'] = 'name_op';
+$handler->display->display_options['filters']['name']['expose']['identifier'] = 'cv';
+$handler->display->display_options['filters']['name']['expose']['remember_roles'] = array(
+  2 => '2',
+  1 => 0,
+  3 => 0,
+);
+$handler->display->display_options['filters']['name']['values_form_type'] = 'select';
+$handler->display->display_options['filters']['name']['select_optional'] = TRUE;
+/* Filter criterion: Chado Cvterm: Name */
+$handler->display->display_options['filters']['name_1']['id'] = 'name_1';
+$handler->display->display_options['filters']['name_1']['table'] = 'cvterm';
+$handler->display->display_options['filters']['name_1']['field'] = 'name';
+$handler->display->display_options['filters']['name_1']['operator'] = 'contains';
+$handler->display->display_options['filters']['name_1']['group'] = '0';
+$handler->display->display_options['filters']['name_1']['exposed'] = TRUE;
+$handler->display->display_options['filters']['name_1']['expose']['operator_id'] = '';
+$handler->display->display_options['filters']['name_1']['expose']['label'] = 'Name Contains';
+$handler->display->display_options['filters']['name_1']['expose']['identifier'] = 'name';
+$handler->display->display_options['filters']['name_1']['expose']['remember_roles'] = array(
+  2 => '2',
+  1 => 0,
+  3 => 0,
+);
+/* Filter criterion: Chado Cvterm: Definition */
+$handler->display->display_options['filters']['definition']['id'] = 'definition';
+$handler->display->display_options['filters']['definition']['table'] = 'cvterm';
+$handler->display->display_options['filters']['definition']['field'] = 'definition';
+$handler->display->display_options['filters']['definition']['operator'] = 'contains';
+$handler->display->display_options['filters']['definition']['group'] = '0';
+$handler->display->display_options['filters']['definition']['exposed'] = TRUE;
+$handler->display->display_options['filters']['definition']['expose']['operator_id'] = 'definition_op';
+$handler->display->display_options['filters']['definition']['expose']['label'] = 'Definition Contains';
+$handler->display->display_options['filters']['definition']['expose']['operator'] = 'definition_op';
+$handler->display->display_options['filters']['definition']['expose']['identifier'] = 'definition';
+$handler->display->display_options['filters']['definition']['expose']['remember_roles'] = array(
+  2 => '2',
+  1 => 0,
+  3 => 0,
+);
 
-  /** MANUALLY ADD since filter handler no exporting correctly
-   $handler->display->display_options['filters']['name']['expose']['values_form_type'] = 'select';
-   $handler->display->display_options['filters']['name']['expose']['select_multiple'] = FALSE;
-   $handler->display->display_options['filters']['name']['expose']['select_optional'] = TRUE;
-   $handler->display->display_options['filters']['name']['expose']['max_length'] = 40;
+/* Display: Page */
+$handler = $view->new_display('page', 'Page', 'page_1');
+$handler->display->display_options['path'] = 'admin/tripal/storage/chado/cvterms';
+$handler->display->display_options['menu']['type'] = 'normal';
+$handler->display->display_options['menu']['title'] = 'Terms';
+$handler->display->display_options['menu']['description'] = 'A listing of a controlled vocabulary terms for a given vocabulary';
+$handler->display->display_options['menu']['weight'] = '-8';
+$handler->display->display_options['menu']['name'] = 'management';
+$handler->display->display_options['menu']['context'] = 0;
+$handler->display->display_options['menu']['context_only_inline'] = 0;
 
-   $handler->display->display_options['filters']['name_1']['expose']['values_form_type'] = 'textfield';
-   $handler->display->display_options['filters']['name_1']['expose']['select_multiple'] = FALSE;
-   $handler->display->display_options['filters']['name_1']['expose']['select_optional'] = FALSE;
-   $handler->display->display_options['filters']['name_1']['expose']['max_length'] = 40;
-   */
 
   return $view;
 }

+ 7 - 7
tripal_chado/views_handlers/chado_views_handler_filter.inc

@@ -27,7 +27,7 @@ class chado_views_handler_filter_boolean extends views_handler_filter_boolean_op
    */
   function query() {
 
-    // Adds joins to chado_entity and the chado table this field is from.
+    // Adds joins to chado entity and the chado table this field is from.
     $alias = _chado_views_add_table_joins($this);
 
     // Booleans in chado are stored t/f.
@@ -48,7 +48,7 @@ class chado_views_handler_filter_date extends views_handler_filter_date {
    */
   function query() {
 
-    // Adds joins to chado_entity and the chado table this field is from.
+    // Adds joins to chado entity and the chado table this field is from.
     $alias = _chado_views_add_table_joins($this);
 
     // Then allow the parent handler to add the where.
@@ -99,7 +99,7 @@ class chado_views_handler_filter_fk extends views_handler_filter {
    */
   function query() {
 
-    // Adds joins to chado_entity and the chado table this field is from.
+    // Adds joins to chado entity and the chado table this field is from.
     $alias = _chado_views_add_table_joins($this);
 
     // We need to do a quick fix for multiple values selected.
@@ -391,7 +391,7 @@ class chado_views_handler_filter_string extends views_handler_filter_string {
 
   function query() {
 
-    // Adds joins to chado_entity and the chado table this field is from.
+    // Adds joins to chado entity and the chado table this field is from.
     $alias = _chado_views_add_table_joins($this);
 
     // Finally add the restriction on the chado table including the value entered by the filter.
@@ -414,16 +414,16 @@ class chado_views_handler_filter_string extends views_handler_filter_string {
  */
 function _chado_views_add_table_joins(&$handler) {
 
-  // First we need to join to the chado_entity table where the link between an
+  // First we need to join to the chado entity table where the link between an
   // entity and it's chado record is stored.
   $join = new views_join();
   $join->construct('chado_entity', $handler->table, 'id', 'chado_entity_id');
   $alias = $handler->query->add_relationship('chado_entity', $join, $handler->table_alias, $handler->relationship);
 
-  // Restrict the chado_entity join to only return the table this field is from.
+  // Restrict the chado entity join to only return the table this field is from.
   $handler->query->add_where(0, $alias . '.data_table', $handler->definition['chado_table'], '=');
 
-  // Now, we need to join from chado_entity to the chado table needed by this field.
+  // Now, we need to join from chado entity to the chado table needed by this field.
   // This only works if the field is from the base table.
   // @todo: fix handler to work with non-base tables.
   $join = new views_join();

+ 292 - 291
tripal_chado_views/tripal_chado_views.views_default.inc

@@ -24,300 +24,301 @@ function tripal_chado_views_views_default_views() {
  */
 function tripal_chado_views_defaultview_admin_integrations() {
 
-  $view = new view();
-  $view->name = 'tripal_views_admin_integrations';
-  $view->description = 'DO NOT DISABLE';
-  $view->tag = 'tripal admin';
-  $view->base_table = 'tripal_views';
-  $view->human_name = 'Tripal Views (Admin)';
-  $view->core = 7;
-  $view->api_version = '3.0';
-  $view->disabled = FALSE; /* Edit this to true to make a default view disabled initially */
+$view = new view();
+$view->name = 'tripal_views_admin_integrations';
+$view->description = 'DO NOT DISABLE';
+$view->tag = 'tripal admin';
+$view->base_table = 'tripal_views';
+$view->human_name = 'Tripal Views (Admin)';
+$view->core = 7;
+$view->api_version = '3.0';
+$view->disabled = FALSE; /* Edit this to true to make a default view disabled initially */
 
-  /* Display: Master */
-  $handler = $view->new_display('default', 'Master', 'default');
-  $handler->display->display_options['title'] = 'Tripal Views Integrations';
-  $handler->display->display_options['use_more_always'] = FALSE;
-  $handler->display->display_options['access']['type'] = 'perm';
-  $handler->display->display_options['access']['perm'] = 'manage tripal_views_integration';
-  $handler->display->display_options['cache']['type'] = 'none';
-  $handler->display->display_options['query']['type'] = 'views_query';
-  $handler->display->display_options['exposed_form']['type'] = 'basic';
-  $handler->display->display_options['exposed_form']['options']['submit_button'] = 'Filter';
-  $handler->display->display_options['pager']['type'] = 'full';
-  $handler->display->display_options['pager']['options']['items_per_page'] = '25';
-  $handler->display->display_options['style_plugin'] = 'table';
-  $handler->display->display_options['style_options']['columns'] = array(
-    'name' => 'name',
-    'table_name' => 'table_name',
-    'mv_table' => 'mv_table',
-    'comment' => 'comment',
-    'base_table' => 'base_table',
-    'priority' => 'priority',
-  );
-  $handler->display->display_options['style_options']['default'] = '-1';
-  $handler->display->display_options['style_options']['info'] = array(
-    'name' => array(
-      'sortable' => 1,
-      'default_sort_order' => 'asc',
-      'align' => '',
-      'separator' => '',
-      'empty_column' => 0,
-    ),
-    'table_name' => array(
-      'sortable' => 1,
-      'default_sort_order' => 'asc',
-      'align' => '',
-      'separator' => '',
-      'empty_column' => 0,
-    ),
-    'mv_table' => array(
-      'sortable' => 1,
-      'default_sort_order' => 'asc',
-      'align' => '',
-      'separator' => '',
-      'empty_column' => 0,
-    ),
-    'comment' => array(
-      'sortable' => 0,
-      'default_sort_order' => 'asc',
-      'align' => '',
-      'separator' => '',
-      'empty_column' => 0,
-    ),
-    'base_table' => array(
-      'sortable' => 1,
-      'default_sort_order' => 'asc',
-      'align' => '',
-      'separator' => '',
-      'empty_column' => 0,
-    ),
-    'priority' => array(
-      'sortable' => 1,
-      'default_sort_order' => 'asc',
-      'align' => '',
-      'separator' => '',
-      'empty_column' => 0,
-    ),
-  );
-  /* Header: Global: Text area */
-  $handler->display->display_options['header']['area']['id'] = 'area';
-  $handler->display->display_options['header']['area']['table'] = 'views';
-  $handler->display->display_options['header']['area']['field'] = 'area';
-  $handler->display->display_options['header']['area']['label'] = 'Description';
-  $handler->display->display_options['header']['area']['empty'] = TRUE;
-  $handler->display->display_options['header']['area']['content'] = '<p>The following tables are available for integration with Drupal Views. If a table is integrated more than once, then the setup with the lightest priority will be used. For example, if you have created a custom setup with a priority of -5 then that will be used instead of the default setup with priority 10. Priorities range from -10 to +10 where a setup with -10 has greater precedent than any other and +10 has the least.</p>';
-  $handler->display->display_options['header']['area']['format'] = 'filtered_html';
-  /* Header: Global: Action Links */
-  $handler->display->display_options['header']['action_links_area']['id'] = 'action_links_area';
-  $handler->display->display_options['header']['action_links_area']['table'] = 'views';
-  $handler->display->display_options['header']['action_links_area']['field'] = 'action_links_area';
-  $handler->display->display_options['header']['action_links_area']['label'] = 'Add Links';
-  $handler->display->display_options['header']['action_links_area']['empty'] = TRUE;
-  $handler->display->display_options['header']['action_links_area']['link-1'] = array(
-    'label-1' => 'Add New Integration',
-    'path-1' => 'admin/tripal/storage/chado/views-integration/new',
-  );
-  $handler->display->display_options['header']['action_links_area']['link-2'] = array(
-    'label-2' => 'Import Integration',
-    'path-2' => 'admin/tripal/storage/chado/views-integration/import',
-  );
-  $handler->display->display_options['header']['action_links_area']['link-3'] = array(
-    'label-3' => '',
-    'path-3' => '',
-  );
-  $handler->display->display_options['header']['action_links_area']['link-4'] = array(
-    'label-4' => '',
-    'path-4' => '',
-  );
-  /* Header: Global: Action Links */
-  $handler->display->display_options['header']['action_links_area_1']['id'] = 'action_links_area_1';
-  $handler->display->display_options['header']['action_links_area_1']['table'] = 'views';
-  $handler->display->display_options['header']['action_links_area_1']['field'] = 'action_links_area';
-  $handler->display->display_options['header']['action_links_area_1']['label'] = 'Delete Links';
-  $handler->display->display_options['header']['action_links_area_1']['empty'] = TRUE;
-  $handler->display->display_options['header']['action_links_area_1']['link-1'] = array(
-    'label-1' => 'Delete ALL Integrations',
-    'path-1' => 'admin/tripal/storage/chado/views-integration/delete-all/confirm',
-  );
-  $handler->display->display_options['header']['action_links_area_1']['link-2'] = array(
-    'label-2' => '',
-    'path-2' => '',
-  );
-  $handler->display->display_options['header']['action_links_area_1']['link-3'] = array(
-    'label-3' => '',
-    'path-3' => '',
-  );
-  $handler->display->display_options['header']['action_links_area_1']['link-4'] = array(
-    'label-4' => '',
-    'path-4' => '',
-  );
-  /* Field: Tripal Views Integration: Setup ID */
-  $handler->display->display_options['fields']['setup_id']['id'] = 'setup_id';
-  $handler->display->display_options['fields']['setup_id']['table'] = 'tripal_views';
-  $handler->display->display_options['fields']['setup_id']['field'] = 'setup_id';
-  $handler->display->display_options['fields']['setup_id']['exclude'] = TRUE;
-  $handler->display->display_options['fields']['setup_id']['separator'] = '';
-  /* Field: Tripal Views Integration: Name */
-  $handler->display->display_options['fields']['name']['id'] = 'name';
-  $handler->display->display_options['fields']['name']['table'] = 'tripal_views';
-  $handler->display->display_options['fields']['name']['field'] = 'name';
-  /* Field: Tripal Views Integration: Chado Table Name */
-  $handler->display->display_options['fields']['table_name']['id'] = 'table_name';
-  $handler->display->display_options['fields']['table_name']['table'] = 'tripal_views';
-  $handler->display->display_options['fields']['table_name']['field'] = 'table_name';
-  /* Field: Tripal Materialized Views: Table */
-  $handler->display->display_options['fields']['mv_table']['id'] = 'mv_table';
-  $handler->display->display_options['fields']['mv_table']['table'] = 'tripal_mviews';
-  $handler->display->display_options['fields']['mv_table']['field'] = 'mv_table';
-  $handler->display->display_options['fields']['mv_table']['label'] = 'Materialized View';
-  /* Field: Tripal Views Integration: Description */
-  $handler->display->display_options['fields']['comment']['id'] = 'comment';
-  $handler->display->display_options['fields']['comment']['table'] = 'tripal_views';
-  $handler->display->display_options['fields']['comment']['field'] = 'comment';
-  /* Field: Tripal Views Integration: Base Table? */
-  $handler->display->display_options['fields']['base_table']['id'] = 'base_table';
-  $handler->display->display_options['fields']['base_table']['table'] = 'tripal_views';
-  $handler->display->display_options['fields']['base_table']['field'] = 'base_table';
-  $handler->display->display_options['fields']['base_table']['not'] = 0;
-  /* Field: Tripal Views Integration: Priority */
-  $handler->display->display_options['fields']['priority']['id'] = 'priority';
-  $handler->display->display_options['fields']['priority']['table'] = 'tripal_views';
-  $handler->display->display_options['fields']['priority']['field'] = 'priority';
-  $handler->display->display_options['fields']['priority']['separator'] = '';
-  /* Field: Global: Custom text */
-  $handler->display->display_options['fields']['nothing']['id'] = 'nothing';
-  $handler->display->display_options['fields']['nothing']['table'] = 'views';
-  $handler->display->display_options['fields']['nothing']['field'] = 'nothing';
-  $handler->display->display_options['fields']['nothing']['label'] = 'Edit Link';
-  $handler->display->display_options['fields']['nothing']['exclude'] = TRUE;
-  $handler->display->display_options['fields']['nothing']['alter']['text'] = 'edit';
-  $handler->display->display_options['fields']['nothing']['alter']['make_link'] = TRUE;
-  $handler->display->display_options['fields']['nothing']['alter']['path'] = 'admin/tripal/storage/chado/views-integration/edit/[setup_id]';
-  /* Field: Global: Custom text */
-  $handler->display->display_options['fields']['nothing_1']['id'] = 'nothing_1';
-  $handler->display->display_options['fields']['nothing_1']['table'] = 'views';
-  $handler->display->display_options['fields']['nothing_1']['field'] = 'nothing';
-  $handler->display->display_options['fields']['nothing_1']['label'] = 'Delete Link';
-  $handler->display->display_options['fields']['nothing_1']['exclude'] = TRUE;
-  $handler->display->display_options['fields']['nothing_1']['alter']['text'] = 'delete';
-  $handler->display->display_options['fields']['nothing_1']['alter']['make_link'] = TRUE;
-  $handler->display->display_options['fields']['nothing_1']['alter']['path'] = 'admin/tripal/storage/chado/views-integration/delete/[setup_id]';
-  /* Field: Global: Custom text */
-  $handler->display->display_options['fields']['nothing_2']['id'] = 'nothing_2';
-  $handler->display->display_options['fields']['nothing_2']['table'] = 'views';
-  $handler->display->display_options['fields']['nothing_2']['field'] = 'nothing';
-  $handler->display->display_options['fields']['nothing_2']['label'] = 'Export Link';
-  $handler->display->display_options['fields']['nothing_2']['exclude'] = TRUE;
-  $handler->display->display_options['fields']['nothing_2']['alter']['text'] = 'export';
-  $handler->display->display_options['fields']['nothing_2']['alter']['make_link'] = TRUE;
-  $handler->display->display_options['fields']['nothing_2']['alter']['path'] = 'admin/tripal/storage/chado/views-integration/export/[setup_id]';
-  /* Field: Global: Custom text */
-  $handler->display->display_options['fields']['nothing_3']['id'] = 'nothing_3';
-  $handler->display->display_options['fields']['nothing_3']['table'] = 'views';
-  $handler->display->display_options['fields']['nothing_3']['field'] = 'nothing';
-  $handler->display->display_options['fields']['nothing_3']['label'] = '';
-  $handler->display->display_options['fields']['nothing_3']['alter']['text'] = '[nothing]   [nothing_1]<br />
+/* Display: Master */
+$handler = $view->new_display('default', 'Master', 'default');
+$handler->display->display_options['title'] = 'Tripal Views Integrations';
+$handler->display->display_options['use_more_always'] = FALSE;
+$handler->display->display_options['access']['type'] = 'perm';
+$handler->display->display_options['access']['perm'] = 'manage tripal_views_integration';
+$handler->display->display_options['cache']['type'] = 'none';
+$handler->display->display_options['query']['type'] = 'views_query';
+$handler->display->display_options['exposed_form']['type'] = 'basic';
+$handler->display->display_options['exposed_form']['options']['submit_button'] = 'Filter';
+$handler->display->display_options['pager']['type'] = 'full';
+$handler->display->display_options['pager']['options']['items_per_page'] = '25';
+$handler->display->display_options['style_plugin'] = 'table';
+$handler->display->display_options['style_options']['columns'] = array(
+  'name' => 'name',
+  'table_name' => 'table_name',
+  'mv_table' => 'mv_table',
+  'comment' => 'comment',
+  'base_table' => 'base_table',
+  'priority' => 'priority',
+);
+$handler->display->display_options['style_options']['default'] = '-1';
+$handler->display->display_options['style_options']['info'] = array(
+  'name' => array(
+    'sortable' => 1,
+    'default_sort_order' => 'asc',
+    'align' => '',
+    'separator' => '',
+    'empty_column' => 0,
+  ),
+  'table_name' => array(
+    'sortable' => 1,
+    'default_sort_order' => 'asc',
+    'align' => '',
+    'separator' => '',
+    'empty_column' => 0,
+  ),
+  'mv_table' => array(
+    'sortable' => 1,
+    'default_sort_order' => 'asc',
+    'align' => '',
+    'separator' => '',
+    'empty_column' => 0,
+  ),
+  'comment' => array(
+    'sortable' => 0,
+    'default_sort_order' => 'asc',
+    'align' => '',
+    'separator' => '',
+    'empty_column' => 0,
+  ),
+  'base_table' => array(
+    'sortable' => 1,
+    'default_sort_order' => 'asc',
+    'align' => '',
+    'separator' => '',
+    'empty_column' => 0,
+  ),
+  'priority' => array(
+    'sortable' => 1,
+    'default_sort_order' => 'asc',
+    'align' => '',
+    'separator' => '',
+    'empty_column' => 0,
+  ),
+);
+/* Header: Global: Text area */
+$handler->display->display_options['header']['area']['id'] = 'area';
+$handler->display->display_options['header']['area']['table'] = 'views';
+$handler->display->display_options['header']['area']['field'] = 'area';
+$handler->display->display_options['header']['area']['label'] = 'Description';
+$handler->display->display_options['header']['area']['empty'] = TRUE;
+$handler->display->display_options['header']['area']['content'] = '<p>The following tables are available for integration with Drupal Views. If a table is integrated more than once, then the setup with the lightest priority will be used. For example, if you have created a custom setup with a priority of -5 then that will be used instead of the default setup with priority 10. Priorities range from -10 to +10 where a setup with -10 has greater precedent than any other and +10 has the least.</p>';
+$handler->display->display_options['header']['area']['format'] = 'filtered_html';
+/* Header: Global: Action Links */
+$handler->display->display_options['header']['action_links_area']['id'] = 'action_links_area';
+$handler->display->display_options['header']['action_links_area']['table'] = 'views';
+$handler->display->display_options['header']['action_links_area']['field'] = 'action_links_area';
+$handler->display->display_options['header']['action_links_area']['label'] = 'Add Links';
+$handler->display->display_options['header']['action_links_area']['empty'] = TRUE;
+$handler->display->display_options['header']['action_links_area']['link-1'] = array(
+  'label-1' => 'Add New Integration',
+  'path-1' => 'admin/tripal/storage/chado/views-integration/new',
+);
+$handler->display->display_options['header']['action_links_area']['link-2'] = array(
+  'label-2' => 'Import Integration',
+  'path-2' => 'admin/tripal/storage/chado/views-integration/import',
+);
+$handler->display->display_options['header']['action_links_area']['link-3'] = array(
+  'label-3' => '',
+  'path-3' => '',
+);
+$handler->display->display_options['header']['action_links_area']['link-4'] = array(
+  'label-4' => '',
+  'path-4' => '',
+);
+/* Header: Global: Action Links */
+$handler->display->display_options['header']['action_links_area_1']['id'] = 'action_links_area_1';
+$handler->display->display_options['header']['action_links_area_1']['table'] = 'views';
+$handler->display->display_options['header']['action_links_area_1']['field'] = 'action_links_area';
+$handler->display->display_options['header']['action_links_area_1']['label'] = 'Delete Links';
+$handler->display->display_options['header']['action_links_area_1']['empty'] = TRUE;
+$handler->display->display_options['header']['action_links_area_1']['link-1'] = array(
+  'label-1' => 'Delete ALL Integrations',
+  'path-1' => 'admin/tripal/storage/chado/views-integration/delete-all/confirm',
+);
+$handler->display->display_options['header']['action_links_area_1']['link-2'] = array(
+  'label-2' => '',
+  'path-2' => '',
+);
+$handler->display->display_options['header']['action_links_area_1']['link-3'] = array(
+  'label-3' => '',
+  'path-3' => '',
+);
+$handler->display->display_options['header']['action_links_area_1']['link-4'] = array(
+  'label-4' => '',
+  'path-4' => '',
+);
+/* Field: Tripal Views Integration: Setup ID */
+$handler->display->display_options['fields']['setup_id']['id'] = 'setup_id';
+$handler->display->display_options['fields']['setup_id']['table'] = 'tripal_views';
+$handler->display->display_options['fields']['setup_id']['field'] = 'setup_id';
+$handler->display->display_options['fields']['setup_id']['exclude'] = TRUE;
+$handler->display->display_options['fields']['setup_id']['separator'] = '';
+/* Field: Tripal Views Integration: Name */
+$handler->display->display_options['fields']['name']['id'] = 'name';
+$handler->display->display_options['fields']['name']['table'] = 'tripal_views';
+$handler->display->display_options['fields']['name']['field'] = 'name';
+/* Field: Tripal Views Integration: Chado Table Name */
+$handler->display->display_options['fields']['table_name']['id'] = 'table_name';
+$handler->display->display_options['fields']['table_name']['table'] = 'tripal_views';
+$handler->display->display_options['fields']['table_name']['field'] = 'table_name';
+/* Field: Tripal Materialized Views: Table */
+$handler->display->display_options['fields']['mv_table']['id'] = 'mv_table';
+$handler->display->display_options['fields']['mv_table']['table'] = 'tripal_mviews';
+$handler->display->display_options['fields']['mv_table']['field'] = 'mv_table';
+$handler->display->display_options['fields']['mv_table']['label'] = 'Materialized View';
+/* Field: Tripal Views Integration: Description */
+$handler->display->display_options['fields']['comment']['id'] = 'comment';
+$handler->display->display_options['fields']['comment']['table'] = 'tripal_views';
+$handler->display->display_options['fields']['comment']['field'] = 'comment';
+/* Field: Tripal Views Integration: Base Table? */
+$handler->display->display_options['fields']['base_table']['id'] = 'base_table';
+$handler->display->display_options['fields']['base_table']['table'] = 'tripal_views';
+$handler->display->display_options['fields']['base_table']['field'] = 'base_table';
+$handler->display->display_options['fields']['base_table']['not'] = 0;
+/* Field: Tripal Views Integration: Priority */
+$handler->display->display_options['fields']['priority']['id'] = 'priority';
+$handler->display->display_options['fields']['priority']['table'] = 'tripal_views';
+$handler->display->display_options['fields']['priority']['field'] = 'priority';
+$handler->display->display_options['fields']['priority']['separator'] = '';
+/* Field: Global: Custom text */
+$handler->display->display_options['fields']['nothing']['id'] = 'nothing';
+$handler->display->display_options['fields']['nothing']['table'] = 'views';
+$handler->display->display_options['fields']['nothing']['field'] = 'nothing';
+$handler->display->display_options['fields']['nothing']['label'] = 'Edit Link';
+$handler->display->display_options['fields']['nothing']['exclude'] = TRUE;
+$handler->display->display_options['fields']['nothing']['alter']['text'] = 'edit';
+$handler->display->display_options['fields']['nothing']['alter']['make_link'] = TRUE;
+$handler->display->display_options['fields']['nothing']['alter']['path'] = 'admin/tripal/storage/chado/views-integration/edit/[setup_id]';
+/* Field: Global: Custom text */
+$handler->display->display_options['fields']['nothing_1']['id'] = 'nothing_1';
+$handler->display->display_options['fields']['nothing_1']['table'] = 'views';
+$handler->display->display_options['fields']['nothing_1']['field'] = 'nothing';
+$handler->display->display_options['fields']['nothing_1']['label'] = 'Delete Link';
+$handler->display->display_options['fields']['nothing_1']['exclude'] = TRUE;
+$handler->display->display_options['fields']['nothing_1']['alter']['text'] = 'delete';
+$handler->display->display_options['fields']['nothing_1']['alter']['make_link'] = TRUE;
+$handler->display->display_options['fields']['nothing_1']['alter']['path'] = 'admin/tripal/storage/chado/views-integration/delete/[setup_id]';
+/* Field: Global: Custom text */
+$handler->display->display_options['fields']['nothing_2']['id'] = 'nothing_2';
+$handler->display->display_options['fields']['nothing_2']['table'] = 'views';
+$handler->display->display_options['fields']['nothing_2']['field'] = 'nothing';
+$handler->display->display_options['fields']['nothing_2']['label'] = 'Export Link';
+$handler->display->display_options['fields']['nothing_2']['exclude'] = TRUE;
+$handler->display->display_options['fields']['nothing_2']['alter']['text'] = 'export';
+$handler->display->display_options['fields']['nothing_2']['alter']['make_link'] = TRUE;
+$handler->display->display_options['fields']['nothing_2']['alter']['path'] = 'admin/tripal/storage/chado/views-integration/export/[setup_id]';
+/* Field: Global: Custom text */
+$handler->display->display_options['fields']['nothing_3']['id'] = 'nothing_3';
+$handler->display->display_options['fields']['nothing_3']['table'] = 'views';
+$handler->display->display_options['fields']['nothing_3']['field'] = 'nothing';
+$handler->display->display_options['fields']['nothing_3']['label'] = '';
+$handler->display->display_options['fields']['nothing_3']['alter']['text'] = '[nothing]   [nothing_1]<br />
   [nothing_2]';
-  $handler->display->display_options['fields']['nothing_3']['element_class'] = 'short-column';
-  $handler->display->display_options['fields']['nothing_3']['element_label_class'] = 'short-column';
-  $handler->display->display_options['fields']['nothing_3']['element_label_colon'] = FALSE;
-  /* Sort criterion: Tripal Views Integration: Chado Table Name */
-  $handler->display->display_options['sorts']['table_name']['id'] = 'table_name';
-  $handler->display->display_options['sorts']['table_name']['table'] = 'tripal_views';
-  $handler->display->display_options['sorts']['table_name']['field'] = 'table_name';
-  /* Sort criterion: Tripal Views Integration: Priority */
-  $handler->display->display_options['sorts']['priority']['id'] = 'priority';
-  $handler->display->display_options['sorts']['priority']['table'] = 'tripal_views';
-  $handler->display->display_options['sorts']['priority']['field'] = 'priority';
-  /* Filter criterion: Tripal Views Integration: Name */
-  $handler->display->display_options['filters']['name']['id'] = 'name';
-  $handler->display->display_options['filters']['name']['table'] = 'tripal_views';
-  $handler->display->display_options['filters']['name']['field'] = 'name';
-  $handler->display->display_options['filters']['name']['operator'] = 'contains';
-  $handler->display->display_options['filters']['name']['group'] = 1;
-  $handler->display->display_options['filters']['name']['exposed'] = TRUE;
-  $handler->display->display_options['filters']['name']['expose']['operator_id'] = 'name_op';
-  $handler->display->display_options['filters']['name']['expose']['label'] = 'Integration Name Contains';
-  $handler->display->display_options['filters']['name']['expose']['operator'] = 'name_op';
-  $handler->display->display_options['filters']['name']['expose']['identifier'] = 'name';
-  $handler->display->display_options['filters']['name']['expose']['remember_roles'] = array(
-    2 => '2',
-    1 => 0,
-    3 => 0,
-  );
-  /* Filter criterion: Tripal Views Integration: Chado Table Name */
-  $handler->display->display_options['filters']['table_name']['id'] = 'table_name';
-  $handler->display->display_options['filters']['table_name']['table'] = 'tripal_views';
-  $handler->display->display_options['filters']['table_name']['field'] = 'table_name';
-  $handler->display->display_options['filters']['table_name']['group'] = 1;
-  $handler->display->display_options['filters']['table_name']['exposed'] = TRUE;
-  $handler->display->display_options['filters']['table_name']['expose']['operator_id'] = 'table_name_op';
-  $handler->display->display_options['filters']['table_name']['expose']['label'] = 'Chado Table Name';
-  $handler->display->display_options['filters']['table_name']['expose']['operator'] = 'table_name_op';
-  $handler->display->display_options['filters']['table_name']['expose']['identifier'] = 'table_name';
-  $handler->display->display_options['filters']['table_name']['expose']['remember_roles'] = array(
-    2 => '2',
-    1 => 0,
-    3 => 0,
-  );
-  /* Filter criterion: Tripal Materialized Views: Table */
-  $handler->display->display_options['filters']['mv_table']['id'] = 'mv_table';
-  $handler->display->display_options['filters']['mv_table']['table'] = 'tripal_mviews';
-  $handler->display->display_options['filters']['mv_table']['field'] = 'mv_table';
-  $handler->display->display_options['filters']['mv_table']['group'] = 1;
-  $handler->display->display_options['filters']['mv_table']['exposed'] = TRUE;
-  $handler->display->display_options['filters']['mv_table']['expose']['operator_id'] = 'mv_table_op';
-  $handler->display->display_options['filters']['mv_table']['expose']['label'] = 'Materialized View Table Name';
-  $handler->display->display_options['filters']['mv_table']['expose']['operator'] = 'mv_table_op';
-  $handler->display->display_options['filters']['mv_table']['expose']['identifier'] = 'mv_table';
-  $handler->display->display_options['filters']['mv_table']['expose']['remember_roles'] = array(
-    2 => '2',
-    1 => 0,
-    3 => 0,
-  );
-  /* Filter criterion: Tripal Views Integration: Priority */
-  $handler->display->display_options['filters']['priority']['id'] = 'priority';
-  $handler->display->display_options['filters']['priority']['table'] = 'tripal_views';
-  $handler->display->display_options['filters']['priority']['field'] = 'priority';
-  $handler->display->display_options['filters']['priority']['group'] = 1;
-  $handler->display->display_options['filters']['priority']['exposed'] = TRUE;
-  $handler->display->display_options['filters']['priority']['expose']['operator_id'] = 'priority_op';
-  $handler->display->display_options['filters']['priority']['expose']['label'] = 'Priority';
-  $handler->display->display_options['filters']['priority']['expose']['operator'] = 'priority_op';
-  $handler->display->display_options['filters']['priority']['expose']['identifier'] = 'priority';
-  $handler->display->display_options['filters']['priority']['expose']['remember_roles'] = array(
-    2 => '2',
-    1 => 0,
-    3 => 0,
-  );
-  /* Filter criterion: Tripal Views Integration: Base Table? */
-  $handler->display->display_options['filters']['base_table']['id'] = 'base_table';
-  $handler->display->display_options['filters']['base_table']['table'] = 'tripal_views';
-  $handler->display->display_options['filters']['base_table']['field'] = 'base_table';
-  $handler->display->display_options['filters']['base_table']['value'] = 'All';
-  $handler->display->display_options['filters']['base_table']['group'] = 1;
-  $handler->display->display_options['filters']['base_table']['exposed'] = TRUE;
-  $handler->display->display_options['filters']['base_table']['expose']['operator_id'] = '';
-  $handler->display->display_options['filters']['base_table']['expose']['label'] = 'Integrates a Base Table?';
-  $handler->display->display_options['filters']['base_table']['expose']['operator'] = 'base_table_op';
-  $handler->display->display_options['filters']['base_table']['expose']['identifier'] = 'base_table';
-  $handler->display->display_options['filters']['base_table']['expose']['remember_roles'] = array(
-    2 => '2',
-    1 => 0,
-    3 => 0,
-  );
+$handler->display->display_options['fields']['nothing_3']['element_class'] = 'short-column';
+$handler->display->display_options['fields']['nothing_3']['element_label_class'] = 'short-column';
+$handler->display->display_options['fields']['nothing_3']['element_label_colon'] = FALSE;
+/* Sort criterion: Tripal Views Integration: Chado Table Name */
+$handler->display->display_options['sorts']['table_name']['id'] = 'table_name';
+$handler->display->display_options['sorts']['table_name']['table'] = 'tripal_views';
+$handler->display->display_options['sorts']['table_name']['field'] = 'table_name';
+/* Sort criterion: Tripal Views Integration: Priority */
+$handler->display->display_options['sorts']['priority']['id'] = 'priority';
+$handler->display->display_options['sorts']['priority']['table'] = 'tripal_views';
+$handler->display->display_options['sorts']['priority']['field'] = 'priority';
+/* Filter criterion: Tripal Views Integration: Name */
+$handler->display->display_options['filters']['name']['id'] = 'name';
+$handler->display->display_options['filters']['name']['table'] = 'tripal_views';
+$handler->display->display_options['filters']['name']['field'] = 'name';
+$handler->display->display_options['filters']['name']['operator'] = 'contains';
+$handler->display->display_options['filters']['name']['group'] = 1;
+$handler->display->display_options['filters']['name']['exposed'] = TRUE;
+$handler->display->display_options['filters']['name']['expose']['operator_id'] = 'name_op';
+$handler->display->display_options['filters']['name']['expose']['label'] = 'Integration Name Contains';
+$handler->display->display_options['filters']['name']['expose']['operator'] = 'name_op';
+$handler->display->display_options['filters']['name']['expose']['identifier'] = 'name';
+$handler->display->display_options['filters']['name']['expose']['remember_roles'] = array(
+  2 => '2',
+  1 => 0,
+  3 => 0,
+);
+/* Filter criterion: Tripal Views Integration: Chado Table Name */
+$handler->display->display_options['filters']['table_name']['id'] = 'table_name';
+$handler->display->display_options['filters']['table_name']['table'] = 'tripal_views';
+$handler->display->display_options['filters']['table_name']['field'] = 'table_name';
+$handler->display->display_options['filters']['table_name']['group'] = 1;
+$handler->display->display_options['filters']['table_name']['exposed'] = TRUE;
+$handler->display->display_options['filters']['table_name']['expose']['operator_id'] = 'table_name_op';
+$handler->display->display_options['filters']['table_name']['expose']['label'] = 'Chado Table Name';
+$handler->display->display_options['filters']['table_name']['expose']['operator'] = 'table_name_op';
+$handler->display->display_options['filters']['table_name']['expose']['identifier'] = 'table_name';
+$handler->display->display_options['filters']['table_name']['expose']['remember_roles'] = array(
+  2 => '2',
+  1 => 0,
+  3 => 0,
+);
+/* Filter criterion: Tripal Materialized Views: Table */
+$handler->display->display_options['filters']['mv_table']['id'] = 'mv_table';
+$handler->display->display_options['filters']['mv_table']['table'] = 'tripal_mviews';
+$handler->display->display_options['filters']['mv_table']['field'] = 'mv_table';
+$handler->display->display_options['filters']['mv_table']['group'] = 1;
+$handler->display->display_options['filters']['mv_table']['exposed'] = TRUE;
+$handler->display->display_options['filters']['mv_table']['expose']['operator_id'] = 'mv_table_op';
+$handler->display->display_options['filters']['mv_table']['expose']['label'] = 'Materialized View Table Name';
+$handler->display->display_options['filters']['mv_table']['expose']['operator'] = 'mv_table_op';
+$handler->display->display_options['filters']['mv_table']['expose']['identifier'] = 'mv_table';
+$handler->display->display_options['filters']['mv_table']['expose']['remember_roles'] = array(
+  2 => '2',
+  1 => 0,
+  3 => 0,
+);
+/* Filter criterion: Tripal Views Integration: Priority */
+$handler->display->display_options['filters']['priority']['id'] = 'priority';
+$handler->display->display_options['filters']['priority']['table'] = 'tripal_views';
+$handler->display->display_options['filters']['priority']['field'] = 'priority';
+$handler->display->display_options['filters']['priority']['group'] = 1;
+$handler->display->display_options['filters']['priority']['exposed'] = TRUE;
+$handler->display->display_options['filters']['priority']['expose']['operator_id'] = 'priority_op';
+$handler->display->display_options['filters']['priority']['expose']['label'] = 'Priority';
+$handler->display->display_options['filters']['priority']['expose']['operator'] = 'priority_op';
+$handler->display->display_options['filters']['priority']['expose']['identifier'] = 'priority';
+$handler->display->display_options['filters']['priority']['expose']['remember_roles'] = array(
+  2 => '2',
+  1 => 0,
+  3 => 0,
+);
+/* Filter criterion: Tripal Views Integration: Base Table? */
+$handler->display->display_options['filters']['base_table']['id'] = 'base_table';
+$handler->display->display_options['filters']['base_table']['table'] = 'tripal_views';
+$handler->display->display_options['filters']['base_table']['field'] = 'base_table';
+$handler->display->display_options['filters']['base_table']['value'] = 'All';
+$handler->display->display_options['filters']['base_table']['group'] = 1;
+$handler->display->display_options['filters']['base_table']['exposed'] = TRUE;
+$handler->display->display_options['filters']['base_table']['expose']['operator_id'] = '';
+$handler->display->display_options['filters']['base_table']['expose']['label'] = 'Integrates a Base Table?';
+$handler->display->display_options['filters']['base_table']['expose']['operator'] = 'base_table_op';
+$handler->display->display_options['filters']['base_table']['expose']['identifier'] = 'base_table';
+$handler->display->display_options['filters']['base_table']['expose']['remember_roles'] = array(
+  2 => '2',
+  1 => 0,
+  3 => 0,
+);
 
-  /* Display: Page */
-  $handler = $view->new_display('page', 'Page', 'page');
-  $handler->display->display_options['path'] = 'admin/tripal/views-integration/integrations';
-  $handler->display->display_options['menu']['type'] = 'default tab';
-  $handler->display->display_options['menu']['title'] = 'Integrations';
-  $handler->display->display_options['menu']['weight'] = '-10';
-  $handler->display->display_options['menu']['name'] = 'management';
-  $handler->display->display_options['menu']['context'] = 0;
-  $handler->display->display_options['menu']['context_only_inline'] = 0;
-  $handler->display->display_options['tab_options']['weight'] = '0';
+/* Display: Page */
+$handler = $view->new_display('page', 'Page', 'page');
+$handler->display->display_options['path'] = 'admin/tripal/storage/chado/views-integration';
+$handler->display->display_options['menu']['type'] = 'normal';
+$handler->display->display_options['menu']['title'] = 'Integrations';
+$handler->display->display_options['menu']['description'] = 'Integrates Chado tables with Drupal Views for direct access.';
+$handler->display->display_options['menu']['weight'] = '-10';
+$handler->display->display_options['menu']['name'] = 'management';
+$handler->display->display_options['menu']['context'] = 0;
+$handler->display->display_options['menu']['context_only_inline'] = 0;
+$handler->display->display_options['tab_options']['weight'] = '0';
 
   return $view;
 }