Prechádzať zdrojové kódy

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

Shawna 7 rokov pred
rodič
commit
e70e91e0eb
78 zmenil súbory, kde vykonal 2319 pridanie a 1182 odobranie
  1. 2 2
      legacy/tripal_analysis/includes/tripal_analysis.chado_node.inc
  2. 6 6
      legacy/tripal_core/api/tripal_core.DEPRECATED.inc
  3. 3 3
      legacy/tripal_core/api/tripal_core.chado_nodes.api.inc
  4. 4 1
      legacy/tripal_core/api/tripal_core.chado_nodes.relationships.api.inc
  5. 121 11
      legacy/tripal_core/api/tripal_core.chado_nodes.title_and_path.inc
  6. 2 2
      legacy/tripal_core/includes/tripal_core.form_elements.inc
  7. 439 0
      legacy/tripal_core/includes/tripal_core.search.inc
  8. 0 1
      legacy/tripal_core/tripal_core.info
  9. 123 0
      legacy/tripal_core/tripal_core.module
  10. 104 0
      legacy/tripal_core/tripal_core.views_default.inc
  11. 1 1
      legacy/tripal_cv/tripal_cv.module
  12. 1 4
      legacy/tripal_feature/includes/tripal_feature.chado_node.inc
  13. 18 20
      legacy/tripal_feature/theme/templates/tripal_feature_help.tpl.php
  14. 1 1
      legacy/tripal_feature/theme/templates/tripal_feature_sequence.tpl.php
  15. 6 1
      legacy/tripal_feature/theme/templates/tripal_organism_feature_browser.tpl.php
  16. 5 0
      legacy/tripal_feature/theme/tripal_feature.theme.inc
  17. 23 130
      legacy/tripal_feature/tripal_feature.module
  18. 24 19
      legacy/tripal_featuremap/theme/templates/tripal_feature_featurepos.tpl.php
  19. 27 22
      legacy/tripal_featuremap/theme/templates/tripal_featuremap_featurepos.tpl.php
  20. 38 33
      legacy/tripal_genetic/theme/templates/tripal_feature_genotypes.tpl.php
  21. 32 27
      legacy/tripal_genetic/theme/templates/tripal_stock_genotypes.tpl.php
  22. 6 1
      legacy/tripal_library/theme/templates/tripal_library_features.tpl.php
  23. 35 30
      legacy/tripal_natural_diversity/theme/templates/tripal_feature_nd_genotypes.tpl.php
  24. 44 39
      legacy/tripal_natural_diversity/theme/templates/tripal_stock_nd_genotypes.tpl.php
  25. 41 36
      legacy/tripal_natural_diversity/theme/templates/tripal_stock_nd_phenotypes.tpl.php
  26. 1 1
      legacy/tripal_phylogeny/tripal_phylogeny.module
  27. 1 1
      legacy/tripal_pub/includes/tripal_pub.chado_node.inc
  28. 1 1
      legacy/tripal_pub/includes/tripal_pub.pub_search.inc
  29. 8 2
      legacy/tripal_pub/theme/templates/tripal_pub_featuremaps.tpl.php
  30. 6 1
      legacy/tripal_pub/theme/templates/tripal_pub_features.tpl.php
  31. 6 1
      legacy/tripal_pub/theme/templates/tripal_pub_libraries.tpl.php
  32. 6 1
      legacy/tripal_pub/theme/templates/tripal_pub_projects.tpl.php
  33. 6 1
      legacy/tripal_pub/theme/templates/tripal_pub_stocks.tpl.php
  34. 56 0
      legacy/tripal_stock/includes/tripal_stock.chado_node.inc
  35. 7 1
      legacy/tripal_stock/theme/templates/tripal_organism_stocks.tpl.php
  36. 1 57
      legacy/tripal_stock/tripal_stock.module
  37. 35 4
      tripal/api/tripal.jobs.api.inc
  38. 18 9
      tripal/api/tripal.notice.api.inc
  39. 46 44
      tripal/includes/TripalImporter.inc
  40. 128 0
      tripal/includes/tripal.entity.inc
  41. 4 1
      tripal/includes/tripal.jobs.inc
  42. 5 1
      tripal/tripal.drush.inc
  43. 8 2
      tripal/tripal.module
  44. 1 1
      tripal/tripal.views.inc
  45. 10 2
      tripal/tripal.views_default.inc
  46. 2 2
      tripal/views_handlers/tripal_views_handler_filter_select_string.inc
  47. 160 182
      tripal_bulk_loader/includes/tripal_bulk_loader.admin.templates.inc
  48. 0 116
      tripal_bulk_loader/theme/templates/tripal_bulk_loader_modify_template_base_form.tpl.php
  49. 54 0
      tripal_bulk_loader/theme/templates/tripal_bulk_loader_modify_template_base_form_fields.tpl.php
  50. 55 0
      tripal_bulk_loader/theme/templates/tripal_bulk_loader_modify_template_base_form_records.tpl.php
  51. 42 0
      tripal_bulk_loader/theme/tripal_bulk_loader.css
  52. 9 4
      tripal_bulk_loader/tripal_bulk_loader.module
  53. 55 69
      tripal_chado/api/modules/tripal_chado.cv.api.inc
  54. 2 2
      tripal_chado/api/tripal_chado.api.inc
  55. 5 2
      tripal_chado/api/tripal_chado.custom_tables.api.inc
  56. 94 14
      tripal_chado/api/tripal_chado.query.api.inc
  57. 13 7
      tripal_chado/api/tripal_chado.schema.api.inc
  58. 3 3
      tripal_chado/includes/TripalFields/chado_linker__contact/chado_linker__contact.inc
  59. 7 3
      tripal_chado/includes/TripalFields/chado_linker__contact/chado_linker__contact_formatter.inc
  60. 45 49
      tripal_chado/includes/TripalFields/chado_linker__contact/chado_linker__contact_widget.inc
  61. 0 22
      tripal_chado/includes/TripalFields/obi__organism/obi__organism.inc
  62. 35 20
      tripal_chado/includes/TripalImporter/FASTAImporter.inc
  63. 1 1
      tripal_chado/includes/TripalImporter/OBOImporter.inc
  64. 22 9
      tripal_chado/includes/loaders/tripal_chado.pub_importer_AGL.inc
  65. 2 2
      tripal_chado/includes/loaders/tripal_chado.pub_importers.inc
  66. 2 5
      tripal_chado/includes/tripal_chado.cv.inc
  67. 6 66
      tripal_chado/includes/tripal_chado.entity.inc
  68. 9 8
      tripal_chado/includes/tripal_chado.field_storage.inc
  69. 10 6
      tripal_chado/includes/tripal_chado.install.inc
  70. 7 7
      tripal_chado/includes/tripal_chado.migrate.inc
  71. 13 13
      tripal_chado/includes/tripal_chado.seq_extract.inc
  72. 154 21
      tripal_chado/tripal_chado.module
  73. 1 1
      tripal_chado/tripal_chado.views_default.inc
  74. 27 4
      tripal_chado_views/tripal_chado_views.views.inc
  75. 15 14
      tripal_chado_views/views/handlers/tripal_views_handler_filter_select_cvterm.inc
  76. 5 5
      tripal_chado_views/views/handlers/tripal_views_handler_filter_select_id.inc
  77. 3 3
      tripal_chado_views/views/handlers/tripal_views_handler_filter_select_string.inc
  78. 1 1
      tripal_daemon/TripalDaemon.inc

+ 2 - 2
legacy/tripal_analysis/includes/tripal_analysis.chado_node.inc

@@ -171,7 +171,7 @@ function chado_analysis_form($node, &$form_state) {
   );
   $form['programversion']= array(
     '#type' => 'textfield',
-    '#title' => t('Program, Pipeline  or Method version'),
+    '#title' => t('Program, Pipeline  or Method Version'),
     '#required' => TRUE,
     '#default_value' => $programversion,
     '#description' => t("Version description, e.g. TBLASTX 2.0MP-WashU [09-Nov-2000]. Enter 'n/a' if no version is available or applicable."),
@@ -441,7 +441,7 @@ function chado_analysis_insert($node) {
     );
     $analysis = chado_insert_record('analysis', $values);
     if (!$analysis) {
-      drupal_set_message(t('Unable to add analysis.', 'warning'));
+      drupal_set_message(t('Unable to add analysis.'), 'warning');
       tripal_report_error('tripal_analysis', TRIPAL_ERROR, 'Insert analysis: Unable to create analysis where values:%values',
         array('%values' => print_r($values, TRUE)));
       return;

+ 6 - 6
legacy/tripal_core/api/tripal_core.DEPRECATED.inc

@@ -794,7 +794,7 @@ function tripal_job_set_progress($job_id, $percentage) {
 /**
  * @deprecated Restructured API to make naming more readable and consistent.
  * Function was deprecated in Tripal 2.0 and will be removed 2 releases from now.
- * This function has been replaced by tripal_refresh_mview(),  and 
+ * This function has been replaced by tripal_refresh_mview(),  and
  * tripal_delete_mview().
  *
  * @see tripal_refresh_mview() or tripal_delete_mview().
@@ -897,7 +897,7 @@ function tripal_mviews_get_mview_id($view_name) {
       '%new_function' => 'tripal_get_mview_id'
     )
   );
-  
+
   //New API Function
   return tripal_get_mview_id($view_name);
 }
@@ -915,7 +915,7 @@ function tripal_core_delete_property_by_id($basetable, $property_id) {
     'tripal_deprecated',
     TRIPAL_NOTICE,
     "DEPRECATED: %old_function has been replaced with %new_function. This requires manual
-      intervention since the arguements for the two functions are different.
+      intervention since the arguments for the two functions are different.
       Please update your code.",
     array(
       '%old_function'=>'tripal_core_delete_property_by_id',
@@ -958,7 +958,7 @@ function tripal_core_delete_property($basetable, $record_id, $property, $cv_name
     'type_name' => $property,
     'cv_name' => $cv_name,
   );
-  
+
   //New API Function
   return chado_delete_property($record, $property);
 }
@@ -980,7 +980,7 @@ function tripal_core_get_property($basetable, $record_id, $property, $cv_name) {
       '%new_function' => 'chado_get_property'
     )
   );
-  
+
   $record = array(
     'table' => $basetable,
     'id' => $record_id
@@ -1101,7 +1101,7 @@ function tripal_core_update_property_by_id($basetable, $record_id, $property,
     'cv_name' => $cv_name,
     'value' => $value,
   );
-  
+
   // New API Function.
   return chado_update_property($record, $property);
 }

+ 3 - 3
legacy/tripal_core/api/tripal_core.chado_nodes.api.inc

@@ -552,7 +552,7 @@ function chado_node_sync_form($form, &$form_state) {
       // yet been synced.
       $query = "SELECT " . implode(', ', $select) . ' ' .
                'FROM {' . $base_table . '} ' . $base_table . ' ' . implode(' ', $joins) . ' '.
-               "  LEFT JOIN {" . $linking_table . "} CT ON CT.$base_table_id = $base_table.$base_table_id " .
+               "  LEFT JOIN [" . $linking_table . "] CT ON CT.$base_table_id = $base_table.$base_table_id " .
                "WHERE CT.$base_table_id IS NULL";
 
       // extend the where clause if needed
@@ -862,7 +862,7 @@ function chado_node_sync_records($base_table, $max_sync = FALSE,
   $query = "
     SELECT " . implode(', ', $select) . ' ' .
     'FROM {' . $base_table . '} ' . $base_table . ' ' . implode(' ', $joins) . ' '.
-    "  LEFT JOIN {" . $linking_table . "} CT ON CT.$base_table_id = $base_table.$base_table_id " .
+    "  LEFT JOIN [" . $linking_table . "] CT ON CT.$base_table_id = $base_table.$base_table_id " .
     "WHERE CT.$base_table_id IS NULL ";
 
   // extend the where clause if needed
@@ -1245,7 +1245,7 @@ function hook_chado_node_sync_form($form, &$form_state) {
  *
  * Allows you to use this function as your own submit.
  *
- * This might be necessary if you want to add additional arguements to the
+ * This might be necessary if you want to add additional arguments to the
  * tripal job or to call your own sync'ing function if the generic
  * chado_node_sync_records() is not sufficient.
  *

+ 4 - 1
legacy/tripal_core/api/tripal_core.chado_nodes.relationships.api.inc

@@ -1046,7 +1046,10 @@ function chado_add_node_form_relationships_name_to_id_callback($base_table, $nam
 
   $base_key = $base_table.'_id';
 
-  $query = db_select('chado.'.$base_table, 'b')
+  // determine the chado schema.
+  $chado = tripal_get_schema_name('chado');
+
+  $query = db_select($chado . '.' . $base_table, 'b')
     ->fields('b', array($base_key, $name_field))
     ->condition($name_field, '%' . db_like($string) . '%', 'LIKE');
 

+ 121 - 11
legacy/tripal_core/api/tripal_core.chado_nodes.title_and_path.inc

@@ -1304,12 +1304,14 @@ function chado_node_generate_tokens($base_table, $token_prefix = FALSE, $locatio
  * @return
  *   The value of the token
  */
-function chado_get_token_value($token_info, $node) {
+function chado_get_token_value($token_info, $node, $options = array()) {
 
   $token = $token_info['token'];
   $table = $token_info['table'];
   $var = $node;
 
+  $supress_errors = (isset($options['supress_errors'])) ? $options['supress_errors'] : FALSE;
+
   // Iterate through each portion of the location string. An example string
   // might be:  stock > type_id > name.
   $location = explode('>', $token_info['location']);
@@ -1325,11 +1327,13 @@ function chado_get_token_value($token_info, $node) {
         $var = $var->$index;
       }
       else {
-        tripal_report_error('chado_node_api', TRIPAL_WARNING,
-          'Tokens: Unable to determine the value of %token. Things went awry when trying ' .
-          'to access \'%index\' for the following: \'%var\'.',
-          array('%token' => $token, '%index' => $index, '%var' => print_r($var,TRUE))
-        );
+        if (!$supress_errors) {
+          tripal_report_error('chado_node_api', TRIPAL_WARNING,
+            'Tokens: Unable to determine the value of %token. Things went awry when trying ' .
+            'to access \'%index\' for the following: \'%var\'.',
+            array('%token' => $token, '%index' => $index, '%var' => print_r($var,TRUE))
+          );
+        }
         return '';
       }
     }
@@ -1339,11 +1343,13 @@ function chado_get_token_value($token_info, $node) {
       $var = $var[$index];
     }
     else {
-      tripal_report_error('chado_node_api', TRIPAL_WARNING,
-        'Tokens: Unable to determine the value of %token. Things went awry when trying ' .
-        'to access \'%index\' for the following: \'%var\'.',
-        array('%token' => $token, '%index' => $index, '%var' => print_r($var,TRUE))
-      );
+      if (!$supress_errors) {
+        tripal_report_error('chado_node_api', TRIPAL_WARNING,
+          'Tokens: Unable to determine the value of %token. Things went awry when trying ' .
+          'to access \'%index\' for the following: \'%var\'.',
+          array('%token' => $token, '%index' => $index, '%var' => print_r($var,TRUE))
+        );
+      }
       return '';
     }
   }
@@ -1431,3 +1437,107 @@ function tripal_sort_key_length_asc($a, $b) {
     return -1;
   }
 }
+
+/**
+ * Generate a Readable but not necessarily unique format based on a given primary
+ * key token.
+ *
+ * For example, given the token [feature.type_id>cvterm.cvterm_id] you don't
+ * want the actual id indexed but instead would want the term name, [feature.type_id>cvterm.name]
+ */
+function chado_node_get_readable_format($token) {
+
+  // First, lets break down the token into it's parts.
+  // 1. Remove containing brackets.
+  $parts = str_replace(array('[',']'),'',$token);
+  // 2. Break into table clauses.
+  $parts = explode('>',$parts);
+  // 3. Break each table clause into table & field.
+  foreach ($parts as $k => $v) {
+    $parts[$k] = explode('.', $v);
+    if (sizeof($parts[$k]) == 1) {
+      $parts[$k] = explode(':', $v);
+    }
+  }
+  $last_k = $k;
+
+  // Now, we want to find readable fields for the last table specified in the token.
+  // (ie: for cvterm in [feature.type_id>cvterm.cvterm_id])
+  $table = $parts[$last_k][0];
+  $format = array();
+  if ($table == 'organism') {
+    $format[] = preg_replace('/(\w+)\]$/', 'genus]', $token);
+    $format[] = preg_replace('/(\w+)\]$/', 'species]', $token);
+    $format[] = preg_replace('/(\w+)\]$/', 'common_name]', $token);
+    $format = $format[0] . ' ' . $format[1] . ' (' . $format[2] . ')';
+   }
+   elseif ($table == 'dbxref') {
+     $format[] = preg_replace('/(\w+)\]$/', 'accession]', $token);
+     $format[] = preg_replace('/(\w+)\]$/', 'db_id>db.name]', $token);
+     $format = $format[0] . ' (' . $format[1] . ')';
+   }
+   else {
+     $schema = chado_get_schema($table);
+     foreach ($schema['fields'] as $field_name => $details) {
+       if (preg_match('/name/',$field_name)) {
+         $format[] = preg_replace('/(\w+)\]$/', $field_name.']', $token);
+       }
+     }
+     $format = implode(', ',$format);
+   }
+   if (empty($format)) {
+     return FALSE;
+   }
+   return $format;
+ }
+
+ /**
+  * Returns the "location" as specified in the token information based on the
+  * token.
+  */
+ function chado_node_get_location_from_token($token) {
+
+   if (is_array($token) and isset($token['location'])) {
+     return $token['location'];
+   }
+   // If we have been given the token as a string, we can still determine the location
+   // but it takes more work...
+   // First, lets clarify what the location is: the location shows which keys in which
+   // order need to be travelled in order to access the value. For example, the token
+   // [feature.organism_id>organism.genus] would have a location of
+   // feature > organism_id > genus to show that the value is at
+   // $node->feature->organism->genus.
+   elseif (is_string($token)) {
+
+     // First, lets break down the token into it's parts.
+     // 1. Remove containing brackets.
+     $parts = str_replace(array('[',']'),'',$token);
+     // 2. Break into table clauses.
+     $parts = explode('>',$parts);
+     // 3. Break each table clause into table & field.
+     foreach ($parts as $k => $v) {
+       $parts[$k] = explode('.', $v);
+       if (sizeof($parts[$k]) == 1) {
+         $parts[$k] = explode(':', $v);
+       }
+     }
+
+     // This is a base level field that is not a foreign key.
+     if (sizeof($parts) == 1 AND sizeof($parts[0]) == 2) {
+       return $parts[0][0] . ' > ' . $parts[0][1];
+     }
+     // Darn, we have at least one foreign key...
+     elseif (sizeof($parts) > 1 AND sizeof($parts[0]) == 2) {
+       $location = $parts[0][0] . ' > ' . $parts[0][1];
+       foreach ($parts as $k => $p) {
+         if ($k != 0 AND isset($p[1])) {
+           $location .= ' > ' . $p[1];
+         }
+       }
+       return $location;
+     }
+     else {
+       return FALSE;
+     }
+   }
+ }

+ 2 - 2
legacy/tripal_core/includes/tripal_core.form_elements.inc

@@ -177,7 +177,7 @@ function expand_sequence_combo($element, $form_state, $complete_form) {
   $element['upstream'] = array(
      '#type' => 'textfield',
      '#title' => t('Get Upstream Bases'),
-     '#description' => t('Specify the number of upstream bases to include in the sequnce'),
+     '#description' => t('Specify the number of upstream bases to include in the sequence'),
      '#default_value' => $element['#value']['upstream'],
   );
   // add the downstream box
@@ -187,7 +187,7 @@ function expand_sequence_combo($element, $form_state, $complete_form) {
      '#type' => 'textfield',
      '#prefix' => '<br>',
      '#title' => t('Get Downstream Bases'),
-     '#description' => t('Specify the number of downstream bases to include in the sequnce'),
+     '#description' => t('Specify the number of downstream bases to include in the sequence'),
      '#default_value' => $element['#value']['downstream'],
   );
   return $element;

+ 439 - 0
legacy/tripal_core/includes/tripal_core.search.inc

@@ -0,0 +1,439 @@
+<?php
+/**
+ * @file
+ * Adds support for Drupal indexing of Chado.
+ * It's important to note that not all of Chado is indexed but instead
+ * Only fields indicated in hook_search_include_chado_fields().
+ */
+
+/**
+ * Implements hook_search_include_chado_fields().
+ *
+ * This hook allows Tripal Admin/modules to specify which chado fields should be indexed
+ * for searching in a simple manner.
+ *
+ * @return
+ *   An array of chado fields you would like available for indexing. Each element should
+ *   be the name of the table followed by the field and separated by a period. For example.
+ *   feature.uniquename to indicate the uniquename field from the feature table.
+ */
+function tripal_core_search_include_chado_fields() {
+  return array(
+    'organism.genus',
+    'organism.species',
+  );
+}
+
+/**
+ * Implements hook_entity_property_info_alter().
+ *
+ * This is where we actually add the properties to the node entity in order to indicate
+ * which chado fields should be indexed.
+ */
+function tripal_core_entity_property_info_alter(&$info) {
+
+  // We provide a hook to allow Tripal admin to easily add fields to the search api.
+  // We want to invoke all implementations of that hook now for use below.
+  $fields_to_include = module_invoke_all('search_include_chado_fields');
+  $fields_to_include = array_unique($fields_to_include);
+
+  // Retrieve information for all nodes.
+  // We focus on nodes at this point because we need to link search results back to
+  // the entity and we have no entites for non-node chado content in Tripal2.
+  $node_info = module_invoke_all('node_info');
+
+  foreach ($node_info as $n) {
+
+    // Now keep in mind this hook is defined for ALL THE NODE TYPES and we only want
+    // to add extra support for chado so we onle care about chado node types.
+    // We can distinguish chado node types from all others by the existence of
+    // the 'chado_node_api' key which is used for all sorts of beautiful tripal/chado
+    // node integration (ie: adding properties, relationships and dbxrefs to node forms).
+    if (isset($n['chado_node_api'])) {
+      $schema = chado_get_schema($n['chado_node_api']['base_table']);
+
+      // Now we are going to start by adding some defaults. It feels safe to say, we
+      // probably want to index all the "names" so we are going to look through
+      // all the fields and if they contain "name" we are going to add them automatically.
+      foreach ($schema['fields'] as $field_name => $details) {
+
+        $machine_name = $n['chado_node_api']['base_table'] . '.' . $field_name;
+
+        // Try to create a readable label.
+        $label = ucwords(str_replace(array('.','_'),' ',$machine_name));
+
+        // We want to add all name fields and any fields previously indicated to be indexed.
+        if (preg_match('/name/', $field_name) OR in_array($machine_name, $fields_to_include)) {
+
+          if (!isset($info['node']['bundles'][ $n['base'] ]['properties'][$machine_name])) {
+            $info['node']['bundles'][ $n['base'] ]['properties'][$machine_name] = array(
+              'label' => $label,
+              'description' => (isset($details['description'])) ? $details['description'] : '',
+              'type' => ($details['type'] == 'varchar') ? 'text' : $details['type'],
+              'schema field' => '[' . $machine_name . ']',
+              // The following getter callback is a generic function that can retrieve
+              // values for any chado field.
+              'getter callback' => 'tripal_search_chado_token_getter_callback'
+            );
+          }
+        }
+      }
+
+      // We want to add any base foreign keys. This allows you to search for all features
+      // from a given organism. Furthermore, we want to add a single field for each foreign
+      // key that will span content types in order to be exposed as facets.
+      foreach ($schema['foreign keys'] as $table => $fk_details) {
+        foreach ($fk_details['columns'] as $left_field => $right_field) {
+
+          $machine_name = $n['chado_node_api']['base_table'] . '.' . $left_field;
+          $field_details = $schema['fields'][$left_field];
+
+          // Try to create a readable label.
+          $label = $table . ' (' . $machine_name . ')';
+          if (preg_match('/(\w+)_id/',$left_field,$matches)) {
+            // Key only field.
+            $key_label = ucwords(str_replace('_', ' ', $matches[1]));
+
+            // Expanded field.
+            $label = str_replace('_', ' ', $n['chado_node_api']['base_table']);
+            $label .= ' ' . str_replace('_', ' ', $matches[1]);
+            $label = ucwords($label);
+          }
+
+          $keytoken = '[BASE.' . $left_field . '>' . $table . '.' . $right_field . ']';
+          $format = chado_node_get_readable_format($keytoken);
+
+          // First, create the key version. This is best used for facets since it
+          // won't/can't be tokenized along with the other fields. This will be shared
+          // among node types to facillitate use as a facet.
+          $info['node']['properties'][$table . '.' . $right_field .' key'] = array(
+            'label' => $key_label . ' (All Content Types)',
+            'description' => (isset($field_details['description'])) ? $field_details['description'] : '',
+            'type' => 'text',
+            // We include both the token for the current node type and the token for
+            // the parent table. That way the organism node will appear in the results
+            // for the organism key.
+            'schema field' => $format,
+            // The following getter callback is a generic function that can retrieve
+            // values for any chado foreign key.
+            'getter callback' => 'tripal_search_chado_token_across_nodetypes_getter_callback'
+          );
+
+          $pretoken = '[' . $n['chado_node_api']['base_table'] . '.' . $left_field . '>' . $table . '.' . $right_field . ']';
+          $format = chado_node_get_readable_format($pretoken);
+
+          // Add a more readable version that will be tokenized so users can
+          // search for fruitfly and get all features with that as an organism.
+          $info['node']['bundles'][ $n['base'] ]['properties'][$machine_name .' expanded'] = array(
+            'label' => $label . ' (Expanded)',
+            'description' => (isset($field_details['description'])) ? $field_details['description'] : '',
+            'type' => 'text',
+            'schema field' => $format,
+            // The following getter callback is a generic function that can retrieve
+            // values for any chado foreign key.
+            'getter callback' => 'tripal_search_chado_token_getter_callback'
+          );
+        }
+      }
+    }
+  }
+
+  // Provide our own hook for altering properties to make it easier for our users.
+  drupal_alter('tripal_search_properties', $info);
+}
+
+/**
+ * Allows tripal admin to alter entity property information after it has. This is currently
+ * being used to indicate chado fields to be indexed for search.
+ *
+ * NOTE: If you simply need to add a field to be indexed, use hook_search_include_chado_fields()
+ * which provides the much easier method of simply listing fields to include.
+ *
+ * This function is most useful if you want to change the way the value is retrieved
+ * (done by changing the 'getter callback') or add your own custom computed field.
+ */
+function hook_tripal_search_properties_alter(&$info) { }
+
+/**
+ * Implements a getter callback for chado token formats.
+ *
+ * A chado token format is a string containing chado tokens.
+ *
+ * Chado tokens are expected to follow the format of tokens auto-generated using
+ *   chado_node_generate_tokens(). For example, [feature.uniquename] indicates you
+ *   should return the uniquename of a feature node and [feature.organism_id>organism.species]
+ *   indicates you should return the organism genus of the feature node.
+ *
+ * The chado token format must be stored in the 'schema field' when defining the property in
+ *  hook_entity_property_info() in order for this getter to work.
+ *
+ * @param $data
+ *   The entity object (in our case the node we need to retrieve feature properties for).
+ * @param $options
+ * @param $field_name
+ *   The machine name for the entity property.
+ * @param $info
+ *   The full property definition from entity property info.
+ *
+ * @return
+ *   A string representing the "value" of the field.
+ */
+function tripal_search_chado_token_getter_callback($data, $options, $field_name, $type, $info) {
+
+  if (isset($data->nid)) {
+    if (isset($info['schema field'])) {
+      $format = $info['schema field'];
+
+      // Determine our base table so we know if this is even the right node type.
+      if (preg_match('/\[(\w+)\.(\w+)/',$format, $matches)) {
+        $base_table = $matches[1];
+        $field_name = $matches[2];
+
+        // For some weird reason nodes of all types are trying to get a value for fields
+        // that we defined as specific to a given node type (ie: bundle). As such we need
+        // this check here to ensure this field is actually for this node type.
+        if (!isset($data->{$base_table})) return NULL;
+
+        $format = tripal_core_get_token_value_for_property($base_table, $field_name, $format, $data, $info);
+        return $format;
+      }
+      else {
+        // Not able to determine table?
+        tripal_report_error(
+          'tripal_search',
+          TRIPAL_ERROR,
+          'Unable to extract the base table from the format (:format) for :field because it didn\'t match the expected format: [tablename.field...',
+          array(':field' => $field_name, ':format' => $format)
+        );
+        return NULL;
+      }
+    }
+    else {
+      tripal_report_error(
+        'tripal_search',
+        TRIPAL_ERROR,
+        'Unable to get value for :field because the schema field was not set.',
+        array(':field' => $field_name)
+      );
+      return NULL;
+    }
+  }
+}
+
+/**
+ * Implements a getter callback for foreign keys collon between content types.
+ *
+ * @param $data
+ *   The entity object (in our case the node we need to retrieve feature properties for).
+ * @param $options
+ * @param $field_name
+ *   The machine name for the entity property.
+ * @param $info
+ *   The full property definition from entity property info.
+ *
+ * @return
+ *   A string representing the "value" of the field.
+ */
+function tripal_search_chado_token_across_nodetypes_getter_callback($data, $options, $field_name, $type, $info) {
+
+  // First, make sure this is a chado node.
+  // Assumption #1: All chado node types are prefixed with chado_
+  if (isset($data->nid)) {
+    if (preg_match('/^chado_(\w+)/',$data->type,$matches)) {
+      if (isset($info['schema field'])) {
+
+        // Assumption #2: The base table is the suffix of the node type.
+        $base_table = $matches[1];
+
+        // Substitute in the  base table for "BASE" in the schema field.
+        $format = str_replace('BASE', $base_table, $info['schema field']);
+
+        // Replace all tokens for values and return the result.
+        $format = tripal_core_get_token_value_for_property($base_table, $field_name, $format, $data, $info);
+        return $format;
+      }
+      else {
+        // Not able to determine table?
+        tripal_report_error(
+          'tripal_search',
+          TRIPAL_ERROR,
+          'Unable to extract the base table from the format (:format) for :field because it didn\'t match the expected format: [tablename.field...',
+          array(':field' => $field_name, ':format' => $format)
+        );
+      }
+    }
+    else {
+      tripal_report_error(
+        'tripal_search',
+        TRIPAL_ERROR,
+        'Unable to get value for :field because the schema field was not set.',
+        array(':field' => $field_name)
+      );
+    }
+  }
+
+  return NULL;
+}
+
+/**
+ * Retrieve values for all tokens for an entity property getter function.
+ */
+function tripal_core_get_token_value_for_property($base_table, $field_name, $format, $data, $info) {
+
+  // Determine which tokens were used in the format string
+  if (preg_match_all('/\[[^]]+\]/', $format, $used_tokens)) {
+    $used_tokens = $used_tokens[0];
+
+    // If there are no tokens then return the format as is...
+    if (empty($used_tokens)) {
+      tripal_report_error(
+        'tripal_search',
+        TRIPAL_NOTICE,
+        'Returned static text for :field since there were no tokens in the supplied format: :format',
+        array(':field' => $field_name, ':format' => $format)
+      );
+      return $format;
+    }
+
+    // Get the value of each token.
+    $null_tokens = array();
+    foreach ($used_tokens as $token) {
+      $token_info = array(
+          'name' => $info['label'],
+          'table' => $base_table,
+          'field' => $field_name,
+          'token' => $token,
+          'description' => $info['description'],
+          'location' => chado_node_get_location_from_token($token),
+      );
+
+      $value = chado_get_token_value($token_info, $data, array('supress_errors' => TRUE));
+      if (empty($value)) $null_tokens[] = $token;
+
+      // And sub it in to the format.
+      $format = str_replace($token, $value, $format);
+    }
+
+    // If none of the tokens had values then this node doesn't have this field.
+    // As such we return null so the search api doesn't bother indexing an empty format.
+    if (sizeof($used_tokens) == sizeof($null_tokens)) return NULL;
+  }
+  else {
+    tripal_report_error(
+      'tripal_search',
+      TRIPAL_NOTICE,
+      'Returned static text for :field since there were no tokens of a recognized format in the supplied format: :format',
+      array(':field' => $field_name, ':format' => $format)
+    );
+  }
+
+  return $format;
+}
+
+/**
+ * Implements hook_modules_enabled().
+ *
+ * This hook is called when ANY module is enabled. This allows us to update the
+ * the search api "Default node index" when any Tripal module is enabled thus allowing us
+ * to catch new node types right after they're created.
+ */
+function tripal_core_modules_enabled($modules) {
+  if (module_exists('search_api')) {
+    $index_enabled = db_query('SELECT enabled FROM search_api_index WHERE machine_name=:name', array(':name' => 'default_node_index'))->fetchField();
+    if ($index_enabled) {
+      tripal_search_update_default_index();
+    }
+  }
+}
+
+/**
+ * The Search API provides a default node index which has a number of
+ * node-specific fields enabled by default. We want to ensure our
+ * chado fields are also enabled by default thus making for easier
+ * enabling of Tripal search.
+ *
+ * This function should be called whenever new nodes might have been
+ * added to ensure that their fields are added as well.
+ *
+ * We should only modify the default node index if it has no database service yet.
+ * That way we ensure we don't override user changes!
+ */
+function tripal_search_update_default_index() {
+
+  // First we need the index object for the "Default node index".
+  $index_id = db_query('SELECT id FROM search_api_index WHERE machine_name=:name',
+    array(':name' => 'default_node_index'))->fetchField();
+  if (!$index_id) {
+    // ERROR
+    return FALSE;
+  }
+  $index = search_api_index_load($index_id);
+
+  // Collect all the fields already added to the search index.
+  $changes = array('options' => $index->options);
+
+  // Now we only want to update the index if it's both enabled and has no server indicated.
+  // That way we can be reasonably sure that it was been untouched by admin users.
+  if ($index->enabled == FALSE AND $index->server == NULL) {
+
+    // We need information about all the fields available to nodes before we can
+    // go crazy enabling them... That information is stored as properties of nodes
+    // so we'll grab that.
+    $info = entity_get_property_info('node');
+
+    // Now we want to loop through each node type and add all the properties for the
+    // chado node types.
+    // Assumption #1: We are assuming that all chado node types are prefixed 'chado_'.
+    foreach ($info['bundles'] as $node_type => $details) {
+      if (preg_match('/^chado_/', $node_type)) {
+
+        // Now add each chado fields to the index but only if they are not already added.
+        foreach ($details['properties'] as $field_name => $field_details) {
+          if (!isset($changes['options']['fields'][$field_name])) {
+            $changes['options']['fields'][$field_name]['type'] = ($field_details['type'] == 'varchar') ? 'text' : $field_details['type'];
+
+            // Furthermore if this is a name then we want to add a boost to ensure it carries
+            // more weight in the search results.
+            if (preg_match('/name/',$field_name)) {
+              $changes['options']['fields'][$field_name]['boost'] = '3.0';
+            }
+          }
+        }
+
+      }
+    }
+
+    // We also want to enable highlighting to ensure an excerpt is generated since this
+    // will be used in the default search view distributed with Tripal.
+    if (!isset($index->options['processors']['search_api_highlighting'])) {
+      $changes['options']['processors']['search_api_highlighting'] = array(
+        'status' => 1,
+        'weight' => 35,
+        'settings' => array(
+          'prefix' => '<strong>',
+          'suffix' => '</strong>',
+          'excerpt' => 1,
+          'excerpt_length' => 256,
+          'exclude_fields' => array(),
+          'highlight' => 'always',
+        ),
+      );
+    }
+    else {
+      $changes['options']['processors']['search_api_highlighting']['status'] = 1;
+      $changes['options']['processors']['search_api_highlighting']['settings']['excerpt'] = 1;
+    }
+
+    // Finally we save all of our changes :-).
+    search_api_index_edit($index_id, $changes);
+    drupal_set_message('The Search API "Default Node Index" was updated.');
+  }
+  else {
+    tripal_report_error(
+      'tripal_search',
+      TRIPAL_NOTICE,
+      'The Search API "Default Node Index" was not updated with Tripal Fields. If you would like to enable more Tripal/Chado fields to be indexed, edit the Field Listing for the "Default Node Index" now.'
+    );
+  }
+}
+

+ 0 - 1
legacy/tripal_core/tripal_core.info

@@ -11,7 +11,6 @@ scripts[]          = theme/js/tripal_core.js
 
 dependencies[] = views
 dependencies[] = path
-dependencies[] = search
 dependencies[] = php
 dependencies[] = tripal
 dependencies[] = tripal_chado

+ 123 - 0
legacy/tripal_core/tripal_core.module

@@ -12,6 +12,7 @@ require_once 'api/tripal_core.chado_nodes.dbxrefs.api.inc';
 require_once 'api/tripal_core.chado_nodes.relationships.api.inc';
 require_once 'api/tripal_core.tripal_variables.api.inc';
 require_once 'includes/tripal_core.form_elements.inc';
+require_once 'includes/tripal_core.search.inc';
 
 /**
  * @defgroup tripal_core Tripal Core Module
@@ -274,4 +275,126 @@ function tripal_core_field_widget_form_alter(&$element, &$form_state, $context)
       );
     }
   }
+}
+
+/**
+ * Implements hook_block_info().
+ */
+function tripal_core_block_info() {
+
+  $blocks['tripal_search'] = array(
+    'info' => t('Tripal Search Block'),
+    'cache' => DRUPAL_NO_CACHE,
+  );
+
+  return $blocks;
+}
+
+/**
+ * Implements hook_block_view().
+ */
+function tripal_core_block_view($delta = '') {
+  $block = array();
+
+  switch ($delta) {
+    case 'tripal_search':
+      $block['title'] = 'Search';
+
+      $form_render_arr = drupal_get_form('tripal_core_search_block');
+      $block['content'] = array(
+        '#markup' => drupal_render($form_render_arr),
+      );
+      break;
+  }
+
+  return $block;
+}
+
+/**
+ * A simple search box form.
+ */
+function tripal_core_search_block($form, $form_state) {
+
+  $form['wrapper'] = array(
+    '#prefix' => '<div id="search-block-form" class="container-inline">',
+    '#suffix' => '</div>',
+  );
+
+  $form['wrapper']['title'] = array(
+    '#markup' => '<h2 class="element-invisible">Search form</h2>',
+  );
+
+  $form['wrapper']['search_block_form'] = array(
+    '#title' => 'Search',
+    '#title_display' => 'invisible',
+    '#type' => 'textfield',
+    '#size' => 15,
+    '#maxlength' => 128,
+    '#attributes' =>array('placeholder' => t(variable_get('tripal_search_placeholder', 'Keywords')))
+  );
+
+  $form['wrapper']['submit'] = array(
+    '#type' => 'submit',
+    '#value' => 'Search',
+    '#prefix' => '<div class="form-actions form-wrapper" id="edit-actions">',
+    '#suffix' => '</div>'
+  );
+
+  $form['search_placeholder'] = array(
+    '#type' => 'textfield',
+    '#title' => 'Placeholder Text',
+    '#description' => 'Change the text that shows up within the search box until the user enters any of their own text.',
+    '#default_value' => variable_get('tripal_search_placeholder', 'Keywords'),
+  );
+
+  return $form;
+}
+
+/**
+ * Submit for tripal_core_search_block form.
+ */
+function tripal_core_search_block_submit($form, &$form_state) {
+
+  $form_state['redirect'] = array(
+    variable_get('tripal_search_block_url', 'search/data'),
+    array(
+      'query' => array(
+        'keywords' => $form_state['values']['search_block_form']
+      ),
+    ),
+  );
+
+}
+
+/**
+ * Implements hook_block_configure().
+ */
+function tripal_core_block_configure ($delta = '') {
+  $form = array();
+
+  $form['search_url'] = array(
+    '#type' => 'textfield',
+    '#title' => 'Search Page URL',
+    '#description' => 'The URL for the page you would like to redirect to when the user
+        clicks "Search". It is expected that this page will be a view with an exposed
+        filter having a "Filter Identifier" (in "More" fieldset on the edit filter form)
+        of "keywords".',
+    '#default_value' => variable_get('tripal_search_block_url', 'search/data'),
+  );
+
+  return $form;
+}
+
+/**
+ * Implements hook_block_save().
+ */
+function tripal_core_block_save($delta = '', $edit = array()) {
+
+  // We simply want to save this information in a Drupal variable for use in the form submit.
+  if (!empty($edit['search_url'])) {
+    variable_set('tripal_search_block_url', $edit['search_url']);
+  }
+  if (!empty($edit['search_placeholder'])) {
+    variable_set('tripal_search_placeholder', $edit['search_placeholder']);
+  }
 }

+ 104 - 0
legacy/tripal_core/tripal_core.views_default.inc

@@ -0,0 +1,104 @@
+<?php
+/**
+ * @file
+* Describes core default views
+*/
+
+/**
+ * Describes core default views
+*
+* @ingroup tripal_core
+*/
+function tripal_core_views_default_views() {
+  $views = array();
+
+  // We only want to make this view available if the Search API module is installed
+  // and the "Default Node Index has been enabled.
+  if (module_exists('search_api')) {
+    $index_enabled = db_query('SELECT enabled FROM search_api_index WHERE machine_name=:name', array(':name' => 'default_node_index'))->fetchField();
+    if ($index_enabled) {
+      $view = tripal_core_search_default_node_index();
+      $views[$view->name] = $view;
+    }
+  }
+  return $views;
+}
+
+
+/**
+ * Provides a default search view for the Search API "Default Node Index".
+ */
+function tripal_core_search_default_node_index() {
+
+  $view = new view();
+  $view->name = 'search_api_default_node_search';
+  $view->description = 'A default keyword-based search view using the search API "Default node index".';
+  $view->tag = 'search';
+  $view->base_table = 'search_api_index_default_node_index';
+  $view->human_name = 'Search';
+  $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'] = 'Search';
+  $handler->display->display_options['use_more_always'] = FALSE;
+  $handler->display->display_options['access']['type'] = 'none';
+  $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']['expose_sort_order'] = FALSE;
+  $handler->display->display_options['exposed_form']['options']['text_input_required'] = '';
+  $handler->display->display_options['exposed_form']['options']['text_input_required_format'] = 'filtered_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'] = 'default';
+  $handler->display->display_options['row_plugin'] = 'fields';
+  /* Field: Content: Rendered Node */
+  $handler->display->display_options['fields']['rendered_entity']['id'] = 'rendered_entity';
+  $handler->display->display_options['fields']['rendered_entity']['table'] = 'views_entity_node';
+  $handler->display->display_options['fields']['rendered_entity']['field'] = 'rendered_entity';
+  $handler->display->display_options['fields']['rendered_entity']['label'] = '';
+  $handler->display->display_options['fields']['rendered_entity']['element_label_colon'] = FALSE;
+  $handler->display->display_options['fields']['rendered_entity']['link_to_entity'] = 1;
+  $handler->display->display_options['fields']['rendered_entity']['display'] = 'view';
+  $handler->display->display_options['fields']['rendered_entity']['view_mode'] = 'teaser';
+  $handler->display->display_options['fields']['rendered_entity']['bypass_access'] = 0;
+  /* Sort criterion: Search: Relevance */
+  $handler->display->display_options['sorts']['search_api_relevance']['id'] = 'search_api_relevance';
+  $handler->display->display_options['sorts']['search_api_relevance']['table'] = 'search_api_index_default_node_index';
+  $handler->display->display_options['sorts']['search_api_relevance']['field'] = 'search_api_relevance';
+  $handler->display->display_options['sorts']['search_api_relevance']['order'] = 'DESC';
+  /* Filter criterion: Search: Fulltext search */
+  $handler->display->display_options['filters']['search_api_views_fulltext']['id'] = 'search_api_views_fulltext';
+  $handler->display->display_options['filters']['search_api_views_fulltext']['table'] = 'search_api_index_default_node_index';
+  $handler->display->display_options['filters']['search_api_views_fulltext']['field'] = 'search_api_views_fulltext';
+  $handler->display->display_options['filters']['search_api_views_fulltext']['operator'] = 'OR';
+  $handler->display->display_options['filters']['search_api_views_fulltext']['exposed'] = TRUE;
+  $handler->display->display_options['filters']['search_api_views_fulltext']['expose']['operator_id'] = 'search_api_views_fulltext_op';
+  $handler->display->display_options['filters']['search_api_views_fulltext']['expose']['label'] = 'Keywords';
+  $handler->display->display_options['filters']['search_api_views_fulltext']['expose']['operator'] = 'search_api_views_fulltext_op';
+  $handler->display->display_options['filters']['search_api_views_fulltext']['expose']['identifier'] = 'keywords';
+  $handler->display->display_options['filters']['search_api_views_fulltext']['expose']['remember_roles'] = array(
+    2 => '2',
+    1 => 0,
+    3 => 0,
+  );
+
+  /* Display: Page */
+  $handler = $view->new_display('page', 'Page', 'page');
+  $handler->display->display_options['path'] = 'chado';
+  $handler->display->display_options['menu']['type'] = 'normal';
+  $handler->display->display_options['menu']['title'] = 'Search';
+  $handler->display->display_options['menu']['description'] = 'General keyword search of all content.';
+  $handler->display->display_options['menu']['weight'] = '0';
+  $handler->display->display_options['menu']['context'] = 0;
+  $handler->display->display_options['menu']['context_only_inline'] = 0;
+
+  return $view;
+}

+ 1 - 1
legacy/tripal_cv/tripal_cv.module

@@ -115,7 +115,7 @@ function tripal_cv_menu() {
     'type' => MENU_CALLBACK,
   );
   $items['admin/tripal/legacy/vocab/cvterm/auto_name/%/%'] = array(
-    'page callback' => 'tripal_cv_cvterm_name_autocomplete',
+    'page callback' => 'tripal_autocomplete_cvterm',
     'page arguments' => array(6, 7),
     'access arguments' => array('administer controlled vocabularies'),
     'type' => MENU_CALLBACK,

+ 1 - 4
legacy/tripal_feature/includes/tripal_feature.chado_node.inc

@@ -772,10 +772,7 @@ function tripal_feature_node_presave($node) {
         $organism_id = $node->feature->organism_id;
         $name        = $node->feature->name;
         $uname       = $node->feature->uniquename;
-        $type_id     = $node->feature->type_id;
-        $values = array('cvterm_id' => $type_id);
-        $ftype = chado_select_record('cvterm', array('name'), $values);
-        $type = $ftype[0]->name;
+        $type        = $node->feature->cvtname;
       }
 
       $values = array('organism_id' => $organism_id);

+ 18 - 20
legacy/tripal_feature/theme/templates/tripal_feature_help.tpl.php

@@ -6,16 +6,14 @@
   <ol>
     <li><p><b>Set Permissions</b>: By default only the site administrator account has access to create, edit, delete
    or administer features. Navigate to the <?php print l('permissions page', 'admin/user/permissions')?> and set the
-   permissions under the 'tripal_feature' section as appropriate for your site. For a simple setup, allow anonymous 
+   permissions under the 'tripal_feature' section as appropriate for your site. For a simple setup, allow anonymous
    users access to view content and create a special role for creating, editing and other administrative tasks.</p></li>
-   
-   <li><p><b>Loading of Ontologies</b>:  
+
+   <li><p><b>Loading of Ontologies</b>:
      Before loading genomic features you must also have several vocabularies loaded as well. Using the
      <?php print l('OGO loader','admin/tripal/tripal_cv/obo_loader')?> you should load the following
      ontologies:</p>
      <ul>
-        <li>Chado Feature Properties</li>
-        <li>Relationship Ontology</li>
         <li>Sequence Ontology</li>
         <li>Gene Ontology (if loading GO terms for features)</li>
      </ul>
@@ -40,7 +38,7 @@
      <li><p><b>Data Import</b>:  if you do not already have an existing Chado database with preloaded data
      then you will want
      to import data.  You can do so using the Chado perl scripts that come with the normal
-     <a href="http://gmod.org/wiki/Chado">distribution of Chado</a> or you can use 
+     <a href="http://gmod.org/wiki/Chado">distribution of Chado</a> or you can use
      the <a href="<?php print url('admin/tripal/tripal_feature/fasta_loader') ?>">FASTA loader</a> and
      <a href="<?php print url('admin/tripal/tripal_feature/gff3_load') ?>">GFF loader</a> provided here.  If you
      created the Chado database using Tripal then you'll most likely want to use the Tripal loaders.  If your data
@@ -70,27 +68,27 @@
   <p>Aside from data loading and feature page setup (as described in the Setup section above),
   The Tripal feature module also provides the following functionality</p>
   <ul>
-    <li><p><b>Retrieve Sequences</b>: A tool to <?php print l('retrieve sequences','find/sequences') ?> is provided 
+    <li><p><b>Retrieve Sequences</b>: A tool to <?php print l('retrieve sequences','find/sequences') ?> is provided
      which allows end-users to download sequences in FASTA format.  The site admin must first load sequence residues
-     as well as alignments.  The <?php  print l('organism_feature_count', 'admin/tripal/mviews') ?> and 
+     as well as alignments.  The <?php  print l('organism_feature_count', 'admin/tripal/mviews') ?> and
      <?php print l('analysis_organism', 'admin/tripal/mviews') ?> materialized
-     views must be populated before using this tool.  Those views should be re-populated 
+     views must be populated before using this tool.  Those views should be re-populated
      when new data is added.  If you use the <?php print l('jquery_update module', 'http://drupal.org/project/jquery_update') ?>
-     the tool may break.  You will need to update the jquery_update/replace/jquery.form.js file with <?php 
+     the tool may break.  You will need to update the jquery_update/replace/jquery.form.js file with <?php
      print l('a more recent version','https://raw.github.com/malsup/form/master/jquery.form.js') ?>. </p></li>
-    
-     <li><p><b>Generic Feature URL</b>:  As described in the setup instructions above, it is often convenient to have a 
-     simple URL for each feature page. For example, http://www.mygenomesite.org/[feature], where [feature] is a 
+
+     <li><p><b>Generic Feature URL</b>:  As described in the setup instructions above, it is often convenient to have a
+     simple URL for each feature page. For example, http://www.mygenomesite.org/[feature], where [feature] is a
      unique identifier for a feature page.  The
-     <?php print l('Feature Configuration page','admin/tripal/tripal_feature/configuration') ?> allows a 
+     <?php print l('Feature Configuration page','admin/tripal/tripal_feature/configuration') ?> allows a
      site admin to generate unique URLs for all feature.  The unique URL is necessary, however, sometimes
      it is easier to allow for links to the feature name without knowing the unique URL.  This is possible
-     using the URL: http://[site url]/feature/[feature name], where [site url] is the URL for the site and 
+     using the URL: http://[site url]/feature/[feature name], where [site url] is the URL for the site and
      [feature name] is the name of the feature.  If the feature name is not unique then a page will be
-     presented listing all of the features with the same name and allow the user to choose which one to 
-     view.  If the feature name is unique then the user will automatically be redirected to the 
+     presented listing all of the features with the same name and allow the user to choose which one to
+     view.  If the feature name is unique then the user will automatically be redirected to the
      unique URL for the feature.</p></li>
-     
+
     <li><p><b>Feature Browser:</b>  The feature browser is a tabular list of features with links to their
      feature pages which appears on the organism
      page.  It was created to provide a mechanism to allow site visitors to quickly
@@ -112,9 +110,9 @@
     published data (only works if Chado was installed using Tripal).  You can see a list of available pre-existing
     Views <a href="<?php print url('admin/build/views/') ?>">here</a>, as well as create your own. </p></li>
 
-    <li><p><b>Simple Search Tool</b>: A <?php print l('simple search tool','chado/features') ?> is provided for 
+    <li><p><b>Simple Search Tool</b>: A <?php print l('simple search tool','chado/features') ?> is provided for
     finding features. This tool relies on Drupal Views.  <a href="http://drupal.org/project/views">Drupal Views</a>
-    which must be installed to see the search tool.  Look for it in the navigation menu under the item 
+    which must be installed to see the search tool.  Look for it in the navigation menu under the item
     "Search Data". </p></li>
 
     <li><p><b>Delete Features</b>: You can  <a href="<?php print url('admin/tripal/tripal_feature/delete') ?>">bulk delete features</a>

+ 1 - 1
legacy/tripal_feature/theme/templates/tripal_feature_sequence.tpl.php

@@ -171,7 +171,7 @@ if ($residues or count($featureloc_sequences) > 0) {
       // that one mRNA is only aligned to a single location on the assembly so we
       // can access the CDS sequence with index 0.
       if ($cds_sequence[0]['residues']) {
-        $list_items[] = '<a href="#coding_' . $attrs['id'] . '">coding sequnece from alignment at  ' . $attrs['location'] . "</a>";
+        $list_items[] = '<a href="#coding_' . $attrs['id'] . '">coding sequence from alignment at  ' . $attrs['location'] . "</a>";
         $sequences_html .= '<a name="ccoding_' . $attrs['id'] . '"></a>';
         $sequences_html .= '<div id="coding_' . $attrs['id'] . '" class="tripal_feature-sequence-item">';
         $sequences_html .= '<p><b>Coding sequence (CDS) from alignment at  ' . $attrs['location'] . '</b></p>';

+ 6 - 1
legacy/tripal_feature/theme/templates/tripal_organism_feature_browser.tpl.php

@@ -109,15 +109,20 @@ if (count($so_terms) > 0) {
     // here we add the paramter 'block' => 'feature_browser'. This is because
     // the pager is not on the default block that appears. When the user clicks a
     // page number we want the browser to re-appear with the page is loaded.
+    // We remove the 'pane' parameter from the original query parameters because
+    // Drupal won't reset the parameter if it already exists.
+    $get = $_GET;
+    unset($_GET['pane']);
     $pager = array(
       'tags' => array(),
       'element' => $element,
       'parameters' => array(
-        'block' => 'feature_browser'
+        'pane' => 'feature_browser'
       ),
       'quantity' => $num_per_page,
     );
     print theme_pager($pager);
+    $_GET = $get;
 
     print tripal_set_message("
       Administrators, please note that the feature browser will be retired in

+ 5 - 0
legacy/tripal_feature/theme/tripal_feature.theme.inc

@@ -603,6 +603,11 @@ function tripal_feature_load_organism_feature_counts($organism) {
   $order = array();
   $names = array();
 
+  // We should not assume this table is present since it is a materialized view.
+  if (!chado_table_exists('organism_feature_count')) {
+      return NULL;
+  }
+
   // build the where clause for the SQL statement if we have a custom term list
   // we'll also keep track of the names the admin provided (if any) and the
   // order that the terms should appear.

+ 23 - 130
legacy/tripal_feature/tripal_feature.module

@@ -108,34 +108,6 @@ function tripal_feature_permission() {
 function tripal_feature_menu() {
   $items = array();
 
-  // the administative settings menu
-  $items['find/sequences'] = array(
-    'title' => 'Sequence Retrieval',
-    'description' => 'Download a file of sequences',
-    'page callback' => 'drupal_get_form',
-    'page arguments' => array('tripal_feature_seq_extract_form'),
-    'access arguments' => array('access chado_feature content'),
-    'file' =>  'includes/tripal_feature.seq_extract.inc',
-    'file path' => drupal_get_path('module', 'tripal_feature'),
-    'type' => MENU_CALLBACK,
-  );
-
-  $items['find/sequences/download'] = array(
-    'page callback' => 'tripal_feature_seq_extract_download',
-    'access arguments' => array('access chado_feature content'),
-    'file' =>  'includes/tripal_feature.seq_extract.inc',
-    'file path' => drupal_get_path('module', 'tripal_feature'),
-    'type' => MENU_CALLBACK,
-  );
-
-  // the menu link for addressing any feature (by name, uniquename, synonym)
-  $items['feature/%'] = array(
-    'page callback' => 'tripal_feature_match_features_page',
-    'page arguments' => array(1),
-    'access arguments' => array('access chado_feature content'),
-    'type' => MENU_LOCAL_TASK,
-  );
-
   // the administative settings menu
   $items['admin/tripal/legacy/tripal_feature'] = array(
     'title' => 'Features',
@@ -324,11 +296,6 @@ function tripal_feature_theme($existing, $type, $theme, $path) {
     'path' => "$path/theme/templates"
   );
 
-  // Themed Forms
-  $items['tripal_feature_seq_extract_form'] = array(
-     'render element' => 'form',
-  );
-
   // D3 Charts.
   // Feature Type/Organism Stacked Bar Chart.
   $items['tripal_feature_bar_chart_type_organism_summary'] = array(
@@ -350,31 +317,38 @@ function tripal_feature_job_describe_args($callback, $args) {
   $new_args = array();
   if ($callback == 'tripal_feature_load_fasta') {
     $new_args['FASTA file'] = $args[0];
-    $organism = chado_select_record('organism', array('genus', 'species'), array('organism_id' => $args[1]));
-    $new_args['Organism'] = $organism[0]->genus . " " . $organism[0]->species;
-    $new_args['Sequence Type'] = $args[2];
-    $new_args['Name Match Type'] = $args[14];
-    $new_args['Name RE'] = $args[4];
-    $new_args['Unique Name RE'] = $args[5];
 
+    // Add in the organism.
+    if ($args[1] AND is_numeric($args[1])) {
+      $organism = chado_select_record('organism', array('genus', 'species'), array('organism_id' => $args[1]));
+      $new_args['Organism'] = $organism[0]->genus . " " . $organism[0]->species;
+    }
+    $new_args['Sequence Type'] = $args[2];
+    if (isset($args[14])) {
+      $new_args['Name Match Type'] = $args[14];
+      $new_args['Name RE'] = $args[4];
+      $new_args['Unique Name RE'] = $args[5];
+    }
     // add in the relationship arguments
-    $new_args['Relationship Type'] = $args[8];
-    $new_args['Relationship Parent RE'] = $args[9];
-    $new_args['Relationship Parent Type'] = $args[10];
+    if ($args[8]) {
+      $new_args['Relationship Type'] = $args[8];
+      $new_args['Relationship Parent RE'] = $args[9];
+      $new_args['Relationship Parent Type'] = $args[10];
+    }
 
     // add in the database reference arguments
-    if ($args[7]) {
+    if ($args[7] AND is_numeric($args[7])) {
       $db = chado_select_record('db', array('name'), array('db_id' => $args[7]));
+      $new_args['Database Reference'] = $db[0]->name;
+      $new_args['Accession RE'] = $args[6];
+      $new_args['Method'] = $args[11];
     }
-    $new_args['Database Reference'] = $db[0]->name;
-    $new_args['Accession RE'] = $args[6];
-    $new_args['Method'] = $args[11];
 
     // add in the analysis
-    if ($args[13]) {
-      $analysis = chado_select_record('analysis', array('name'), array('analysis_id' => $args[13]));
+    if ($args[12] AND is_numeric($args[12])) {
+      $analysis = chado_select_record('analysis', array('name'), array('analysis_id' => $args[12]));
+      $new_args['Analysis'] = $analysis[0]->name;
     }
-    $new_args['Analysis'] = $analysis[0]->name;
   }
   if ($callback == 'tripal_feature_delete_features') {
     if ($args[0]) {
@@ -441,87 +415,6 @@ function tripal_feature_coder_ignore() {
   );
 }
 
-/*
- * Uses the value provided in the $id argument to find all features that match
- * that ID by name, featurename or synonym.  If it matches uniquenly to a single
- * feature it will redirect to that feature page, otherwise, a list of matching
- * features is shown.
- *
- * @ingroup tripal_feature
- */
-function tripal_feature_match_features_page($id) {
-
-  // first check to see if the URL (e.g. /feature/$id) is already
-  // assigned to a node. If so, then just go there.  Otherwise,
-  // try to find the feature.
-  $sql = "
-    SELECT source
-    FROM {url_alias}
-    WHERE alias = :alias
-  ";
-  $match = db_query($sql, array(':alias' => "feature/$id"))->fetchObject();
-  if ($match) {
-    drupal_goto($match->source);
-    return;
-  }
-  $sql = "
-    SELECT
-      F.name, F.uniquename, F.feature_id,
-      O.genus, O.species, O.organism_id,
-      CVT.cvterm_id, CVT.name as type_name,
-      CF.nid,
-      array_agg(S.name) as synonyms
-    FROM {feature} F
-      INNER JOIN {organism} O on F.organism_id = O.organism_id
-      INNER JOIN {cvterm} CVT on CVT.cvterm_id = F.type_id
-      LEFT JOIN {feature_synonym} FS on FS.feature_id = F.feature_id
-      LEFT JOIN {synonym} S on S.synonym_id = FS.synonym_id
-      INNER JOIN {chado_feature} CF on CF.feature_id = F.feature_id
-    WHERE
-      F.uniquename = :uname or
-      F.name = :fname or
-      S.name = :sname
-    GROUP BY F.name, F.uniquename, F.feature_id, O.genus, O.species,
-      O.organism_id, CVT.cvterm_id, CVT.name, CF.nid
-  ";
-
-  $args = array(':uname' => $id, ':fname' => $id, ':sname' => $id);
-  $results = chado_query($sql, $args);
-
-  $num_matches = 0;
-
-  // iterate through the matches and build the table for showing matches
-  $header = array('Uniquename', 'Name', 'Type', 'Species', 'Synonyms');
-  $rows = array();
-  $curr_match;
-  while ($match = $results->fetchObject()) {
-    $curr_match = $match;
-    $synonyms = $match->synonyms;
-    $synonyms = preg_replace('/[\"\{\}]/', '', $synonyms);
-    $rows[] = array(
-       $match->uniquename,
-       "<a href=\"" . url("node/" . $match->nid) . "\">" . $match->name . "</a>",
-       $match->type_name,
-       '<i>' . $match->genus . ' ' . $match->species . '</i>',
-       $synonyms,
-    );
-    $num_matches++;
-  }
-
-  // if we have more than one match then generate the table, otherwise, redirect
-  // to the matched feature
-  if ($num_matches == 1) {
-    drupal_goto("node/" . $curr_match->nid);
-  }
-  if ($num_matches == 0) {
-    return "<p>No features matched the given name '$id'</p>";
-  }
-
-  $table_attrs = array('class' => 'tripal-data-table');
-  $output = "<p>The following features match the name '$id'.</p>";
-  $output .= theme_table($header, $rows, $table_attrs, $caption);
-  return $output;
-}
 
 /**
  * Implementation of hook_form_alter()

+ 24 - 19
legacy/tripal_featuremap/theme/templates/tripal_feature_featurepos.tpl.php

@@ -2,18 +2,18 @@
 
 // expand the feature object to include the records from the featurepos table
 // specify the number of features to show by default and the unique pager ID
-$num_results_per_page = 25; 
+$num_results_per_page = 5;
 $featurepos_pager_id = 20;
 
 // get the maps associated with this feature
 $feature = $variables['node']->feature;
-$options = array(  
+$options = array(
   'return_array' => 1,
   'order_by' => array(
     'map_feature_id' => 'ASC'
   ),
   'pager' => array(
-    'limit' => $num_results_per_page, 
+    'limit' => $num_results_per_page,
     'element' => $featurepos_pager_id
   ),
   'include_fk' => array(
@@ -29,7 +29,7 @@ $options = array(
 
 $feature = chado_expand_var($feature, 'table', 'featurepos', $options);
 
-// because the featurepos table has  FK relationships with map_feature_id and feature_id with the feature table 
+// because the featurepos table has  FK relationships with map_feature_id and feature_id with the feature table
 // the function call above will try to expand both and will create an array of matches for each FK.
 // we only want to show the map that this feature belongs to
 $map_positions = $feature->featurepos->map_feature_id;
@@ -39,20 +39,20 @@ $total_records = chado_pager_get_count($featurepos_pager_id);
 
 
 if(count($map_positions) > 0){ ?>
-  <div class="tripal_feature-data-block-desc tripal-data-block-desc">This feature is contained in the following <?php print number_format($total_records) ?> map(s):</div><?php 
+  <div class="tripal_feature-data-block-desc tripal-data-block-desc">This feature is contained in the following <?php print number_format($total_records) ?> map(s):</div><?php
 
   // the $headers array is an array of fields to use as the colum headers.
   // additional documentation can be found here
   // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
   $headers = array('Map Name', 'Landmark', 'Type', 'Position');
-  
+
   // the $rows array contains an array of rows where each row is an array
   // of values for each column of the table in that row.  Additional documentation
   // can be found here:
   // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
   $rows = array();
 
-  // iterate through our map positions    
+  // iterate through our map positions
   foreach ($map_positions as $position){
     $map_feature = $position->map_feature_id;
 
@@ -61,7 +61,7 @@ if(count($map_positions) > 0){ ?>
     $options = array(
       'return_array' => 1,
       'include_fk' => array(
-        'type_id' => 1,            
+        'type_id' => 1,
       ),
     );
     $position = chado_expand_var($position, 'table', 'featureposprop', $options);
@@ -76,8 +76,8 @@ if(count($map_positions) > 0){ ?>
          if ($property->type_id->name == 'stop') {
            $stop = $property->value;
          }
-      }      
-    }  
+      }
+    }
     if ($start and $stop and $start != $stop) {
       $mappos = "$start-$stop";
     }
@@ -87,20 +87,20 @@ if(count($map_positions) > 0){ ?>
     if ($start and $stop and $start == $stop) {
       $mappos = $start;
     }
-    
+
     // get the map name feature
     $map_name =  $position->featuremap_id->name;
     if (property_exists($position->featuremap_id, 'nid')) {
       $map_name = l($map_name, 'node/' . $position->featuremap_id->nid, array('attributes' => array('target' => '_blank')));
     }
-    
-    
+
+
     // get the landmark
     $landmark = $map_feature->name;
     if (property_exists($map_feature, 'nid')) {
       $landmark =  l($landmark, 'node/' . $map_feature->nid, array('attributes' => array('target' => '_blank')));
     }
-    
+
     $rows[] = array(
       $map_name,
       $landmark,
@@ -127,22 +127,27 @@ if(count($map_positions) > 0){ ?>
 
   // once we have our table array structure defined, we call Drupal's theme_table()
   // function to generate the table.
-  print theme_table($table); 
-  
+  print theme_table($table);
+
   // the $pager array values that control the behavior of the pager.  For
   // documentation on the values allows in this array see:
   // https://api.drupal.org/api/drupal/includes!pager.inc/function/theme_pager/7
   // here we add the paramter 'block' => 'features'. This is because
   // the pager is not on the default block that appears. When the user clicks a
   // page number we want the browser to re-appear with the page is loaded.
+  // We remove the 'pane' parameter from the original query parameters because
+  // Drupal won't reset the parameter if it already exists.
+  $get = $_GET;
+  unset($_GET['pane']);
   $pager = array(
     'tags' => array(),
     'element' => $featurepos_pager_id,
     'parameters' => array(
-      'block' => 'featurepos'
+      'pane' => 'featurepos'
     ),
     'quantity' => $num_results_per_page,
   );
-  print theme_pager($pager); 
-}?>
+  print theme_pager($pager);
+  $_GET = $get;
+}
 

+ 27 - 22
legacy/tripal_featuremap/theme/templates/tripal_featuremap_featurepos.tpl.php

@@ -4,15 +4,15 @@ $feature_positions = array();
 
 // expand the featuremap object to include the records from the featurepos table
 // specify the number of features to show by default and the unique pager ID
-$num_results_per_page = 25; 
+$num_results_per_page = 25;
 $featurepos_pager_id = 0;
 
 // get the features aligned on this map
-$options = array(  
+$options = array(
   'return_array' => 1,
   'order_by' => array('map_feature_id' => 'ASC'),
   'pager' => array(
-    'limit' => $num_results_per_page, 
+    'limit' => $num_results_per_page,
     'element' => $featurepos_pager_id
   ),
   'include_fk' => array(
@@ -38,30 +38,30 @@ $total_features = chado_pager_get_count($featurepos_pager_id);
 
 
 if(count($feature_positions) > 0){ ?>
-  <div class="tripal_featuremap-data-block-desc tripal-data-block-desc">This map contains <?php print number_format($total_features) ?> features:</div> <?php 
-  
+  <div class="tripal_featuremap-data-block-desc tripal-data-block-desc">This map contains <?php print number_format($total_features) ?> features:</div> <?php
+
   // the $headers array is an array of fields to use as the colum headers.
   // additional documentation can be found here
   // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
   $headers = array('Landmark', 'Type', 'Organism', 'Feature Name', 'Type', 'Position');
-  
+
   // the $rows array contains an array of rows where each row is an array
   // of values for each column of the table in that row.  Additional documentation
   // can be found here:
   // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
   $rows = array();
-  
+
   foreach ($feature_positions as $position){
     $map_feature = $position->map_feature_id;
-    $feature     = $position->feature_id;  
-    $organism    = $map_feature->organism_id; 
+    $feature     = $position->feature_id;
+    $organism    = $map_feature->organism_id;
 
     // check if there are any values in the featureposprop table for the start and stop
     $mappos = $position->mappos;
     $options = array(
       'return_array' => 1,
       'include_fk' => array(
-        'type_id' => 1,            
+        'type_id' => 1,
       ),
     );
     $position = chado_expand_var($position, 'table', 'featureposprop', $options);
@@ -76,18 +76,18 @@ if(count($feature_positions) > 0){ ?>
          if ($property->type_id->name == 'stop') {
            $stop = $property->value;
          }
-      }      
-    }  
+      }
+    }
     if ($start and $stop and $start != $stop) {
       $mappos = "$start-$stop";
     }
     if ($start and !$stop) {
       $mappos = $start;
-    } 
+    }
     if ($start and $stop and $start == $stop) {
       $mappos = $start;
     }
-    
+
     $mfname = $map_feature->name;
     if (property_exists($map_feature, 'nid')) {
       $mfname =  l($mfname, 'node/' . $map_feature->nid, array('attributes' => array('target' => '_blank')));
@@ -95,18 +95,18 @@ if(count($feature_positions) > 0){ ?>
     $orgname = $organism->genus ." " . $organism->species ." (" . $organism->common_name .")";
     if (property_exists($organism, 'nid')) {
       $orgname = l(
-        "<i>" . $organism->genus . " " . $organism->species . "</i> (" . $organism->common_name .")", 
-        "node/". $organism->nid, 
+        "<i>" . $organism->genus . " " . $organism->species . "</i> (" . $organism->common_name .")",
+        "node/". $organism->nid,
         array('html' => TRUE, 'attributes' => array('target' => '_blank'))
       );
     }
     $organism =  $organism->genus . ' ' . $organism->species;
-    
+
     $fname = $feature->name;
     if (property_exists($feature, 'nid')) {
       $fname = l($fname, 'node/' . $feature->nid, array('attributes' => array('target' => '_blank')));
     }
-      
+
     $rows[] = array(
       $mfname,
       $map_feature->type_id->name,
@@ -115,7 +115,7 @@ if(count($feature_positions) > 0){ ?>
       $feature->type_id->name,
       $mappos . ' ' . $position->featuremap_id->unittype_id->name
     );
-  } 
+  }
   // the $table array contains the headers and rows array as well as other
   // options for controlling the display of the table.  Additional
   // documentation can be found here:
@@ -132,7 +132,7 @@ if(count($feature_positions) > 0){ ?>
     'colgroups' => array(),
     'empty' => '',
   );
-  
+
   // once we have our table array structure defined, we call Drupal's theme_table()
   // function to generate the table.
   print theme_table($table);
@@ -143,14 +143,19 @@ if(count($feature_positions) > 0){ ?>
   // here we add the paramter 'block' => 'features'. This is because
   // the pager is not on the default block that appears. When the user clicks a
   // page number we want the browser to re-appear with the page is loaded.
+  // We remove the 'pane' parameter from the original query parameters because
+  // Drupal won't reset the parameter if it already exists.
+  $get = $_GET;
+  unset($_GET['pane']);
   $pager = array(
     'tags' => array(),
     'element' => $featurepos_pager_id,
     'parameters' => array(
-      'block' => 'featurepos'
+      'pane' => 'featurepos'
     ),
     'quantity' => $num_results_per_page,
   );
-  print theme_pager($pager); 
+  print theme_pager($pager);
+  $_GET = $get;
 }
 

+ 38 - 33
legacy/tripal_genetic/theme/templates/tripal_feature_genotypes.tpl.php

@@ -1,31 +1,31 @@
 <?php
 /*
  * Details about genotypes associated with features can be found in the following way:
- * 
+ *
  * feature => feature_genotype => genotype
- *   
- * There are two ways that features with genotypes can be associated with stocks.  The first, 
+ *
+ * There are two ways that features with genotypes can be associated with stocks.  The first,
  * more simple method, is by traversion the FK relationships in this manner:
- * 
+ *
  *   Simple Method: feature => feature_genotype => genotype => stock_genotype => stock
- *   
+ *
  * The second method involves use of the natural diversity tables which allows for association
- * or more ancilliary information. Within the Natural Diversity tables, if a feature has genotypes then 
- * you can find the corresponding stock by traversing the FK relationships 
- * in this manner: 
- * 
+ * or more ancilliary information. Within the Natural Diversity tables, if a feature has genotypes then
+ * you can find the corresponding stock by traversing the FK relationships
+ * in this manner:
+ *
  *   ND Method:     feature => feature_genotype => nd_experiment_genotype => nd_experiment => nd_experiment_stock => stock
- * 
- * The tripal_natural_diversity module handles association of stocks using the ND method.  
+ *
+ * The tripal_natural_diversity module handles association of stocks using the ND method.
  * This template handles association of stocks when stored using the simple method.
  * If the tripal_natural_diversity module is enabled then this template will not show.
  * You should instead see the tripal_feature.nd_genotypes.tpl.php template
- * 
+ *
  */
 $feature = $variables['node']->feature;
 
 // specify the number of genotypes to show by default and the unique pager ID
-$num_results_per_page = 25; 
+$num_results_per_page = 25;
 $feature_pager_id = 15;
 
 // get the genotypes from the feature_genotype table
@@ -36,7 +36,7 @@ $options = array(
     'element' => $feature_pager_id
   ),
 );
-$feature = chado_expand_var($feature, 'table', 'feature_genotype', $options); 
+$feature = chado_expand_var($feature, 'table', 'feature_genotype', $options);
 $feature_genotypes = $feature->feature_genotype->feature_id;
 
 // get the total number of records
@@ -44,8 +44,8 @@ $total_records = chado_pager_get_count($feature_pager_id);
 
 // now iterate through the feature genotypes and print a paged table.
 if (count($feature_genotypes) > 0) {?>
-  <div class="tripal_feature-data-block-desc tripal-data-block-desc">This following <?php print number_format($total_records) ?> genotype(s) have been recorded for this feature.</div><?php 
-  
+  <div class="tripal_feature-data-block-desc tripal-data-block-desc">This following <?php print number_format($total_records) ?> genotype(s) have been recorded for this feature.</div><?php
+
   // the $headers array is an array of fields to use as the colum headers.
   // additional documentation can be found here
   // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
@@ -56,26 +56,26 @@ if (count($feature_genotypes) > 0) {?>
   // can be found here:
   // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
   $rows = array();
-  
+
   foreach($feature_genotypes as $feature_genotype) {
     $genotype = $feature_genotype->genotype_id;
-    
+
     // show the uniquename for the genotype unless a name exists
     $name = $genotype->uniquename;
     if ($genotype->name){
       $name = $genotype->name;
     }
-    
+
     // get the genotype type
     $type = 'N/A';
     if ($genotype->type_id) {
       $type = ucwords(preg_replace('/_/', ' ', $genotype->type_id->name));
     }
-    
+
     // get the genotype properties
     $options = array('return_array' => 1);
     $genotype = chado_expand_var($genotype, 'table', 'genotypeprop', $options);
-    $properties = $genotype->genotypeprop; 
+    $properties = $genotype->genotypeprop;
     $details = '';
     if(count($properties) > 0) {
       foreach ($properties as $property){
@@ -83,7 +83,7 @@ if (count($feature_genotypes) > 0) {?>
       }
       $details = substr($details, 0, -4); // remove trailing <br>
     }
-    
+
     // add in stocks associated with this genotype if any
     $options = array(
       'return_array' => 1,
@@ -94,21 +94,21 @@ if (count($feature_genotypes) > 0) {?>
       ),
     );
     $genotype = chado_expand_var($genotype, 'table', 'stock_genotype', $options);
-    $stock_genotypes = $genotype->stock_genotype; 
+    $stock_genotypes = $genotype->stock_genotype;
 
     // build the list of germplasm.
     $stock_names = '';
-    if(count($stock_genotypes) > 0) { 
-      foreach ($stock_genotypes as $stock_genotype){ 
-        $stock = $stock_genotype->stock_id; 
-        $stock_name = $stock->name . ' (' . $stock->uniquename . ')'; 
+    if(count($stock_genotypes) > 0) {
+      foreach ($stock_genotypes as $stock_genotype){
+        $stock = $stock_genotype->stock_id;
+        $stock_name = $stock->name . ' (' . $stock->uniquename . ')';
         if(property_exists($stock, 'nid')) {
           $stock_name = l($stock_name, 'node/' . $stock->nid, array('attributes' => array('target' => '_blank')));
         }
         $stock_names .= $stock_name . '<br>';
       }
       $stock_names = substr($stock_names, 0, -4); // remove trailing <br>
-    } 
+    }
     // add the fields to the table row
     $rows[] = array(
       $name,
@@ -118,7 +118,7 @@ if (count($feature_genotypes) > 0) {?>
       $stock_names
     );
   }
-   
+
   // the $table array contains the headers and rows array as well as other
   // options for controlling the display of the table.  Additional
   // documentation can be found here:
@@ -135,24 +135,29 @@ if (count($feature_genotypes) > 0) {?>
     'colgroups' => array(),
     'empty' => '',
   );
-  
+
   // once we have our table array structure defined, we call Drupal's theme_table()
   // function to generate the table.
-  print theme_table($table); 
-  
+  print theme_table($table);
+
   // the $pager array values that control the behavior of the pager.  For
   // documentation on the values allows in this array see:
   // https://api.drupal.org/api/drupal/includes!pager.inc/function/theme_pager/7
   // here we add the paramter 'block' => 'features'. This is because
   // the pager is not on the default block that appears. When the user clicks a
   // page number we want the browser to re-appear with the page is loaded.
+  // We remove the 'pane' parameter from the original query parameters because
+  // Drupal won't reset the parameter if it already exists.
+  $get = $_GET;
+  unset($_GET['pane']);
   $pager = array(
     'tags' => array(),
     'element' => $feature_pager_id,
     'parameters' => array(
-      'block' => 'genotypes'
+      'pane' => 'genotypes'
     ),
     'quantity' => $num_results_per_page,
   );
   print theme_pager($pager);
+  $_GET = $get;
 }

+ 32 - 27
legacy/tripal_genetic/theme/templates/tripal_stock_genotypes.tpl.php

@@ -1,35 +1,35 @@
 <?php
 /*
- * Details about genotypes associated with stocks can be found in two ways by 
+ * Details about genotypes associated with stocks can be found in two ways by
  * traversing the the foreign key (FK) relationships in these ways:
- * 
+ *
  *   Simple Method: stock => stock_genotype => genotype
  *   ND Method:     stock => nd_experiment_stock => nd_experiment => nd_experiment_genotype => genotype
- *   
- * The tripal_natural_diversity module handles display of genotypes when stored using the 
+ *
+ * The tripal_natural_diversity module handles display of genotypes when stored using the
  * ND method.  This template handles display of genotype when stored using
  * the Simple Method.  If the tripal_natural_diversity module is enabled then this template
  * will not show.  You should instead see the tripal_stock.nd_genotypes.tpl.php template
- *  
+ *
  */
 $stock = $variables['node']->stock;
 
 // specify the number of genotypes to show by default and the unique pager ID
-$num_results_per_page = 25; 
+$num_results_per_page = 25;
 $stock_pager_id = 15;
 
 // get the genotypes from the stock_genotype table
 $options = array(
-  'return_array' => 1, 
+  'return_array' => 1,
   'pager' => array(
-    'limit' => $num_results_per_page, 
+    'limit' => $num_results_per_page,
     'element' => $stock_pager_id
   ),
   'fk_include' => array(
     'genotype_id' => 1
   ),
 );
-$stock = chado_expand_var($stock, 'table', 'stock_genotype', $options); 
+$stock = chado_expand_var($stock, 'table', 'stock_genotype', $options);
 $stock_genotypes = $stock->stock_genotype;
 
 // get the total number of records
@@ -38,26 +38,26 @@ $total_records = chado_pager_get_count($stock_pager_id);
 // now iterate through the stock genotypes and print a paged table.
 if (count($stock_genotypes) > 0) {?>
   <div class="tripal_stock-data-block-desc tripal-data-block-desc">The following <?php print number_format($total_records) ?> genotype(s) have been recorded for this stock.</div> <?php
-  
+
   // the $headers array is an array of fields to use as the colum headers.
   // additional documentation can be found here
   // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
   $headers = array('Name', 'Type', 'Genotype', 'Details', 'Markers');
-  
+
   // the $rows array contains an array of rows where each row is an array
   // of values for each column of the table in that row.  Additional documentation
   // can be found here:
   // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
   $rows = array();
-  
-  foreach($stock_genotypes as $stock_genotype) {       
+
+  foreach($stock_genotypes as $stock_genotype) {
     $genotype = $stock_genotype->genotype_id;
-    
+
     // get the genotype properties
     $options = array('return_array' => 1);
     $genotype = chado_expand_var($genotype, 'table', 'genotypeprop', $options);
-    $properties = $genotype->genotypeprop; 
-    
+    $properties = $genotype->genotypeprop;
+
     // add in markers associated with this genotype if any
     $options = array(
       'return_array' => 1,
@@ -68,8 +68,8 @@ if (count($stock_genotypes) > 0) {?>
       ),
     );
     $genotype = chado_expand_var($genotype, 'table', 'feature_genotype', $options);
-    $feature_genotypes = $genotype->feature_genotype; 
-    
+    $feature_genotypes = $genotype->feature_genotype;
+
     // show the uniquename for the genotype unless a name exists
     $name = $genotype->uniquename;
     if ($genotype->name){
@@ -80,7 +80,7 @@ if (count($stock_genotypes) > 0) {?>
     if ($genotype->type_id) {
       $type = ucwords(preg_replace('/_/', ' ', $genotype->type_id->name));
     }
-    
+
     // get the genotype properties
     $details = '';
     if(count($properties) > 0) {
@@ -89,7 +89,7 @@ if (count($stock_genotypes) > 0) {?>
       }
       $details = substr($details, 0, -4); // remove trailing <br>
     }
-    
+
     // build the list of marker features.
     $feature_names = 'N/A';
     if(count($feature_genotypes) > 0) {
@@ -104,7 +104,7 @@ if (count($stock_genotypes) > 0) {?>
       }
       $feature_names = substr($feature_names, 0, -4); // remove trailing <br>
     }
-      
+
     // add the fields to the table row
     $rows[] = array(
       $name,
@@ -113,8 +113,8 @@ if (count($stock_genotypes) > 0) {?>
       $details,
       $feature_names
     );
-  } 
-  
+  }
+
   // the $table array contains the headers and rows array as well as other
   // options for controlling the display of the table.  Additional
   // documentation can be found here:
@@ -134,20 +134,25 @@ if (count($stock_genotypes) > 0) {?>
   // once we have our table array structure defined, we call Drupal's theme_table()
   // function to generate the table.
   print theme_table($table);
-  
+
   // the $pager array values that control the behavior of the pager.  For
   // documentation on the values allows in this array see:
   // https://api.drupal.org/api/drupal/includes!pager.inc/function/theme_pager/7
   // here we add the paramter 'block' => 'features'. This is because
   // the pager is not on the default block that appears. When the user clicks a
   // page number we want the browser to re-appear with the page is loaded.
+  // We remove the 'pane' parameter from the original query parameters because
+  // Drupal won't reset the parameter if it already exists.
+  $get = $_GET;
+  unset($_GET['pane']);
   $pager = array(
     'tags' => array(),
     'element' => $stock_pager_id,
     'parameters' => array(
-      'block' => 'genotypes'
+      'pane' => 'genotypes'
     ),
     'quantity' => $num_results_per_page,
   );
-  print theme_pager($pager); 
-} 
+  print theme_pager($pager);
+  $_GET = $get;
+}

+ 6 - 1
legacy/tripal_library/theme/templates/tripal_library_features.tpl.php

@@ -86,15 +86,20 @@ if (count($features) > 0) { ?>
   // here we add the paramter 'block' => 'feature_browser'. This is because
   // the pager is not on the default block that appears. When the user clicks a
   // page number we want the browser to re-appear with the page is loaded.
+  // We remove the 'pane' parameter from the original query parameters because
+  // Drupal won't reset the parameter if it already exists.
+  $get = $_GET;
+  unset($_GET['pane']);
   $pager = array(
     'tags' => array(),
     'element' => $element,
     'parameters' => array(
-      'block' => 'features'
+      'pane' => 'features'
     ),
     'quantity' => $num_per_page,
   );
   print theme_pager($pager);
+  $_GET = $get;
 }
 
 

+ 35 - 30
legacy/tripal_natural_diversity/theme/templates/tripal_feature_nd_genotypes.tpl.php

@@ -2,25 +2,25 @@
 /*
  * Deatils about genotypes associated features can be found by traversing the foreign key (FK)
  * relationships in this way
- * 
+ *
  * feature => feature_genotype => genotype
  *
- * There are two ways that features with genotypes can be associated with stocks.  The first, 
+ * There are two ways that features with genotypes can be associated with stocks.  The first,
  * more simple method, is by traversion the FK relationships in this manner:
- * 
+ *
  *   Simple Method: feature => feature_genotype => genotype => stock_genotype => stock
- *   
+ *
  * The second method involves use of the natural diversity (ND) tables which allows for association
- * or more ancilliary information. Within the ND tables, If a feature has genotypes then 
- * you can find the corresponding stock by traversing the FK relationships 
- * in this manner: 
- * 
+ * or more ancilliary information. Within the ND tables, If a feature has genotypes then
+ * you can find the corresponding stock by traversing the FK relationships
+ * in this manner:
+ *
  *   ND MEthod: feature => feature_genotype => nd_experiment_genotype => nd_experiment => nd_experiment_stock => stock
- * 
+ *
  * You can find ancilliary information about data associated with a genotype in the ND tables such as
- * a contact, pub, protocol, project, genotype, dbxref by using the 
+ * a contact, pub, protocol, project, genotype, dbxref by using the
  * nd_experiment.nd_experiment_id value and traversing the other FK relationships
- * 
+ *
  * feature => feature_genotype => nd_experiment_genotype => nd_experiment => nd_experiment_stock => stock
  *                                                                        => nd_experiment_project => project
  *                                                                        => nd_experiment_pub => pub
@@ -29,16 +29,16 @@
  *                                                                        => nd_experiment_protocol => protocol
  *                                                                        => nd_experiment_stockprop
  *                                                                        => nd_experiment_stock_dbxref
- * 
- * In the FK relationships shown above, the nd_experiment_id value represents a single 
- * experimental value that may have all of the ancilliary data associated with it.  
+ *
+ * In the FK relationships shown above, the nd_experiment_id value represents a single
+ * experimental value that may have all of the ancilliary data associated with it.
  * If the genotype record shares an nd_experiment_id with a genotype, pub, contact,
  * protocol, etc then all of that data is associated with the genotype and vice-versa.
- * 
- * Techincally, we can skip including the 'nd_experiment' table when traversing the FK's 
- * because we have the nd_experiment_id value when we get the nd_experiment_genotype record. 
- * 
- * NOTE: if the tripal_natural_diversity module is enabled this template will supercede 
+ *
+ * Techincally, we can skip including the 'nd_experiment' table when traversing the FK's
+ * because we have the nd_experiment_id value when we get the nd_experiment_genotype record.
+ *
+ * NOTE: if the tripal_natural_diversity module is enabled this template will supercede
  * the tripal_feature_genotypes.tpl.php template (provided by the tripal_genetic module).
  * Therefore, this template must handle both cases for linking to stocks as described above
  */
@@ -67,7 +67,7 @@ $total_records = chado_pager_get_count($feature_pager_id);
 
 // now iterate through the feature genotypes and print a paged table.
 if (count($feature_genotypes) > 0) { ?>
-  <div class="tripal_feature-data-block-desc tripal-data-block-desc">This following <?php print number_format($total_records) ?> genotype(s) have been recorded for this feature.</div> <?php 
+  <div class="tripal_feature-data-block-desc tripal-data-block-desc">This following <?php print number_format($total_records) ?> genotype(s) have been recorded for this feature.</div> <?php
 
   // the $headers array is an array of fields to use as the colum headers.
   // additional documentation can be found here
@@ -79,11 +79,11 @@ if (count($feature_genotypes) > 0) { ?>
   // can be found here:
   // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
   $rows = array();
-  
+
   foreach ($feature_genotypes as $feature_genotype) {
     $project_names = 'N/A';
     $stock_names   = 'N/A';
-    
+
     // get the genotype from the feature_genotype record
     $genotype = $feature_genotype->genotype_id;
 
@@ -93,7 +93,7 @@ if (count($feature_genotypes) > 0) { ?>
     if ($genotype->name){
       $name = $genotype->name;
     }
-    
+
     // build the genotype type for display
     $type = 'N/A';
     if ($genotype->type_id) {
@@ -143,7 +143,7 @@ if (count($feature_genotypes) > 0) { ?>
         }
         $stock_names = substr($stock_names, 0, -4); // remove trailing <br>
       }
-      
+
       // expand the nd_experiment object to incldue the nd_experiment_project table
       $values = array('nd_experiment_id' => $nd_experiment_id);
       $options = array('return_array' => 1);
@@ -171,8 +171,8 @@ if (count($feature_genotypes) > 0) { ?>
       $stock_names,
       $project_names,
     );
-  } 
-  
+  }
+
   // the $table array contains the headers and rows array as well as other
   // options for controlling the display of the table.  Additional
   // documentation can be found here:
@@ -191,21 +191,26 @@ if (count($feature_genotypes) > 0) { ?>
   );
   // once we have our table array structure defined, we call Drupal's theme_table()
   // function to generate the table.
-  print theme_table($table); 
-  
+  print theme_table($table);
+
   // the $pager array values that control the behavior of the pager.  For
   // documentation on the values allows in this array see:
   // https://api.drupal.org/api/drupal/includes!pager.inc/function/theme_pager/7
   // here we add the paramter 'block' => 'features'. This is because
   // the pager is not on the default block that appears. When the user clicks a
   // page number we want the browser to re-appear with the page is loaded.
+  // We remove the 'pane' parameter from the original query parameters because
+  // Drupal won't reset the parameter if it already exists.
+  $get = $_GET;
+  unset($_GET['pane']);
   $pager = array(
     'tags' => array(),
     'element' => $feature_pager_id,
     'parameters' => array(
-      'block' => 'genotypes'
+      'pane' => 'genotypes'
     ),
     'quantity' => $num_results_per_page,
   );
-  print theme_pager($pager); 
+  print theme_pager($pager);
+  $_GET = $get;
 }

+ 44 - 39
legacy/tripal_natural_diversity/theme/templates/tripal_stock_nd_genotypes.tpl.php

@@ -1,26 +1,26 @@
 <?php
 /*
- * Details about genotypes associated with stocks can be found in two ways by 
+ * Details about genotypes associated with stocks can be found in two ways by
  * traversing the the foreign key (FK) relationships in these ways:
- * 
+ *
  *   Simple Method: stock => stock_genotype => genotype
  *   ND Method:     stock => nd_experiment_stock => nd_experiment => nd_experiment_genotype => genotype
  *
- * The tripal_genetic module handles display of genotypes when stored using the 
+ * The tripal_genetic module handles display of genotypes when stored using the
  * simple method.  This template handles display of genotype when stored using
- * the ND Method.  The ND method uses the natural diversity tables and allows for 
- * association or more ancilliary information. 
- * 
- * 
- * Within the ND tables, If a stock has genotypes then you can find the corresponding 
- * features by traversing the FK relationships in this manner: 
- * 
+ * the ND Method.  The ND method uses the natural diversity tables and allows for
+ * association or more ancilliary information.
+ *
+ *
+ * Within the ND tables, If a stock has genotypes then you can find the corresponding
+ * features by traversing the FK relationships in this manner:
+ *
  * stock => nd_experiment_stock => nd_experiment => nd_experiment_genotype => genotype => feature_genotype => feature
- * 
+ *
  * You can find ancilliary information about data associated with a genotype in the ND tables such as
- * a contact, pub, protocol, project, genotype, dbxref by using the 
+ * a contact, pub, protocol, project, genotype, dbxref by using the
  * nd_experiment.nd_experiment_id value and traversing the other FK relationships
- * 
+ *
  * stock => nd_experiment_stock => nd_experiment => nd_experiment_project => project
  *                                               => nd_experiment_pub => pub
  *                                               => nd_experiment_contact => contact
@@ -28,21 +28,21 @@
  *                                               => nd_experiment_protocol => protocol
  *                                               => nd_experiment_stockprop
  *                                               => nd_experiment_stock_dbxref
- * 
- * In the FK relationships shown above, the nd_experiment_id value represents a single 
- * experimental unit that may have all of the ancilliary data associated with it or none.  
+ *
+ * In the FK relationships shown above, the nd_experiment_id value represents a single
+ * experimental unit that may have all of the ancilliary data associated with it or none.
  * If the genotype record shares an nd_experiment_id with a genotype, pub, contact,
  * protocol, etc then all of that data is associated with the genotype and vice-versa.
- * 
- * Techincally, we can skip including the 'nd_experiment' table when traversing the FK's 
+ *
+ * Techincally, we can skip including the 'nd_experiment' table when traversing the FK's
  * because we have the nd_experiment_id value when we get the nd_experiment_stock record.
- * 
+ *
  * When lots of genotypes are associated with a stock (e.g. thousands) then traversing
  * the FK relationships as described above can be very slow. Ideally, we only need to
- * show a small subset with a pager. Therefore, a list of nd_experiment_genotype_id's 
+ * show a small subset with a pager. Therefore, a list of nd_experiment_genotype_id's
  * are provided to this template automatically within the stock object.
- * 
- * NOTE: if the tripal_natural_diversity module is enabled this template will supercede 
+ *
+ * NOTE: if the tripal_natural_diversity module is enabled this template will supercede
  * the tripal_stock_genotypes.tpl.php template (provided by the tripal_genetic module).
  * Therefore, this template must handle both cases for linking to features as described above
  */
@@ -57,7 +57,7 @@ $stock_pager_id = 15;
 
 // the nd_experiment_genotype IDs get passed into this template, so we use
 // those to iterate and show a subset via a pager.  This is faster than trying
-// to traverse all of the FK relationship, especially when thousands of 
+// to traverse all of the FK relationship, especially when thousands of
 // associations may be present.  Because the nd_experiment_id in Chado
 // can be associated with other data types it becomes slow to use the
 // chado_expand_var functions that we would normal use.
@@ -70,13 +70,13 @@ $offset = $num_results_per_page * $current_page_num;
 
 $genotypes = array();
 if ($total_records > 0) {
-  
+
   // iterate through the nd_experiment_genotype_ids and get the genotype record
   for ($i = $offset ; $i < $offset + $num_results_per_page; $i++) {
     $nd_experiment_genotype_id = $nd_experiment_genotype_ids[$i];
-      
+
     // expand the nd_experiment record to include the nd_experiment_genotype table
-    // there many be many genotypes for a stock so we want to use a pager to limit 
+    // there many be many genotypes for a stock so we want to use a pager to limit
     // the results returned
     $options = array(
       'return_array' => 1,
@@ -98,7 +98,7 @@ if ($total_records > 0) {
 if (count($genotypes) > 0) { ?>
   <div class="tripal_feature-data-block-desc tripal-data-block-desc">
     The following <?php print number_format($total_records) ?> genotype(s) have been recorded.
-  </div> <?php 
+  </div> <?php
 
   // the $headers array is an array of fields to use as the colum headers.
   // additional documentation can be found here
@@ -110,26 +110,26 @@ if (count($genotypes) > 0) { ?>
   // can be found here:
   // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
   $rows = array();
-  
+
   // iterate through the genotypes and build each row of the resulting table
   foreach ($genotypes as $info) {
     $genotype         = $info['genotype'];
     $nd_experiment_id = $info['nd_experiment_id'];
-    
+
     // get the nd_experiment record
     $nd_experiment = chado_generate_var('nd_experiment', array('nd_experiment_id' => $nd_experiment_id));
-    
+
     // set some defaults for project and feature names
     $project_names = 'N/A';
     $feature_names = 'N/A';
-    
+
     // build the name for displaying the genotype. Use the uniquename by default
     // unless a name exists
     $name = $genotype->uniquename;
     if ($genotype->name){
       $name = $genotype->name;
     }
-    
+
     // build the genotype type for display
     $type = 'N/A';
     if ($genotype->type_id) {
@@ -147,7 +147,7 @@ if (count($genotypes) > 0) { ?>
       }
       $details = substr($details, 0, -4); // remove trailing <br>
     }
-    
+
     // get the features as found in the feature_genotype table and if any, add them to the $features array
     // we will later add in the features list for display
     $features = array();
@@ -173,7 +173,7 @@ if (count($genotypes) > 0) { ?>
       }
       $feature_names = substr($feature_names, 0, -4); // remove trailing <br>
     }
-      
+
     // expand the nd_experiment object to incldue the nd_experiment_project table
     $values = array('nd_experiment_id' => $nd_experiment_id);
     $options = array('return_array' => 1);
@@ -200,8 +200,8 @@ if (count($genotypes) > 0) { ?>
       $feature_names,
       $project_names,
     );
-  } 
-  
+  }
+
   // the $table array contains the headers and rows array as well as other
   // options for controlling the display of the table.  Additional
   // documentation can be found here:
@@ -220,21 +220,26 @@ if (count($genotypes) > 0) { ?>
   );
   // once we have our table array structure defined, we call Drupal's theme_table()
   // function to generate the table.
-  print theme_table($table); 
-  
+  print theme_table($table);
+
   // the $pager array values that control the behavior of the pager.  For
   // documentation on the values allows in this array see:
   // https://api.drupal.org/api/drupal/includes!pager.inc/function/theme_pager/7
   // here we add the paramter 'block' => 'features'. This is because
   // the pager is not on the default block that appears. When the user clicks a
   // page number we want the browser to re-appear with the page is loaded.
+  // We remove the 'pane' parameter from the original query parameters because
+  // Drupal won't reset the parameter if it already exists.
+  $get = $_GET;
+  unset($_GET['pane']);
   $pager = array(
     'tags' => array(),
     'element' => $stock_pager_id,
     'parameters' => array(
-      'block' => 'genotypes'
+      'pane' => 'genotypes'
     ),
     'quantity' => $num_results_per_page,
   );
   print theme_pager($pager);
+  $_GET = $get;
 }

+ 41 - 36
legacy/tripal_natural_diversity/theme/templates/tripal_stock_nd_phenotypes.tpl.php

@@ -2,14 +2,14 @@
 /*
  * Phenotype relationships with stocks are stored in the natural diversity tables.
  * If a stock has phenotypes associated then you can find the data by traversing
- * the foreign key (FK) relationships in this manner: 
- * 
+ * the foreign key (FK) relationships in this manner:
+ *
  * stock => nd_experiment_stock => nd_experiment => nd_experiment_phenotype => phenotype.
- * 
+ *
  * You can find ancillary information about data associated with a phenotype such as
- * a contact, pub, protocol, project, phenotype, dbxref by using the 
+ * a contact, pub, protocol, project, phenotype, dbxref by using the
  * nd_experiment.nd_experiment_id value and traversing the other FK relationships
- * 
+ *
  * stock => nd_experiment_stock => nd_experiment => nd_experiment_phenotype => phenotype
  *                                               => nd_experiment_phenotype => phenotype
  *                                               => nd_experiment_project => project
@@ -19,20 +19,20 @@
  *                                               => nd_experiment_protocol => protocol
  *                                               => nd_experiment_stockprop
  *                                               => nd_experiment_stock_dbxref
- * 
- * In the FK relationships shown above, the nd_experiment_id value represents a single 
- * experimental value that may have all of the ancilliary data associated with it.  
+ *
+ * In the FK relationships shown above, the nd_experiment_id value represents a single
+ * experimental value that may have all of the ancilliary data associated with it.
  * If the phenotype record shares an nd_experiment_id with a phenotype, pub, contact,
  * protocol, etc then all of that data is associated with the phenotype and vice-versa.
- * 
- * Techincally, we can skip including the 'nd_experiment' table when traversing the FK's 
+ *
+ * Techincally, we can skip including the 'nd_experiment' table when traversing the FK's
  * because we have the nd_experiment_id value when we get the nd_experiment_stock record.
- * 
+ *
  * When lots of phenotypes are associated with a stock (e.g. thousands) then traversing
  * the FK relationships as described above can be very slow. Ideally, we only need to
- * show a small subset with a pager. Therefore, a list of nd_experiment_phenotype_id's 
+ * show a small subset with a pager. Therefore, a list of nd_experiment_phenotype_id's
  * are provided to this template automatically within the stock object.
- * 
+ *
  */
 
 // get the current stock
@@ -45,7 +45,7 @@ $stock_pager_id = 10;
 
 // the nd_experiment_phenotype IDs get passed into this template, so we use
 // those to iterate and show a subset via a pager.  This is faster than trying
-// to traverse all of the FK relationship, especially when thousands of 
+// to traverse all of the FK relationship, especially when thousands of
 // associations may be present.  Because the nd_experiment_id in Chado
 // can be associated with other data types it becomes slow to use the
 // chado_expand_var functions that we would normal use.
@@ -59,11 +59,11 @@ $offset = $num_results_per_page * $current_page_num;
 
 $phenotypes = array();
 if ($total_records > 0) {
-  
+
   // iterate through the nd_experiment_phenotype_ids and get the phenotype record
   for ($i = $offset ; $i < $offset + $num_results_per_page; $i++) {
     // expand the nd_experiment record to include the nd_experiment_phenotype table
-    // there many be many phenotypes for a stock so we want to use a pager to limit 
+    // there many be many phenotypes for a stock so we want to use a pager to limit
     // the results returned
     $options = array(
       'return_array' => 1,
@@ -84,7 +84,7 @@ if ($total_records > 0) {
 if (count($phenotypes) > 0) {?>
   <div class="tripal_stock-data-block-desc tripal-data-block-desc">
     The following <?php print number_format($total_records) ?> phenotypes(s) have been recorded.
-  </div><?php 
+  </div><?php
 
   // the $headers array is an array of fields to use as the colum headers.
   // additional documentation can be found here
@@ -96,43 +96,43 @@ if (count($phenotypes) > 0) {?>
   // can be found here:
   // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
   $rows = array();
-  
-  // iterate through the nd_experiment_stock records and get 
+
+  // iterate through the nd_experiment_stock records and get
   // each experiment and the associated phenotypes
   foreach ($phenotypes as $info){
     $phenotype         = $info['phenotype'];
     $nd_experiment_id  = $info['nd_experiment_id'];
-    
+
     // get the nd_experiment record
     $nd_experiment = chado_generate_var('nd_experiment', array('nd_experiment_id' => $nd_experiment_id));
-    
+
     $details = '';
 
-    if ($phenotype->name) { 
+    if ($phenotype->name) {
       $details .= "Name: $phenotype->name<br>";
     }
-    
-    // add in the attribute type pheonotypes values are stored qualitatively or quantitatively. 
+
+    // add in the attribute type pheonotypes values are stored qualitatively or quantitatively.
     // If qualitatively the cvalue_id will link to a type. If quantitative we
     // use the value column
     $details .= ucwords(preg_replace('/_/', ' ', $phenotype->attr_id->name)) . ': ';
-    if ($phenotype->cvalue_id) { 
+    if ($phenotype->cvalue_id) {
       $details .= ucwords(preg_replace('/_/', ' ', $phenotype->cvalue_id->name)) . '<br>';
     }
-    else { 
+    else {
       $details .= $phenotype->value . '<br>';
-    }  
-    
+    }
+
     // get the observable unit and add it to the details
-    if ($phenotype->observable_id) { 
+    if ($phenotype->observable_id) {
       $details .= "Observable Unit: " . ucwords(preg_replace('/_/', ' ', $phenotype->observable_id->name)) . '<br>';
     }
-    
+
     // get the evidence unit and add it to the details
-    if ($phenotype->assay_id) { 
+    if ($phenotype->assay_id) {
       $details .= "Evidence: " .  ucwords(preg_replace('/_/', ' ', $phenotype->assay_id->name)) . '<br>';
     }
-    
+
     // Get the project for this experiment. For each nd_experiment_id there should only be one project
     // but the database does not constrain that there only be one project so just in case we get them all
     $projects = array();
@@ -153,7 +153,7 @@ if (count($phenotypes) > 0) {?>
       $pnames .= $name . '<br>';
     }
     $pnames = substr($pnames, 0, -4); // remove trailing <br>
-    
+
     $rows[] = array(
        $details,
        $pnames,
@@ -177,21 +177,26 @@ if (count($phenotypes) > 0) {?>
   );
   // once we have our table array structure defined, we call Drupal's theme_table()
   // function to generate the table.
-  print theme_table($table); 
-  
+  print theme_table($table);
+
   // the $pager array values that control the behavior of the pager.  For
   // documentation on the values allows in this array see:
   // https://api.drupal.org/api/drupal/includes!pager.inc/function/theme_pager/7
   // here we add the paramter 'block' => 'features'. This is because
   // the pager is not on the default block that appears. When the user clicks a
   // page number we want the browser to re-appear with the page is loaded.
+  // We remove the 'pane' parameter from the original query parameters because
+  // Drupal won't reset the parameter if it already exists.
+  $get = $_GET;
+  unset($_GET['pane']);
   $pager = array(
     'tags' => array(),
     'element' => $stock_pager_id,
     'parameters' => array(
-      'block' => 'genotypes'
+      'pane' => 'genotypes'
     ),
     'quantity' => $num_results_per_page,
   );
   print theme_pager($pager);
+  $_GET = $get;
 }

+ 1 - 1
legacy/tripal_phylogeny/tripal_phylogeny.module

@@ -267,7 +267,7 @@ function tripal_phylogeny_ajax_get_tree_json($phylotree_id) {
 
   // This SQL gets all of the phylonodes for a given tree as well as the
   // features and organisms with which it is assocaited.  Each phylonode
-  // can be associated with an orgnaism in one of two ways: 1) via a
+  // can be associated with an organism in one of two ways: 1) via a
   // feature linked by the phylonode.feature_id field or 2) via a
   // a record in the phylonde_organsim table.  Therefore both types of
   // organism records are returned in the query below, but those

+ 1 - 1
legacy/tripal_pub/includes/tripal_pub.chado_node.inc

@@ -1188,7 +1188,7 @@ function tripal_pub_node_insert($node) {
 function tripal_pub_node_load($nodes, $types) {
   if (count(array_intersect(array('chado_pub'), $types))) {
     foreach ($nodes as $nid => $node) {
-      if ($node->type == 'chado_pub' and !property_exists($node, 'path')) {
+      if ($node->type == 'chado_pub' and !drupal_lookup_path('alias', 'node/' . $nid)) {
         $pub_id = chado_get_id_from_nid('pub', $node->nid);
         $path = tripal_pub_set_pub_url($node, $pub_id);
       }

+ 1 - 1
legacy/tripal_pub/includes/tripal_pub.pub_search.inc

@@ -575,7 +575,7 @@ function tripal_search_publications($search_array, $offset, $limit, &$total_reco
   // build the SQL based on the criteria provided by the user
   $select = "SELECT DISTINCT P.*, CP.nid ";
   $from   = "FROM {pub} P
-               LEFT JOIN {chado_pub} CP on P.pub_id = CP.pub_id
+               LEFT JOIN [chado_pub] CP on P.pub_id = CP.pub_id
                INNER JOIN {cvterm} CVT on CVT.cvterm_id = P.type_id
             ";
   $where  = "WHERE (NOT P.title = 'null') "; // always exclude the dummy pub

+ 8 - 2
legacy/tripal_pub/theme/templates/tripal_pub_featuremaps.tpl.php

@@ -81,14 +81,20 @@ if(count($featuremaps) > 0){ ?>
   // here we add the paramter 'block' => 'featuremaps'. This is because
   // the pager is not on the default block that appears. When the user clicks a
   // page number we want the browser to re-appear with the page is loaded.
+  // We remove the 'pane' parameter from the original query parameters because
+  // Drupal won't reset the parameter if it already exists.
+  $get = $_GET;
+  unset($_GET['pane']);
   $pager = array(
     'tags' => array(),
     'element' => $element,
     'parameters' => array(
-      'block' => 'featuremaps'
+      'pane' => 'featuremaps'
     ),
     'quantity' => $num_per_page,
   );
   print theme_pager($pager);
-}?>
+  $_GET = $get;
+}
+
 

+ 6 - 1
legacy/tripal_pub/theme/templates/tripal_pub_features.tpl.php

@@ -83,14 +83,19 @@ if(count($features) > 0){ ?>
   // here we add the paramter 'block' => 'features'. This is because
   // the pager is not on the default block that appears. When the user clicks a
   // page number we want the browser to re-appear with the page is loaded.
+  // We remove the 'pane' parameter from the original query parameters because
+  // Drupal won't reset the parameter if it already exists.
+  $get = $_GET;
+  unset($_GET['pane']);
   $pager = array(
     'tags' => array(),
     'element' => $element,
     'parameters' => array(
-      'block' => 'features'
+      'pane' => 'features'
     ),
     'quantity' => $num_per_page,
   );
   print theme_pager($pager);
+  $_GET = $get;
 }
 

+ 6 - 1
legacy/tripal_pub/theme/templates/tripal_pub_libraries.tpl.php

@@ -86,14 +86,19 @@ if(count($libraries) > 0){ ?>
   // here we add the paramter 'block' => 'libraries'. This is because
   // the pager is not on the default block that appears. When the user clicks a
   // page number we want the browser to re-appear with the page is loaded.
+  // We remove the 'pane' parameter from the original query parameters because
+  // Drupal won't reset the parameter if it already exists.
+  $get = $_GET;
+  unset($_GET['pane']);
   $pager = array(
     'tags' => array(),
     'element' => $element,
     'parameters' => array(
-      'block' => 'libraries'
+      'pane' => 'libraries'
     ),
     'quantity' => $num_per_page,
   );
   print theme_pager($pager);
+  $_GET = $get;
 }
 

+ 6 - 1
legacy/tripal_pub/theme/templates/tripal_pub_projects.tpl.php

@@ -85,14 +85,19 @@ if(count($projects) > 0){ ?>
   // here we add the paramter 'block' => 'projects'. This is because
   // the pager is not on the default block that appears. When the user clicks a
   // page number we want the browser to re-appear with the page is loaded.
+  // We remove the 'pane' parameter from the original query parameters because
+  // Drupal won't reset the parameter if it already exists.
+  $get = $_GET;
+  unset($_GET['pane']);
   $pager = array(
     'tags' => array(),
     'element' => $element,
     'parameters' => array(
-      'block' => 'projects'
+      'pane' => 'projects'
     ),
     'quantity' => $num_per_page,
   );
   print theme_pager($pager);
+  $_GET = $get;
 }
 

+ 6 - 1
legacy/tripal_pub/theme/templates/tripal_pub_stocks.tpl.php

@@ -83,14 +83,19 @@ if(count($stocks) > 0){ ?>
   // here we add the paramter 'block' => 'stocks'. This is because
   // the pager is not on the default block that appears. When the user clicks a
   // page number we want the browser to re-appear with the page is loaded.
+  // We remove the 'pane' parameter from the original query parameters because
+  // Drupal won't reset the parameter if it already exists.
+  $get = $_GET;
+  unset($_GET['pane']);
   $pager = array(
     'tags' => array(),
     'element' => $element,
     'parameters' => array(
-      'block' => 'stocks'
+      'pane' => 'stocks'
     ),
     'quantity' => $num_per_page,
   );
   print theme_pager($pager);
+  $_GET = $get;
 }
 

+ 56 - 0
legacy/tripal_stock/includes/tripal_stock.chado_node.inc

@@ -926,3 +926,59 @@ function chado_stock_chado_node_default_title_format() {
 function chado_stock_chado_node_default_url_format() {
   return '/stock/[stock.organism_id>organism.genus]/[stock.organism_id>organism.species]/[stock.type_id>cvterm.name]/[stock.uniquename]';
 }
+
+/**
+ * Implement hook_node_access().
+ *
+ * This hook allows node modules to limit access to the node types they define.
+ *
+ *  @param $node
+ *  The node on which the operation is to be performed, or, if it does not yet exist, the
+ *  type of node to be created
+ *
+ *  @param $op
+ *  The operation to be performed
+ *
+ *  @param $account
+ *  A user object representing the user for whom the operation is to be performed
+ *
+ *  @return
+ *  If the permission for the specified operation is not set then return FALSE. If the
+ *  permission is set then return NULL as this allows other modules to disable
+ *  access.  The only exception is when the $op == 'create'.  We will always
+ *  return TRUE if the permission is set.
+ *
+ * @ingroup tripal_stock
+ */
+
+function tripal_stock_node_access($node, $op, $account) {
+  $node_type = $node;
+  if (is_object($node)) {
+    $node_type = $node->type;
+  }
+
+  if($node_type == 'chado_stock') {
+    if ($op == 'create') {
+      if (!user_access('create chado_stock content', $account)) {
+        return NODE_ACCESS_DENY;
+      }
+      return NODE_ACCESS_ALLOW;
+    }
+    if ($op == 'update') {
+      if (!user_access('edit chado_stock content', $account)) {
+        return NODE_ACCESS_DENY;
+      }
+    }
+    if ($op == 'delete') {
+      if (!user_access('delete chado_stock content', $account)) {
+        return NODE_ACCESS_DENY;
+      }
+    }
+    if ($op == 'view') {
+      if (!user_access('access chado_stock content', $account)) {
+        return NODE_ACCESS_DENY;
+      }
+    }
+    return NODE_ACCESS_IGNORE;
+  }
+}

+ 7 - 1
legacy/tripal_stock/theme/templates/tripal_organism_stocks.tpl.php

@@ -82,15 +82,21 @@ if (count($stocks) > 0) { ?>
   // here we add the paramter 'block' => 'features'. This is because
   // the pager is not on the default block that appears. When the user clicks a
   // page number we want the browser to re-appear with the page is loaded.
+  // We remove the 'pane' parameter from the original query parameters because
+  // Drupal won't reset the parameter if it already exists.
+  $get = $_GET;
+  unset($_GET['pane']);
   $pager = array(
     'tags' => array(),
     'element' => $pager_id,
     'parameters' => array(
-      'block' => 'stocks'
+      'pane' => 'stocks'
     ),
     'quantity' => $num_results_per_page,
   );
   print theme_pager($pager);
+  $_GET = $get;
+
 }
 
 

+ 1 - 57
legacy/tripal_stock/tripal_stock.module

@@ -183,62 +183,6 @@ function tripal_stock_permission() {
   );
 }
 
-/**
- * Implement hook_node_access().
- *
- * This hook allows node modules to limit access to the node types they define.
- *
- *  @param $node
- *  The node on which the operation is to be performed, or, if it does not yet exist, the
- *  type of node to be created
- *
- *  @param $op
- *  The operation to be performed
- *
- *  @param $account
- *  A user object representing the user for whom the operation is to be performed
- *
- *  @return
- *  If the permission for the specified operation is not set then return FALSE. If the
- *  permission is set then return NULL as this allows other modules to disable
- *  access.  The only exception is when the $op == 'create'.  We will always
- *  return TRUE if the permission is set.
- *
- * @ingroup tripal_stock
- */
-
-function tripal_stock_node_access($node, $op, $account) {
-  $node_type = $node;
-  if (is_object($node)) {
-    $node_type = $node->type;
-  }
-
-  if($node_type == 'chado_stock') {
-    if ($op == 'create') {
-      if (!user_access('create chado_stock content', $account)) {
-        return NODE_ACCESS_DENY;
-      }
-      return NODE_ACCESS_ALLOW;
-    }
-    if ($op == 'update') {
-      if (!user_access('edit chado_stock content', $account)) {
-        return NODE_ACCESS_DENY;
-      }
-    }
-    if ($op == 'delete') {
-      if (!user_access('delete chado_stock content', $account)) {
-        return NODE_ACCESS_DENY;
-      }
-    }
-    if ($op == 'view') {
-      if (!user_access('access chado_stock content', $account)) {
-        return NODE_ACCESS_DENY;
-      }
-    }
-    return NODE_ACCESS_IGNORE;
-  }
-}
-
 /**
  * Implements hook_views_api().
  *
@@ -392,7 +336,7 @@ function tripal_stock_match_stocks_page($id) {
     FROM {stock} S
       INNER JOIN {organism} O on S.organism_id = O.organism_id
       INNER JOIN {cvterm} CVT on CVT.cvterm_id = S.type_id
-      INNER JOIN {chado_stock} CS on CS.stock_id = S.stock_id
+      INNER JOIN [chado_stock] CS on CS.stock_id = S.stock_id
     WHERE
       S.uniquename = :uname or S.name = :name
   ";

+ 35 - 4
tripal/api/tripal.jobs.api.inc

@@ -345,12 +345,12 @@ function tripal_launch_job($do_parallel = 0, $job_id = NULL, $max_jobs = -1, $si
   // First check if any jobs are currently running if they are, don't continue,
   // we don't want to have more than one job script running at a time.
   if (!$do_parallel and tripal_is_job_running()) {
-    print "Jobs are still running. Use the --parallel=1 option with the Drush command to run jobs in parallel.\n";
+    print date('Y-m-d H:i:s') . ": Jobs are still running. Use the --parallel=1 option with the Drush command to run jobs in parallel.";
     return;
   }
 
   if ($do_parallel && tripal_max_jobs_exceeded($max_jobs)) {
-    print "At least $max_jobs jobs are still running. At least one of these jobs much complete before a new job can start.\n";
+    print date('Y-m-d H:i:s') . ": More than $max_jobs jobs are still running. At least one of these jobs much complete before a new job can start.";
     return;
   }
 
@@ -380,7 +380,10 @@ function tripal_launch_job($do_parallel = 0, $job_id = NULL, $max_jobs = -1, $si
     ";
     $jobs = db_query($sql);
   }
-  print "There are " . $jobs->rowCount() . " jobs queued.\n";
+  if ($jobs) {
+    print date('Y-m-d H:i:s') . ": There are " . $jobs->rowCount() . " jobs queued.\n";
+  }
+
   foreach ($jobs as $jid) {
 
     $job_id = $jid->job_id;
@@ -408,7 +411,7 @@ function tripal_launch_job($do_parallel = 0, $job_id = NULL, $max_jobs = -1, $si
 
     // Run the job
     $callback = $job->getCallback();
-    print "Calling Job #$job_id: $callback(" . implode(", ", $string_args) . ")\n";
+    print date('Y-m-d H:i:s') .": Calling: $callback(" . implode(", ", $string_args) . ")\n";
     try {
       $job->run();
     }
@@ -528,3 +531,31 @@ function tripal_get_active_jobs($modulename = NULL) {
   }
   return $jobs;
 }
+
+
+/**
+ * Execute a specific Tripal Job.
+ *
+ * @param $job_id
+ *   The job id to be exeuted.
+ * @param bool $redirect [optional]
+ *   Whether to redirect to the job page or not.
+ */
+function tripal_execute_job($job_id, $redirect = TRUE) {
+
+  $job = new TripalJob();
+  $job->load($job_id);
+
+  // Run the job.
+  if ($job->getStartTime() == 0 and $job->getEndTime() == 0) {
+    tripal_launch_job(1, $job_id);
+    drupal_set_message(t("Job %job_id has finished executing. See below for more information.", array('%job_id' => $job_id)));
+  }
+  else {
+    drupal_set_message(t("Job %job_id cannot be executed. It has already finished.", array('%job_id' => $job_id)));
+  }
+
+  if ($redirect) {
+    drupal_goto("admin/tripal/tripal_jobs/view/$job_id");
+  }
+}

+ 18 - 9
tripal/api/tripal.notice.api.inc

@@ -86,6 +86,12 @@ function tripal_report_error($type, $severity, $message, $variables = array(), $
       break;
   }
 
+  // If we are not set to return debugging information and the severity string
+  // is debug then don't report the error.
+  if (($severity == TRIPAL_DEBUG) AND (getenv('TRIPAL_DEBUG') != 1)) {
+      return FALSE;
+  }
+
   // Get the backtrace and include in the error message, but only if the
   // TRIPAL_DEBUG environment variable is set.
   if (getenv('TRIPAL_DEBUG') == 1) {
@@ -98,7 +104,7 @@ function tripal_report_error($type, $severity, $message, $variables = array(), $
     }
   }
 
-  // Send to watchdog
+  // Send to watchdog.
   try {
     watchdog($type, $message, $variables, $severity);
   }
@@ -107,7 +113,7 @@ function tripal_report_error($type, $severity, $message, $variables = array(), $
     $options['print'] = TRUE;
   }
 
-  // Format the message for printing (either to the screen, log or both)
+  // Format the message for printing (either to the screen, log or both).
   if (sizeof($variables) > 0) {
     $print_message = str_replace(array_keys($variables), $variables, $message);
   }
@@ -115,13 +121,15 @@ function tripal_report_error($type, $severity, $message, $variables = array(), $
     $print_message = $message;
   }
 
-  // If print option supplied then print directly to the screen
+  // If print option supplied then print directly to the screen.
   if (isset($options['print'])) {
     print $severity_string . ' (' . strtoupper($type) . '): ' . $print_message . "\n";
   }
 
-  // Print to the Tripal error log
-  tripal_log('[' . strtoupper($type) . '] ' . $print_message . "\n", $severity_string);
+  // Print to the Tripal error log but only if the severity is not info.
+  if (($severity != TRIPAL_INFO)) {
+    tripal_log('[' . strtoupper($type) . '] ' . $print_message . "\n", $severity_string);
+  }
 
 }
 
@@ -210,10 +218,11 @@ function tripal_set_message($message, $importance = TRIPAL_INFO, $options = arra
  *   are supported.
  * @param $options
  *   An array of options where the following keys are supported:
- *     - first_progress_bar: this sohuld be used for the first log call for a progress bar
- *     - is_progress_bar: this option should be used for all but the first print of a
- *         progress bar to allow it all to be printed on the same line without intervening
- *         date prefixes
+ *     - first_progress_bar: this sohuld be used for the first log call for a
+ *       progress bar
+ *     - is_progress_bar: this option should be used for all but the first print
+ *       of a progress bar to allow it all to be printed on the same line
+ *       without intervening date prefixes
  * @return
  *   The number of bytes that were written to the file, or FALSE on failure
  */

+ 46 - 44
tripal/includes/TripalImporter.inc

@@ -434,49 +434,6 @@ class TripalImporter {
     }
   }
 
-  // --------------------------------------------------------------------------
-  //                     OVERRIDEABLE FUNCTIONS
-  // --------------------------------------------------------------------------
-
-  /**
-   * Provides form elements to be added to the loader form.
-   *
-   * These form elements are added after the file uploader section that
-   * is automaticaly provided by the TripalImporter.
-   *
-   * @return
-   *   A $form array.
-   */
-  public function form($form, &$form_state) {
-    return $form;
-  }
-
-  /**
-   * Handles submission of the form elements.
-   *
-   * The form elements provided in the implementation of the form() function
-   * can be used for special submit if needed.
-   */
-  public function formSubmit($form, &$form_state) {
-
-  }
-
-  /**
-   * Handles validation of the form elements.
-   *
-   * The form elements provided in the implementation of the form() function
-   * should be validated using this function.
-   */
-  public function formValidate($form, &$form_state) {
-
-  }
-
-  /**
-   * Performs the import.
-   */
-  public function run() {
-  }
-
   /**
    * Logs a message for the importer.
    *
@@ -537,7 +494,7 @@ class TripalImporter {
    *   The total number of items to process.
    */
   protected function setTotalItems($total_items) {
-     $this->total_items = $total_items;
+    $this->total_items = $total_items;
   }
   /**
    * Adds to the count of the total number of items that have been handle.d
@@ -603,4 +560,49 @@ class TripalImporter {
   protected function setInterval($interval) {
     $this->interval = $interval;
   }
+
+  // --------------------------------------------------------------------------
+  //                     OVERRIDEABLE FUNCTIONS
+  // --------------------------------------------------------------------------
+
+  /**
+   * Provides form elements to be added to the loader form.
+   *
+   * These form elements are added after the file uploader section that
+   * is automaticaly provided by the TripalImporter.
+   *
+   * @return
+   *   A $form array.
+   */
+  public function form($form, &$form_state) {
+    return $form;
+  }
+
+  /**
+   * Handles submission of the form elements.
+   *
+   * The form elements provided in the implementation of the form() function
+   * can be used for special submit if needed.
+   */
+  public function formSubmit($form, &$form_state) {
+
+  }
+
+  /**
+   * Handles validation of the form elements.
+   *
+   * The form elements provided in the implementation of the form() function
+   * should be validated using this function.
+   */
+  public function formValidate($form, &$form_state) {
+
+  }
+
+  /**
+   * Performs the import.
+   */
+  public function run() {
+  }
+
+
 }

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

@@ -260,6 +260,134 @@ function tripal_entity_info_alter(&$entity_info){
   }
 }
 
+/**
+ * Implements hook_entity_property_info_alter().
+ *
+ * For some reason not all our TripalFields end up in the properties field for
+ * each bundle. This becomes a problem with Search API integration because only
+ * fields listed in the properties for a bundle are available to be indexed.
+ * Thus we are altering the property info to add any fields attached to
+ * TripalEntities which may have been missed.
+ *
+ * Furthermore, there are some pecularities with how TripalFields store their
+ * value that causes the default getter callback difficulties in some edge cases.
+ * Thus we are overriding that function below.
+ */
+function tripal_entity_property_info_alter(&$info) {
+
+  // For each Tripal Content Type, we want to ensure all attached fields
+  // are added to the bundle properties.
+  foreach ($info['TripalEntity']['bundles'] as $bundle_name => $bundle) {
+
+    // Retrieve information for all fields attached to this Tripal Content Type.
+    $fields = field_info_instances('TripalEntity', $bundle_name);
+    foreach ($fields as $field_name => $field_info) {
+
+      // If there is a field attached to the current Tripal Content Type that
+      // is not listed in properties, then add it. We use the full defaults here
+      // just in case it's not a TripalField or ChadoField.
+      if (!isset($info['TripalEntity']['bundles'][$bundle_name]['properties'][$field_name])) {
+        $info['TripalEntity']['bundles'][$bundle_name]['properties'][$field_name] = array(
+          'label' => $field_info['label'],
+          'type' => 'text',
+          'description' => $field_info['description'],
+          'getter callback' => 'entity_metadata_field_property_get',
+          'setter callback' => 'entity_metadata_field_property_set',
+          'access callback' => 'entity_metadata_field_access_callback',
+          'query callback' => 'entity_metadata_field_query',
+          'translatable' => FALSE,
+          'field' => TRUE,
+          'required' => $field_info['required'],
+        );
+      }
+
+      // Now, if it's a TripalField or a ChadoField, then we want to use a custom
+      // getter callback in order to ensure values are retrieved properly.
+      // ASSUMPTION: All TripalFields and ChadoFields have an ontology term
+      // defining them.
+      if (isset($field_info['settings']['term_accession'])) {
+        $info['TripalEntity']['bundles'][$bundle_name]['properties'][$field_name]['getter callback'] = 'tripal_field_property_get';
+      }
+    }
+  }
+}
+
+/**
+ * Callback for getting TripalField and ChadoField property values.
+ *
+ * This function retrieves the value from a field. Since the value has already
+ * been set by the Tripal/ChadoField class at this point, it should just be a
+ * matter of grabbing the value.
+ *
+ * @param $entity
+ *   The fully-loaded entity object to be indexed.
+ * @param $options
+ *   Options that can be ued when retrieving the value.
+ * @param $field_name
+ *   The machine name of the field we want to retrieve.
+ * @param $entity_type
+ *   The type of entity (ie: TripalEntity).
+ *
+ * @return
+ *   The rendered value of the field specified by $field_name.
+ */
+function tripal_field_property_get($entity, array $options, $field_name, $entity_type, $info) {
+
+  // Retrieve information for the field.
+  $field = field_info_field($field_name);
+
+  // Retrieve the language code.
+  $langcode = isset($options['language']) ? $options['language']->language : LANGUAGE_NONE;
+  $langcode = entity_metadata_field_get_language($entity_type, $entity, $field, $langcode, TRUE);
+
+  $values = array();
+  if (isset($entity->{$field_name}[$langcode])) {
+    // For each value of the field... (this will be multiple if cardinality is > 1).
+    foreach ($entity->{$field_name}[$langcode] as $delta => $data) {
+
+      // All Tripal/ChadoFields should have a value key. Only the information
+      // stored in this value key should be displayed on the page, available
+      // via web services or indexed for searching. This is there is no value
+      // key, we will not index anything.
+      if (!isset($data['value'])) {
+        return NULL;
+      }
+
+      // Sometimes TripalFields may return multiple pieces of information in the
+      // value field. In this case, the key should be an ontology term describing
+      // what each piece of data is and the value should be the data.
+      if (is_array($data['value'])) {
+
+        // Just include all the pieces of information seperated by spaces
+        // so they are tokenized out later on.
+        $tmp = $data['value'];
+        if (isset($tmp['entity'])) { unset($tmp['entity']); }
+        foreach ($tmp as $k => $v) { $tmp[$k] = strip_tags($v); }
+        $curr_val = implode(' ', $tmp);
+      }
+      else {
+
+        // Otherwise, assume the value is a single piece of information
+        // and add that directly to be indexed.
+        $curr_val = strip_tags($data['value']);
+
+        // Ensure that we have a clean boolean data type.
+        if ($info['type'] == 'boolean' || $info['type'] == 'list<boolean>') {
+          $curr_val = (boolean) $curr_val;
+        }
+      }
+      
+      // Only add the current value if it's not empty.
+      if (!empty(trim($curr_val))) {
+        $values[$delta] = $curr_val;
+      }
+    }
+  }
+
+  // For an empty single-valued field, we have to return NULL.
+  return $field['cardinality'] == 1 ? ($values ? reset($values) : NULL) : $values;
+}
+
 /**
  * Checks access permissions for a given entity.
  *

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

@@ -174,8 +174,10 @@ function tripal_jobs_report() {
     $start = tripal_get_job_start($job);
     $end = tripal_get_job_end($job);
     $cancel_link = '';
+    $execute_link = '';
     if ($job->start_time == 0 and $job->end_time == 0) {
       $cancel_link = "<a href=\"" . url("admin/tripal/tripal_jobs/cancel/" . $job->job_id) . "\">Cancel</a><br />";
+      $execute_link = "<a href=\"" . url("admin/tripal/tripal_jobs/execute/" . $job->job_id) . "\">Execute</a><br />";
     }
     $rerun_link = "<a href=\"" . url("admin/tripal/tripal_jobs/rerun/" . $job->job_id) . "\">Re-run</a><br />";
     $view_link ="<a href=\"" . url("admin/tripal/tripal_jobs/view/" . $job->job_id) . "\">View</a>";
@@ -187,7 +189,7 @@ function tripal_jobs_report() {
       $job->priority,
       $job->progress . '%',
       $job->job_status,
-      "$cancel_link $rerun_link $view_link",
+      "$execute_link $cancel_link $rerun_link $view_link",
     );
   }
 
@@ -289,6 +291,7 @@ function tripal_jobs_view($job_id) {
   $links .= l('Re-run this job', "admin/tripal/tripal_jobs/rerun/" . $job->job_id) . ' | ';
   if ($job->start_time == 0 and $job->end_time == 0) {
     $links .= l('Cancel this job', "admin/tripal/tripal_jobs/cancel/" . $job->job_id) . ' | ';
+    $links .= l('Execute this job', "admin/tripal/tripal_jobs/execute/".$job->job_id);
   }
 
   // make our start and end times more legible

+ 5 - 1
tripal/tripal.drush.inc

@@ -123,6 +123,7 @@ function drush_tripal_set_user($username) {
     $results = db_query($sql, array(':name' => $username));
     $u = $results->fetchObject();
     if (!$u) {
+      drush_print(date('Y-m-d H:i:s'));
       drush_print('ERROR: Please provide a valid username (--username argument) for running this job.');
       exit;
     }
@@ -131,6 +132,7 @@ function drush_tripal_set_user($username) {
     return $u->uid;
   }
   else {
+    drush_print(date('Y-m-d H:i:s'));
     drush_print('ERROR: Please provide a username (--username argument) for running this job.');
     exit;
   }
@@ -199,7 +201,7 @@ function drush_tripal_trp_rerun_job() {
   // --username argument for the fture.
   $user = drush_get_option('user');
   $uname = drush_get_option('username');
-  print "USER: '$user', UNAME: '$uname'\n";
+  print date('Y-m-d H:i:s') . ": USER: '$user', UNAME: '$uname'\n";
   if ($user and is_numeric($user)) {
   }
   elseif ($user) {
@@ -259,9 +261,11 @@ function drush_tripal_trp_get_currjob() {
         "Process ID: " . $job->pid . "\n" .
         "Progress: " . $job->progress . "%\n".
         "Current Date: " . date('Y-m-d H:i:s') . "\n";
+    drush_print(date('Y-m-d H:i:s'));
     drush_print($output);
   }
   if (!$job_pid) {
+    drush_print(date('Y-m-d H:i:s'));
     drush_print('There are currently no running jobs.');
   }
   //log to the command line with an OK status

+ 8 - 2
tripal/tripal.module

@@ -213,8 +213,14 @@ function tripal_menu() {
     'type' => MENU_CALLBACK,
     'file' => 'includes/tripal.jobs.inc',
   );
-
-
+  $items['admin/tripal/tripal_jobs/execute/%'] = array(
+    'title' => 'Jobs',
+    'description' => t('Execute an existing job'),
+    'page callback' => 'tripal_execute_job',
+    'page arguments' => array(4),
+    'access arguments' => array('administer tripal'),
+    'type' => MENU_CALLBACK,
+  );
 
   /*
    * AJAX Callbacks.

+ 1 - 1
tripal/tripal.views.inc

@@ -326,7 +326,7 @@ function tripal_views_data_jobs(&$data) {
   // Arguments
   $data['tripal_jobs']['arguments'] = array(
     'title' => t('Arguements'),
-    'help' => t('Any arguements passed to the callback.'),
+    'help' => t('Any arguments passed to the callback.'),
     'field' => array(
       'handler' => 'views_handler_field',
       'click sortable' => TRUE, // This is use by the table display plugin.

+ 10 - 2
tripal/tripal.views_default.inc

@@ -420,12 +420,20 @@ function tripal_admin_defaultview_jobs() {
   $handler->display->display_options['fields']['nothing_3']['alter']['make_link'] = TRUE;
   $handler->display->display_options['fields']['nothing_3']['alter']['path'] = 'admin/tripal/tripal_jobs/cancel/[job_id]';
   /* Field: Global: Custom text */
+  $handler->display->display_options['fields']['nothing_4']['id'] = 'nothing_4';
+  $handler->display->display_options['fields']['nothing_4']['table'] = 'views';
+  $handler->display->display_options['fields']['nothing_4']['field'] = 'nothing';
+  $handler->display->display_options['fields']['nothing_4']['label'] = 'Execute link';
+  $handler->display->display_options['fields']['nothing_4']['exclude'] = TRUE;
+  $handler->display->display_options['fields']['nothing_4']['alter']['text'] = 'Execute';
+  $handler->display->display_options['fields']['nothing_4']['alter']['make_link'] = TRUE;
+  $handler->display->display_options['fields']['nothing_4']['alter']['path'] = 'admin/tripal/tripal_jobs/execute/[job_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'] = 'Action';
-  $handler->display->display_options['fields']['nothing_1']['alter']['text'] = '[nothing_2]<br />
-  [nothing_3]';
+  $handler->display->display_options['fields']['nothing_1']['alter']['text'] = '[nothing_4]<br />[nothing_2]<br />[nothing_3]';
   $handler->display->display_options['fields']['nothing_1']['element_class'] = 'short-column';
   $handler->display->display_options['fields']['nothing_1']['element_label_class'] = 'short-column';
   /* Filter criterion: Tripal Jobs: Job Name */

+ 2 - 2
tripal/views_handlers/tripal_views_handler_filter_select_string.inc

@@ -88,7 +88,7 @@ class tripal_views_handler_filter_string_selectbox extends views_handler_filter_
 
     $return = $this->get_select_option_where();
     $where_clauses = $return['where_clauses'];
-    $arguements = $return['arguements'];
+    $arguments = $return['arguments'];
     $where = '';
     if (!empty($where_clauses)) {
       $where = ' WHERE ' . implode(' AND ', $where_clauses);
@@ -96,7 +96,7 @@ class tripal_views_handler_filter_string_selectbox extends views_handler_filter_
 
     // get the values from the table
     $sql = 'SELECT ' . $this->real_field . ' FROM {' . $this->table . '} ' . $where . ' ORDER BY ' . $this->field . ' ASC';
-    $results = db_query($sql, $arguements);
+    $results = db_query($sql, arguments);
 
     // Build the select box options
     $max_length = (isset($this->options['max_length'])) ? $this->options['max_length'] : 40;

+ 160 - 182
tripal_bulk_loader/includes/tripal_bulk_loader.admin.templates.inc

@@ -31,6 +31,11 @@ function tripal_bulk_loader_modify_template_base_form($form, &$form_state = NULL
   $breadcrumb[] = l('Templates', 'admin/tripal/loaders/bulk/templates');
   drupal_set_breadcrumb($breadcrumb);
 
+  // Add CSS
+  $form['#attached']['css'] = array(
+    drupal_get_path('module', 'tripal_bulk_loader') . '/theme/tripal_bulk_loader.css',
+  );
+
    // get template id from path and rebuild form
   if (isset($form_state['build_info']['args'][1])) {
     $mode = 'edit';
@@ -198,7 +203,10 @@ function tripal_bulk_loader_modify_template_base_form($form, &$form_state = NULL
   );
 
   $form['fields']['fields-data'] = array(
+    '#prefix' => '<div id="tripal-bulk-loader-template-fields">',
+    '#suffix' => '</div>',
     '#tree' => TRUE,
+    '#theme' => 'tripal_bulk_loader_modify_template_base_form_fields'
   );
 
   if (array_key_exists('template', $form_state['storage'])) {
@@ -373,7 +381,7 @@ function tripal_bulk_loader_modify_template_base_form($form, &$form_state = NULL
           $form['fields']['fields-data'][$i] = array(
             'record_id' => array(
               '#type' => 'item',
-              '#markup' =>  $table_array['record_id'],
+              '#markup' =>  $table_array['record_id'] . '<br /><em>(' . ucwords($mode_value) . ')</em>',
               '#prefix' => "<a name=\"fields_$priority\"></a>",
             ),
             'view-record-link' => array(
@@ -1629,6 +1637,9 @@ function tripal_bulk_loader_template_field_form_default_values($mode, &$form_sta
   if (!isset($table)) {
     $table = reset($tables);
   }
+  if (!isset($record_name) and isset($form_state['storage']['template_array'][$record_id])) {
+    $record_name = $form_state['storage']['template_array'][$record_id]['record_id'];
+  }
 
   // Chado fields
   $chado_fields = array();
@@ -1688,7 +1699,7 @@ function tripal_bulk_loader_template_field_form_default_values($mode, &$form_sta
   $v['chado_field'] = $field;
   $v['chado_field_options'] = $chado_fields;
 
-  $v['record_name'] = (isset($form_state['values']['record_name'])) ? $form_state['values']['record_name'] : '';
+  $v['record_name'] = (isset($record_name)) ? $record_name : '';
   if (isset($form_state['values']['field_title'])) {
     $v['field_title'] =  $form_state['values']['field_title'];
   }
@@ -1860,30 +1871,17 @@ function tripal_bulk_loader_template_field_form($form, &$form_state = NULL) {
     '#suffix' => '</div>',
   );
 
-  $form['fields']['basic'] = array(
-    '#type' => 'markup',
-    '#prefix' => '<div class="basic">',
-    '#suffix' => '</div>'
-  );
-
-  $form['fields']['basic']['field_type'] = array(
-    '#type' => 'radios',
-    '#title' => t('Type of Field'),
-    '#options' => array(
-      'table field' => t('Data: A Field which maps to a column in the supplied file.'),
-      'constant' => t('Constant: Field which remains Constant throughout the file'),
-      'foreign key' => t('Record Referral: Fields which map to a record in another table'),
-    ),
-    '#required' => TRUE,
-    '#default_value' => $values['field_type'],
-    '#ajax' => array(
-      'callback' => 'tripal_bulk_loader_template_fields_ahah',
-      'wrapper' => 'tripal_bulk_loader_template-template_fields',
-      'effect' => 'fade'
-    ),
+  $form['fields']['record'] = array(
+    '#type' => 'fieldset',
+    '#title' => 'Record'
   );
-
-  $form['fields']['basic']['field_group']  = array(
+  if (!empty($values['record_name'])) {
+    $form['fields']['record']['#title'] = 'Record: ' . $values['record_name'];
+    $form['fields']['record']['#collapsible'] = TRUE;
+    $form['fields']['record']['#collapsed'] = TRUE;
+  }
+  
+  $form['fields']['record']['field_group']  = array(
     '#type' => 'select',
     '#title' => 'Record',
     '#description' => t(
@@ -1899,16 +1897,53 @@ function tripal_bulk_loader_template_field_form($form, &$form_state = NULL) {
     '#required' => TRUE,
   );
 
-  $form['fields']['basic']['record_name'] = array(
-    '#type' => ($values['no_record_id']) ? 'textfield' : 'hidden',
+  $form['fields']['record']['record_name'] = array(
+    '#type' => 'textfield',
     '#title' => 'Unique Record Name',
     '#prefix' => '<div id="tripal_bulk_loader_template-add_record">',
     '#suffix' => '</div>',
     '#description' => 'A human-readable name for the record; it should be unique.',
+    '#disabled' => ($values['no_record_id']) ? FALSE : TRUE,
     '#default_value' => $values['record_name'],
   );
 
-  $form['fields']['basic']['field_title'] = array(
+  $form['fields']['record']['record_mode'] = array(
+    '#type' => 'radios',
+    '#title' => 'Record Type/Action',
+    '#options' => array(
+      'select' => 'SELECT: Don\'t insert this record: it\'s used to define a foreign key in another record',
+      'select_once' => 'SELECT ONCE: Select the record only once for each constant set.',
+      'insert' => 'INSERT: Insert the record',
+      'insert_once' => 'INSERT ONCE: Record will be inserted once for each constant set.',
+    ),
+    '#description' => 'This indicates the action to take when loading a record. There are many additional options available when editing a record such as "Select if Duplicate" which is very important on insert if the record might already exist.',
+    '#default_value' => 'insert',
+    '#disabled' => ($values['no_record_id']) ? FALSE : TRUE,
+  );
+  
+  $form['fields']['field'] = array(
+    '#type' => 'fieldset',
+    '#title' => 'Field',
+  );
+
+  $form['fields']['field']['field_type'] = array(
+    '#type' => 'radios',
+    '#title' => t('Type of Field'),
+    '#options' => array(
+      'table field' => t('Data: A Field which maps to a column in the supplied file.'),
+      'constant' => t('Constant: Field which remains Constant throughout the file'),
+      'foreign key' => t('Record Referral: Fields which map to a record in another table'),
+    ),
+    '#required' => TRUE,
+    '#default_value' => $values['field_type'],
+    '#ajax' => array(
+      'callback' => 'tripal_bulk_loader_template_fields_ahah',
+      'wrapper' => 'tripal_bulk_loader_template-template_fields',
+      'effect' => 'fade'
+    ),
+  );
+
+  $form['fields']['field']['field_title'] = array(
     '#type' => 'textfield',
     '#title' => t('Human-readable Title for Field'),
     '#default_value' => $values['field_title'],
@@ -1916,13 +1951,13 @@ function tripal_bulk_loader_template_field_form($form, &$form_state = NULL) {
 
 
   // Chado Field
-  $form['fields']['chado'] = array(
+  $form['fields']['field']['chado'] = array(
     '#type' => 'fieldset',
     '#title' => t('Chado Field/Column Details'),
     '#description' => t('Specify the Table/Field in chado that this field maps to.'),
   );
 
-  $form['fields']['chado']['chado_table'] = array(
+  $form['fields']['field']['chado']['chado_table'] = array(
     '#type' => 'select',
     '#title' => t('Chado Table'),
     '#options' => $values['chado_table_options'],
@@ -1934,7 +1969,7 @@ function tripal_bulk_loader_template_field_form($form, &$form_state = NULL) {
       ),
   );
 
-  $form['fields']['chado']['chado_field'] = array(
+  $form['fields']['field']['chado']['chado_field'] = array(
     '#type' => 'select',
     '#title' => t('Chado Field/Column'),
     '#options' => $values['chado_field_options'],
@@ -1947,14 +1982,14 @@ function tripal_bulk_loader_template_field_form($form, &$form_state = NULL) {
   );
 
   // loading file data column
-  $form['fields']['columns'] = array(
+  $form['fields']['field']['columns'] = array(
     '#type' => 'fieldset',
     '#title' => t('Data File Column'),
     '#collapsible' => TRUE,
     '#collapsed' => ($values['field_type'] == 'table field')? FALSE : TRUE,
   );
 
-  $form['fields']['columns']['column_number'] = array(
+  $form['fields']['field']['columns']['column_number'] = array(
     '#type' => 'textfield',
     '#title' => t('Column'),
     '#description' => t('Specify the column in the data that this field maps to where the first column is 1.'),
@@ -1962,14 +1997,14 @@ function tripal_bulk_loader_template_field_form($form, &$form_state = NULL) {
     '#default_value' => $values['column_number'],
   );
 
-  $form['fields']['columns']['column_exposed'] = array(
+  $form['fields']['field']['columns']['column_exposed'] = array(
     '#type' => 'checkbox',
     '#title' => t('Allow Column to be set for each Bulk Loading Job'),
     '#description' => t('Adds a textbox field to the Bulk Loader Page to allow users to set this value.'),
     '#default_value' => $values['column_exposed'],
   );
 
-  $form['fields']['columns']['column_exposed_desc'] = array(
+  $form['fields']['field']['columns']['column_exposed_desc'] = array(
     '#type' => 'textfield',
     '#title' => t('Description for exposed field on bulk loading job'),
     '#description' => t('This description should tell the user what column should be entered here.'),
@@ -1977,28 +2012,28 @@ function tripal_bulk_loader_template_field_form($form, &$form_state = NULL) {
   );
 
   // Global Value
-  $form['fields']['constant'] = array(
+  $form['fields']['field']['constant'] = array(
     '#type' => 'fieldset',
     '#title' => t('Constant'),
     '#collapsible' => TRUE,
     '#collapsed' => ($values['field_type'] == 'constant')? FALSE : TRUE,
   );
 
-  $form['fields']['constant']['constant_value'] = array(
+  $form['fields']['field']['constant']['constant_value'] = array(
     '#type' => 'textfield',
     '#title' => t('Constant Value'),
     '#description' => t('Specify the value you wish this field to have regardless of data file value.'),
     '#default_value' => $values['constant_value']
   );
 
-  $form['fields']['constant']['constant_exposed'] = array(
+  $form['fields']['field']['constant']['constant_exposed'] = array(
     '#type' => 'checkbox',
     '#title' => t('Allow Constant to be set for each Bulk Loading Job'),
     '#description' => t('Adds a textbox field to the Create Bulk Loader Form to allow users to set this value.'),
     '#default_value' => $values['constant_exposed'],
   );
 
-  $form['fields']['constant']['constant_validate'] = array(
+  $form['fields']['field']['constant']['constant_validate'] = array(
     '#type' => 'checkbox',
     '#title' => t('Ensure value is in table'),
     '#description' => t('Checks the database when a bulk loading job is created to ensure the value entered already exists in the database.'),
@@ -2006,14 +2041,14 @@ function tripal_bulk_loader_template_field_form($form, &$form_state = NULL) {
   );
 
   // Foreign Key / Referrer
-  $form['fields']['foreign_key'] = array(
+  $form['fields']['field']['foreign_key'] = array(
     '#type' => 'fieldset',
     '#title' => 'Record Referral',
     '#collapsible' => TRUE,
     '#collapsed' => ($values['field_type'] == 'foreign key')? FALSE : TRUE,
   );
 
-  $form['fields']['foreign_key']['show_all_records'] = array(
+  $form['fields']['field']['foreign_key']['show_all_records'] = array(
     '#type' => 'checkbox',
     '#title' => 'Refer to any record',
     '#description' => t('By default, the bulk loader will only allow referral to records in a foreign key relationship.  To allow referral to any previous record, check this box'),
@@ -2025,7 +2060,7 @@ function tripal_bulk_loader_template_field_form($form, &$form_state = NULL) {
     ),
   );
 
-  $form['fields']['foreign_key']['foreign_record'] = array(
+  $form['fields']['field']['foreign_key']['foreign_record'] = array(
     '#type' => 'select',
     '#title' => 'Record to refer to',
     '#descripion' => 'Select the record that this value should refer to. The record needs to already exist.',
@@ -2038,7 +2073,7 @@ function tripal_bulk_loader_template_field_form($form, &$form_state = NULL) {
     '#default_value' => $values['foreign_record'],
   );
 
-  $form['fields']['foreign_key']['foreign_field'] = array(
+  $form['fields']['field']['foreign_key']['foreign_field'] = array(
     '#type' => 'select',
     '#title' => 'Field to refer to',
     '#descripion' => 'Select the record that this value should refer to. The record needs to already exist.',
@@ -2048,88 +2083,90 @@ function tripal_bulk_loader_template_field_form($form, &$form_state = NULL) {
 
 
   $collapsed = TRUE;
-  if ($values['required'] OR $values['regex_are_set']) {
+  if ($values['required'] OR !empty($values['regex-pattern'])) {
     $collapsed = FALSE;
   }
-  $form['fields']['additional'] = array(
+  $form['fields']['field']['additional'] = array(
     '#type' => 'fieldset',
     '#title' => 'Additional Options',
     '#collapsible' => TRUE,
     '#collapsed' => $collapsed
   );
 
-  $form['fields']['additional']['required'] = array(
+  $form['fields']['field']['additional']['required'] = array(
     '#type' => 'checkbox',
     '#title' => 'Make this field required',
     '#default_value' => $values['required'],
   );
 
-  $form['fields']['additional']['regex_transform'] = array(
+  $form['fields']['field']['additional']['regex_transform'] = array(
     '#type' => 'fieldset',
     '#title' => 'Transform Data File Value Rules',
     '#collapsible' => TRUE,
-    '#collapsed' => !$values['regex_are_set'],
+    '#collapsed' => (!empty($values['regex-pattern'])) ? FALSE : TRUE,
   );
 
-  $form['fields']['additional']['regex_transform']['regex_description'] = array(
+  $form['fields']['field']['additional']['regex_transform']['regex_description'] = array(
     '#type' => 'item',
     '#markup' => 'A transformation rule allows you to transform the original value '
       .'(usually from a user submitted data file) into the form you would like it stored '
-      .'in the chado database. Each rule consists of a match pattern (a php regular expression '
-      .'which determines which replacement patterns are applied and captures regions of the '
-      .'original value) and a replacement pattern (a string which may contain capture references '
-      .'that describes what the new value should be). Each rule is applied to the result of the '
-      .'previous rule.'
-  );
-
-  $form['fields']['additional']['regex_transform']['regex-data'] = array(
-    '#tree' => TRUE,
-    '#theme' => 'tripal_bulk_loader_field_regex_fieldset'
-  );
-  foreach ($values['regex-pattern'] as $index => $pattern) {
-    $data_element = array(
-      'pattern' => array(
-        '#type' => 'item',
-        '#markup' => check_plain($pattern),
-      ),
-      'replace' => array(
-        '#type' => 'item',
-        '#markup' => check_plain($values['regex-replace'][$index]),
-      ),
-      'old_index' => array(
-        '#type' => 'hidden',
-        '#value' => $index,
-      ),
-      'new_index' => array(
-        '#type' => 'select',
-        '#options' => range(0, sizeof($values['regex-pattern'])-1),
-        '#default_value' => $index,
-        '#attributes' => array('class' => array('rank-weight')), // needed for table dragging
-      ),
-      'id' => array(
-        '#type' => 'hidden',
-        '#value' => $index,
-      ),
-      'submit-delete' => array(
-        '#type' => 'submit',
-        '#value' => 'Delete Transformation',
-        '#name' => $index,
-      ),
+      .'in the chado database. A rule consists of a match pattern (a php regular expression '
+      .'which captures regions of the original value) and a replacement pattern (a string which may contain capture references '
+      .'that describes what the new value should be).'
+  );
+  
+  $pattern_default = '';
+  $replace_default = '';
+  
+  // Check to see if there is more than one regex and if so warn them that 
+  // this feature is no longer supported. We don't want people to lose existing
+  // transformation rules just by tweaking the field so we will only set defaults
+  // if there is a single rule and summarize multiple rules statically.
+  if (sizeof($values['regex-pattern']) > 1) {
+    $msg = 'This field uses more than one transformation rule. The current rules are:';
+    
+    $table_vars['header'] = array('Match Pattern', 'Replacement Pattern');
+    $table_vars['rows'] = array();
+    foreach ($values['regex-pattern'] as $index => $pattern) {
+      $table_vars['rows'][] = array(
+        check_plain($pattern),
+        check_plain($values['regex-replace'][$index]),
+      );
+    }
+    $msg .= theme('table', $table_vars);
+    
+    $msg .= 'Unfortunatly adding multiple transformation rules is no longer supported '
+      . 'through the user interface. As long as you don\'t '
+      . 'enter new match/replacement patterns below, your current transformation rules will '
+      . 'be preserved and will be used during loading. However, if any changes need to be '
+      . 'made you will have to switch over to a single transformation rule by entering it below.';
+    
+    $form['fields']['additional']['regex_transform']['warning'] = array(
+      '#type' => 'markup',
+      '#markup' => '<div class="messages warning">' . $msg . '</div>',
+    );
+    
+    // Also save the rules to ensure they are kept.
+    $form['fields']['field']['additional']['regex_transform']['old_rules'] = array(
+      '#type' => 'hidden',
+      '#value' => array(
+        'pattern' => $values['regex-pattern'],
+        'replace' => $values['regex-replace']
+      )
     );
-    $form['fields']['additional']['regex_transform']['regex-data'][$index] = $data_element;
+    $form['fields']['field']['additional']['regex_transform']['old_rules']['#value'] = serialize($form['fields']['additional']['regex_transform']['old_rules']['#value']);
   }
+  else {
+  
+    // Get current pattern/replacement rule to use as defaults.
+    foreach ($values['regex-pattern'] as $index => $pattern) {
+      $pattern_default = $pattern;
+      $replace_default = $values['regex-replace'][$index];
+    }
 
-  $form['fields']['additional']['regex_transform']['submit-reorder_regex'] = array(
-    '#type' => ($values['regex_are_set']) ? 'submit' : 'hidden',
-    '#value' => 'Save Transformation Rule Order'
-  );
-
-  $form['fields']['additional']['regex_transform']['new_regex'] = array(
-    '#type' => 'fieldset',
-    '#title' => 'Add a new Transformation Rule',
-  );
-
-  $form['fields']['additional']['regex_transform']['new_regex']['pattern'] = array(
+  }
+  
+  $form['fields']['field']['additional']['regex_transform']['regex_pattern'] = array(
     '#type' => 'textfield',
     '#title' => 'Match Pattern',
     '#description' => 'You can use standard php regular expressions in this field to specify a '
@@ -2138,20 +2175,22 @@ function tripal_bulk_loader_template_field_form($form, &$form_state = NULL) {
       .'replacement patten surround with round brackets. For example, <i>GI:(\d+)</i> will match '
       .' NCBI gi numbers and will capture the numerical digits for use in the replacement pattern. '
       .' To match and capture any value use <i>.*</i>',
+    '#default_value' => $pattern_default,
   );
 
-  $form['fields']['additional']['regex_transform']['new_regex']['replace'] = array(
+  $form['fields']['field']['additional']['regex_transform']['regex_replace'] = array(
     '#type' => 'textfield',
     '#title' => 'Replacement Pattern',
     '#description' => 'This pattern should contain the text you want to replace the match pattern '
-    .'mentioned above. It can include references of the form \n where n is the number of the '
-    .'capture in the match pattern. For example, \1 will be replaced with the text matched in your '
-    .'first set of round brackets.',
+      .'mentioned above. It can include references of the form \n where n is the number of the '
+      .'capture in the match pattern. For example, \1 will be replaced with the text matched in your '
+      .'first set of round brackets.',
+    '#default_value' => $replace_default,
   );
 
   if ($values['field_type'] == 'table field') {
     $tab = '&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp';
-    $form['fields']['additional']['regex_transform']['new_regex']['replace']['#description'] .= '<p>'
+    $form['fields']['field']['additional']['regex_transform']['regex_replace']['#description'] .= '<p>'
       .'The following references are also available for data file fields: <b><#column:<i>number</i>#></b>. '
       .'This allows you to substitute other data file values into the current field. For example, '
       .'if you had the following line:<br />'
@@ -2162,37 +2201,6 @@ function tripal_bulk_loader_template_field_form($form, &$form_state = NULL) {
       .'Pattern could be \1_<#column:2#> which would insert SNP_15-Jan-2011 into the database.</p>';
   }
 
-  $form['fields']['additional']['regex_transform']['new_regex']['submit-add_transform'] = array(
-    '#type' => 'submit',
-    '#value' => 'Add Transformation',
-  );
-
-  $form['fields']['additional']['regex_transform']['test_regex'] = array(
-    '#type' => 'fieldset',
-    '#title' => 'Test Transformation Rules',
-  );
-
-  $form['fields']['additional']['regex_transform']['test_regex']['test_string'] = array(
-    '#type' => 'textfield',
-    '#title' => 'Test Value',
-    '#description' => 'This should be a value that you expect the above transformation rules '
-      .'to be applied to.',
-    '#default_value' => $values['regex-test-string'],
-  );
-
-  $form['fields']['additional']['regex_transform']['test_regex']['test_result'] = array(
-    '#type' => 'textfield',
-    '#title' => 'Test Result',
-    '#description' => 'This is the value that would be saved to the database after the above transformation '
-      .'riles were applied to the Test Value.',
-    '#default_value' => $values['regex-test-result'],
-  );
-
-  $form['fields']['additional']['regex_transform']['test_regex']['submit-test'] = array(
-    '#type' => 'submit',
-    '#value' => 'Test Transformation Rules'
-  );
-
   $form['submit-save'] = array(
       '#type' => 'submit',
       '#value' => 'Save Changes'
@@ -2252,7 +2260,7 @@ function tripal_bulk_loader_template_field_form_submit($form, &$form_state) {
       $record2priority[$record_name] = $priority;
       $template[$priority]['table'] = $form_state['values']['chado_table'];
       $template[$priority]['record_id'] = $record_name;
-
+      $template[$priority]['mode'] = $form_state['values']['record_mode'];
     }
     else {
       $priority = $form_state['storage']['record_id'];
@@ -2295,24 +2303,35 @@ function tripal_bulk_loader_template_field_form_submit($form, &$form_state) {
       );
     }
 
+    // Save old transformation rules if they exist.
+    if (isset($form_state['values']['old_rules'])) {
+      $field['regex'] = unserialize($form_state['values']['old_rules']);
+    }
     // Deal with any additional options
-    if (isset($form_state['storage']['regex'])) {
-      $field['regex'] = $form_state['storage']['regex'];
+    if (!empty($form_state['values']['regex_pattern']) AND !empty($form_state['values']['regex_replace'])) {
+      if (!preg_match('/^\/.*\/$/', $form_state['values']['regex_pattern'])) {
+        $form_state['values']['regex_pattern'] = '/' . $form_state['values']['regex_pattern'] . '/';
+      }
+      $field['regex']['pattern'] = array($form_state['values']['regex_pattern']);
+      $field['regex']['replace'] = array($form_state['values']['regex_replace']);
     }
+    
 
     // Save Template
     if ($form_state['storage']['mode'] == 'create') {
       $template[$priority]['fields'][] = $field;
+      $success_msg = 'Successfully Added Field to Template';
     }
     else {
       $template[$priority]['fields'][$form_state['storage']['field_index']] = $field;
+      $success_msg = 'Successfully Updated Field';
     }
     $form_state['storage']['template']->template_array = serialize($template);
     $form_state['storage']['template']->changed = time();
     $success = drupal_write_record('tripal_bulk_loader_template', $form_state['storage']['template'], array('template_id'));
 
     if ($success) {
-      drupal_set_message(t('Successfully Added Field to Template'));
+      drupal_set_message(t($success_msg));
       drupal_set_message(t('Template Saved.'));
 
       $form_state['rebuild'] = FALSE;
@@ -2331,47 +2350,6 @@ function tripal_bulk_loader_template_field_form_submit($form, &$form_state) {
       $form_state['rebuild'] = FALSE;
       $form_state['redirect'] = 'admin/tripal/loaders/bulk/template/'.$form_state['storage']['template_id'].'/edit';
   }
-  elseif ($op == 'Add Transformation') {
-
-    // Add transformation rule to original field
-    $form_state['storage']['regex']['pattern'][] = '/' . $form_state['values']['pattern'] . '/';
-    $form_state['storage']['regex']['replace'][] = $form_state['values']['replace'];
-    $form_state['rebuild'] = TRUE;
-    drupal_set_message(t('Successfully Added Transformation Rule'));
-
-  }
-  elseif ($op == 'Save Transformation Rule Order') {
-
-    // Generate new regex array
-    $new_regex = array();
-    $old_regex = $form_state['storage']['regex'];
-    foreach ($form_state['values']['regex-data'] as $key => $element) {
-      $new_regex['pattern'][ $element['new_index'] ] = $old_regex['pattern'][ $element['old_index'] ];
-      $new_regex['replace'][ $element['new_index'] ] = $old_regex['replace'][ $element['old_index'] ];
-    }
-
-    // sort new regex arrays
-    ksort($new_regex['pattern']);
-    ksort($new_regex['replace']);
-
-    $form_state['storage']['regex'] = $new_regex;
-  }
-  elseif ($op == 'Delete Transformation') {
-
-    // Unset regex rule
-    $index = $form_state['clicked_button']['#name'];
-    unset($form_state['storage']['regex']['pattern'][$index]);
-    unset($form_state['storage']['regex']['replace'][$index]);
-
-  }
-  elseif ($op == 'Test Transformation Rules') {
-
-    $patterns = $form_state['storage']['regex']['pattern'];
-    $replaces = $form_state['storage']['regex']['replace'];
-    $test_string = $form_state['values']['test_string'];
-    $form_state['storage']['test_regex_result'] = preg_replace($patterns, $replaces, $test_string);
-    $form_state['storage']['test_regex_test'] = $test_string;
-  }
 
 }
 

+ 0 - 116
tripal_bulk_loader/theme/templates/tripal_bulk_loader_modify_template_base_form.tpl.php

@@ -1,116 +0,0 @@
-
-<style>
-tr.odd .form-item, tr.even .form-item {
-  white-space: normal;
-  word-wrap: break-word;
-}
-fieldset {
-  padding: 20px;
-}
-td.active{
-  width: 10px;
-}
-td.tbl-action-record-links {
-  width: 150px;
-}
-td.tbl-action-field-links {
-  width: 100px;
-}
-</style>
-
-<div id="tripal-bulk-loader-fields"><?php 
-print drupal_render($form['template_name']); ?>
-
-<!-- For each table display details in a draggable table --><?php 
-if (!$form['records']['no_records']['#value']) { ?>
-  <fieldset><legend><?php print $form['records']['#title']; ?></legend> <?php
-    print drupal_render($form['records']['description']);
-
-    // generate table
-    drupal_add_tabledrag('records-table', 'order', 'sibling', 'records-reorder');
-    $header = array(' ', ' ', 'Record Name', 'Chado Table', 'Mode', 'Order',);
-    $rows = array();
-    foreach (element_children($form['records']['records-data']) as $key) {
-      $element = &$form['records']['records-data'][$key];
-      $element['new_priority']['#attributes']['class'] = array('records-reorder');
-
-      $row = array();
-      $row[] = '';
-      $row[] = array(
-        'class' => array('tbl-action-record-links'),
-        'data' => drupal_render($element['submit-edit_record']) . ' | '
-          . drupal_render($element['submit-delete_record']) . ' | '
-          . drupal_render($element['submit-duplicate_record']) . '<br>'
-          . drupal_render($element['view-fields-link']) . ' | '
-          . drupal_render($element['submit-add_field'])
-        );
-      $row[] = drupal_render($element['title']);
-      $row[] = drupal_render($element['chado_table']);
-      $row[] = drupal_render($element['mode']);
-      $row[] = drupal_render($element['new_priority'])
-        . drupal_render($element['id']);
-
-      $rows[] = array('data' => $row, 'class' => array('draggable'));
-    }
-
-    print theme(
-      'table',
-      array(
-        'header' => $header,
-        'rows' => $rows,
-        'attributes' => array('id' => 'records-table')
-      )
-    );
-
-    // Render submit
-    print drupal_render($form['records']['submit-new_record']);
-    print drupal_render($form['records']['submit-reorder']);
-    unset($form['records']); ?>
-  </fieldset> <?php 
-} ?>
-
-<!-- For each field display details plus edit/delete buttons--> <?php 
-if (array_key_exists('total_fields', $form['fields']) and
-    $form['fields']['total_fields']['#value'] > 0) { ?>
-  <fieldset><legend><?php print $form['fields']['#title']; ?></legend> <?php
-    // generate table
-    $header = array('','Record Name', 'Field Name', 'Chado Table', 'Chado Field', 'Data File Column', 'Constant Value', 'Foreign Record');
-    $rows = array();
-    foreach ($form['fields']['fields-data'] as $key => $element) {
-      if (preg_match('/^#/', $key)) { continue; }
-
-      $row = array();
-      $row[] = array(
-        'class' => array('tbl-action-field-links', 'active'),
-        'data' => drupal_render($element['edit_submit']) . ' | '
-          . drupal_render($element['delete_submit']) . '<br />'
-          . drupal_render($element['view-record-link'])
-        );
-      $row[] = drupal_render($element['record_id']);
-      $row[] = drupal_render($element['field_name']);
-      $row[] = drupal_render($element['chado_table_name']);
-      $row[] = drupal_render($element['chado_field_name']);
-      $row[] = drupal_render($element['column_num']);
-      $row[] = drupal_render($element['constant_value']);
-      $row[] = drupal_render($element['foreign_record_id']);
-
-      $rows[] = $row;
-    }
-    print theme(
-      'table',
-      array(
-        'header' => $header,
-        'rows' => $rows,
-        //'attributes' => array('style'=>'table-layout: fixed; width: 100%')
-      )
-    );
-
-    // Render other elements
-    print drupal_render($form['fields']['add_field']);
-    unset($form['fields']); ?>
-  </fieldset> <?php 
-} ?>
-
-<!-- Display Rest of form --><?php 
-print drupal_render_children($form); ?>
-</div>

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 54 - 0
tripal_bulk_loader/theme/templates/tripal_bulk_loader_modify_template_base_form_fields.tpl.php


+ 55 - 0
tripal_bulk_loader/theme/templates/tripal_bulk_loader_modify_template_base_form_records.tpl.php

@@ -0,0 +1,55 @@
+<?php
+/**
+ * @file
+ * Defines how the records table in the Bulk Loader Template Edit form should be rendered.
+ *
+ * @param $element
+ *   The FAPI definition of the records table.
+ */
+
+// Define the header & tell drupal this table should implement table drag for row re-ordering.
+drupal_add_tabledrag('records-table', 'order', 'sibling', 'records-reorder');
+$header = array(' ', ' ', 'Record Name', 'Chado Table', 'Mode', 'Order',);
+$rows = array();
+
+// Create a row for each sub-element that is not a form-api key (ie: #title).
+foreach (element_children($element) as $key) {
+
+  $row_element = &$element[$key];
+  $row_element['new_priority']['#attributes']['class'] = array('records-reorder');
+  $row = array();
+  
+  // Add an empty cell for the tabledrag icon.
+  $row[] = array('class' => array('tbl-drag', 'active'), 'data' => '');
+  
+  // Add our action links.
+  $row[] = array(
+    'class' => array('tbl-action-record-links', 'active'),
+    'data' => drupal_render($row_element['submit-edit_record']) . ' | '
+      . drupal_render($row_element['submit-delete_record']) . ' | '
+      . drupal_render($row_element['submit-duplicate_record']) . '<br>'
+      . drupal_render($row_element['view-fields-link']) . ' | '
+      . drupal_render($row_element['submit-add_field'])
+    );
+  
+  // Add the record information.
+  $row[] = drupal_render($row_element['title']);
+  $row[] = drupal_render($row_element['chado_table']);
+  $row[] = drupal_render($row_element['mode']);
+  $row[] = drupal_render($row_element['new_priority'])
+    . drupal_render($row_element['id']);
+
+  // Finally add the current row to the table.
+  $rows[] = array('data' => $row, 'class' => array('draggable'));
+}
+
+// Finally print the generated table.
+print theme(
+  'table',
+  array(
+    'header' => $header,
+    'rows' => $rows,
+    'attributes' => array('id' => 'records-table')
+  )
+);
+?>

+ 42 - 0
tripal_bulk_loader/theme/tripal_bulk_loader.css

@@ -16,4 +16,46 @@
   border-color: #ed5;
   background-color: #DDDAC0;
   color: #840;
+}
+
+/**
+ * Tripal Bulk Loader Edit Template Form.
+ */
+#tripal-bulk-loader-modify-template-base-form table {
+  width: 100%;
+}
+#tripal-bulk-loader-modify-template-base-form tr.odd .form-item, tr.even .form-item {
+  white-space: normal;
+  word-wrap: break-word;
+}
+#tripal-bulk-loader-modify-template-base-form .fieldset-description {
+  padding-top: 20px;
+}
+#tripal-bulk-loader-modify-template-base-form td.tbl-drag{
+  width: 20px;
+}
+#tripal-bulk-loader-modify-template-base-form td.tbl-action-record-links {
+  width: 150px;
+}
+#tripal-bulk-loader-modify-template-base-form td.tbl-action-field-links {
+  width: 100px;
+}
+#tripal-bulk-loader-modify-template-base-form td.data-column {
+  text-align: center;
+  width: 50px;
+}
+#tripal-bulk-loader-modify-template-base-form td.field-type {
+  text-align: center;
+  width: 50px;
+}
+#tripal-bulk-loader-modify-template-base-form td.record {
+  width: 100px;
+  background-color: #F2F3ED;
+  border-right: 1px solid #bebfb9;
+}
+#tripal-bulk-loader-modify-template-base-form td.record em {
+  color: #bebfb9;
+}
+#tripal-bulk-loader-modify-template-base-form tr.record-first-row td {
+  border-top: 1px solid #bebfb9;
 }

+ 9 - 4
tripal_bulk_loader/tripal_bulk_loader.module

@@ -306,10 +306,15 @@ function tripal_bulk_loader_theme($existing, $type, $theme, $path) {
     ),
 
     // form element themes
-    'tripal_bulk_loader_modify_template_base_form' => array(
-      'template' => 'tripal_bulk_loader_modify_template_base_form',
+    'tripal_bulk_loader_modify_template_base_form_records' => array(
+      'template' => 'tripal_bulk_loader_modify_template_base_form_records',
       'path' => "$path/theme/templates",
-      'render element' => 'form'
+      'render element' => 'element'
+    ),
+    'tripal_bulk_loader_modify_template_base_form_fields' => array(
+      'template' => 'tripal_bulk_loader_modify_template_base_form_fields',
+      'path' => "$path/theme/templates",
+      'render element' => 'element'
     ),
     'tripal_bulk_loader_field_regex_fieldset' => array(
       'file' => 'theme/tripal_bulk_loader.theme.inc',
@@ -455,7 +460,7 @@ function tripal_bulk_loader_progess_file_get_progress($job_id, $update_progress
  * @params $callback
  *   The callback passed into tripal_add_job()
  * @param $args
- *   The arguements passed into tripal_add_job()
+ *   The arguments passed into tripal_add_job()
  * @return
  *   An array where keys are the human readable headers describing each arguement
  *   and the value is the aguement passed in after formatting

+ 55 - 69
tripal_chado/api/modules/tripal_chado.cv.api.inc

@@ -879,10 +879,6 @@ function tripal_insert_cv($name, $definition) {
  *   An associative array with the following keys:
  *    - update_existing: By default this is TRUE.  If the term exists it is
  *      automatically updated.
- *    - force_db_change:  Sometimes a term may need to switch from one
- *      database to another.  If the term already exists, but associated
- *      with another term the insert (or update, rather) will fail.  Set
- *      this variable to TRUE to force the change to occur.
  *
  * @return
  *   A cvterm object
@@ -923,7 +919,7 @@ function tripal_insert_cvterm($term, $options = array()) {
     $dbname = $term['db_name'];
   }
   else {
-    $dbname = 'local';
+    $dbname = 'internal';
   }
 
   if (isset($options['update_existing'])) {
@@ -954,7 +950,7 @@ function tripal_insert_cvterm($term, $options = array()) {
     }
   }
   if (!$name and !$id) {
-    tripal_report_error('tripal_chado', TRIPAL_WARNING, "Cannot find cvterm without 'id' or 'name'", NULL);
+    tripal_report_error('tripal_cv', TRIPAL_WARNING, "Cannot find cvterm without 'id' or 'name'", NULL);
     return 0;
   }
   if (!$id) {
@@ -974,13 +970,11 @@ function tripal_insert_cvterm($term, $options = array()) {
   // Check that we have a database name, give a different message if it's a
   // relationship.
   if ($is_relationship and !$dbname) {
-    tripal_report_error('tripal_chado', TRIPAL_WARNING,
-      "A database name is not provided for this relationship term: $id", NULL);
+    tripal_report_error('tripal_cv', TRIPAL_WARNING, "A database name is not provided for this relationship term: $id", NULL);
     return 0;
   }
   if (!$is_relationship and !$dbname) {
-    tripal_report_error('tripal_chado', TRIPAL_WARNING,
-      "A database identifier is missing from the term: $id", NULL);
+    tripal_report_error('tripal_cv', TRIPAL_WARNING, "A database identifier is missing from the term: $id", NULL);
     return 0;
   }
 
@@ -990,8 +984,7 @@ function tripal_insert_cvterm($term, $options = array()) {
     $cv = tripal_insert_cv($cvname, '');
   }
   if (!$cv) {
-    tripal_report_error('tripal_chado', TRIPAL_WARNING,
-      "Cannot find namespace '$cvname' when adding/updating $id", NULL);
+    tripal_report_error('tripal_cv', TRIPAL_WARNING, "Cannot find namespace '$cvname' when adding/updating $id", NULL);
     return 0;
   }
 
@@ -1016,7 +1009,7 @@ function tripal_insert_cvterm($term, $options = array()) {
     $db = tripal_insert_db(array('name' => $dbname));
   }
   if (!$db) {
-    tripal_report_error('tripal_chado', TRIPAL_WARNING, "Cannot find database '$dbname' in Chado.", NULL);
+    tripal_report_error('tripal_cv', TRIPAL_WARNING, "Cannot find database '$dbname' in Chado.", NULL);
     return 0;
   }
 
@@ -1039,8 +1032,8 @@ function tripal_insert_cvterm($term, $options = array()) {
     $dbxref = $result[0];
     if (!$dbxref) {
       tripal_report_error('tripal_cv', TRIPAL_ERROR,
-        'Unable to access the dbxref record for the :term cvterm. Term Record: !record',
-        array(':term' => $name, '!record' => print_r($cvterm, TRUE))
+          'Unable to access the dbxref record for the :term cvterm. Term Record: !record',
+          array(':term' => $name, '!record' => print_r($cvterm, TRUE))
       );
       return FALSE;
     }
@@ -1050,47 +1043,40 @@ function tripal_insert_cvterm($term, $options = array()) {
     $result = chado_select_record('db', array('*'), $values);
     $db_check = $result[0];
 
-    // If the database from the existing record doesn't match the one that
-    // has been provided then we have a problem.  The term already exists
-    // but we don't want to just switch the term, the callee must force it.
-    if ($db_check->name != $db->name) {
-      if (array_key_exists('force_db_change', $options) and
-          $options['force_db_change'] != TRUE) {
-        tripal_report_error('tripal_cv', TRIPAL_ERROR,
-            'The term already exists, but associated with a different database record: \'!db\'. It cannot be added: !record',
-            array(':term' => $name, '!db' => $db_check->name, '!record' => print_r($cvterm, TRUE))
-        );
-        return FALSE;
-      }
-
-      // Look to see if the correct dbxref record already exists for this
-      // database.
-      $values = array(
-        'db_id' => $db->db_id,
-        'accession' => $accession,
-      );
-      $result = chado_select_record('dbxref', array('*'), $values);
-
-      // If we already have a good dbxref then we want to update our cvterm
-      // to use this dbxref.
-      if (count($result) > 0) {
-        $dbxref = $result[0];
-        $match = array('cvterm_id' => $cvterm->cvterm_id);
-        $values = array('dbxref_id' => $dbxref->dbxref_id);
-        $success = chado_update_record('cvterm', $match, $values);
-        if (!$success) {
-          tripal_report_error('tripal_chado', TRIPAL_WARNING, "Failed to correct the dbxref id for the cvterm " .
-            "'$name' (id: $accession), for database $dbname", NULL);
-          return 0;
-        }
-      }
-      // If we don't have the dbxref then we want to delete our cvterm and let
-      // the code below recreate it with the correct info.
-      else {
-        $match = array('cvterm_id' => $cvterm->cvterm_id);
-        chado_delete_record('cvterm', $match);
-      }
-    }
+    //     // The database name for this existing term does not match that of the
+    //     // one provided to this function.  The CV name matches otherwise we
+    //     // wouldn't have made it this far. So, let's swap the database for
+    //     // this term.
+    //     if ($db_check->name != $db->name) {
+
+    //       // Look to see if the correct dbxref record already exists for this
+    //       // database.
+    //       $values = array(
+    //         'db_id' => $db->db_id,
+    //         'accession' => $accession,
+    //       );
+    //       $result = chado_select_record('dbxref', array('*'), $values);
+
+    //       // If we already have a good dbxref then we want to update our cvterm
+    //       // to use this dbxref.
+    //       if (count($result) > 0) {
+    //         $dbxref = $result[0];
+    //         $match = array('cvterm_id' => $cvterm->cvterm_id);
+    //         $values = array('dbxref_id' => $dbxref->dbxref_id);
+    //         $success = chado_update_record('cvterm', $match, $values);
+    //         if (!$success) {
+    //           tripal_report_error('tripal_cv', TRIPAL_WARNING, "Failed to correct the dbxref id for the cvterm " .
+    //             "'$name' (id: $accession), for database $dbname", NULL);
+    //           return 0;
+    //         }
+    //       }
+    //       // If we don't have the dbxref then we want to delete our cvterm and let
+    //       // the code below recreate it with the correct info.
+    //       else {
+    //         $match = array('cvterm_id' => $cvterm->cvterm_id);
+    //         chado_delete_record('cvterm', $match);
+    //       }
+    //     }
 
     // Check that the accession matches.  Sometimes an OBO can define a term
     // multiple times but with different accessions.  If this is the case we
@@ -1104,8 +1090,8 @@ function tripal_insert_cvterm($term, $options = array()) {
         'accession' => $accession
       ));
       if (!$dbxref_new) {
-        tripal_report_error('tripal_chado', TRIPAL_WARNING, "Failed to find or insert the dbxref record for cvterm, " .
-          "$name (id: $accession), for database $dbname", NULL);
+        tripal_report_error('tripal_cv', TRIPAL_WARNING, "Failed to find or insert the dbxref record for cvterm, " .
+            "$name (id: $accession), for database $dbname", NULL);
         return 0;
       }
 
@@ -1124,8 +1110,8 @@ function tripal_insert_cvterm($term, $options = array()) {
         );
         $success = chado_insert_record('cvterm_dbxref', $values, $options);
         if (!$success) {
-          tripal_report_error('tripal_chado', TRIPAL_WARNING, "Failed to find or insert the cvterm_dbxref record for a " .
-            "duplicated cvterm:  $name (id: $accession), for database $dbname", NULL);
+          tripal_report_error('tripal_cv', TRIPAL_WARNING, "Failed to find or insert the cvterm_dbxref record for a " .
+              "duplicated cvterm:  $name (id: $accession), for database $dbname", NULL);
           return 0;
         }
       }
@@ -1134,7 +1120,6 @@ function tripal_insert_cvterm($term, $options = array()) {
       $cvterm = $result->fetchObject();
       return $cvterm;
     }
-
     // Continue on, we've fixed the record if the db_id did not match.
     // We can now perform and updated if we need to.
   }
@@ -1150,8 +1135,8 @@ function tripal_insert_cvterm($term, $options = array()) {
       'accession' => $accession
     ));
     if (!$dbxref) {
-      tripal_report_error('tripal_chado', TRIPAL_WARNING, "Failed to find or insert the dbxref record for cvterm, " .
-        "$name (id: $accession), for database $dbname", NULL);
+      tripal_report_error('tripal_cv', TRIPAL_WARNING, "Failed to find or insert the dbxref record for cvterm, " .
+          "$name (id: $accession), for database $dbname", NULL);
       return 0;
     }
 
@@ -1171,18 +1156,18 @@ function tripal_insert_cvterm($term, $options = array()) {
       $success = chado_insert_record('cvterm', $ins_values);
       if (!$success) {
         if (!$is_relationship) {
-          tripal_report_error('tripal_chado', TRIPAL_WARNING, "Failed to insert the term: $name ($dbname)", NULL);
+          tripal_report_error('tripal_cv', TRIPAL_WARNING, "Failed to insert the term: $name ($dbname)", NULL);
           return 0;
         }
         else {
-          tripal_report_error('tripal_chado', TRIPAL_WARNING, "Failed to insert the relationship term: $name (cv: " . $cvname . " db: $dbname)", NULL);
+          tripal_report_error('tripal_cv', TRIPAL_WARNING, "Failed to insert the relationship term: $name (cv: " . $cvname . " db: $dbname)", NULL);
           return 0;
         }
       }
     }
     // This dbxref already exists in the cvterm table.
     else {
-      tripal_report_error('tripal_chado', TRIPAL_WARNING, "The dbxref already exists for another cvterm record: $name (cv: " . $cvname . " db: $dbname)", NULL);
+      tripal_report_error('tripal_cv', TRIPAL_WARNING, "The dbxref already exists for another cvterm record: $name (cv: " . $cvname . " db: $dbname)", NULL);
       return 0;
     }
     $result = chado_query($cvtermsql, array(':accession' => $accession, ':name' => $dbname));
@@ -1201,7 +1186,7 @@ function tripal_insert_cvterm($term, $options = array()) {
     );
     $success = chado_update_record('cvterm', $match, $upd_values);
     if (!$success) {
-      tripal_report_error('tripal_chado', TRIPAL_WARNING, "Failed to update the term: $name", NULL);
+      tripal_report_error('tripal_cv', TRIPAL_WARNING, "Failed to update the term: $name", NULL);
       return 0;
     }
 
@@ -1240,16 +1225,17 @@ function tripal_insert_cvterm($term, $options = array()) {
     }
 
     // Finally grab the updated details.
-    $result = chado_query($cvtermsql, array(':accession' => $dbxref->accession, ':name' => $dbname));
+    $result = chado_query($cvtermsql, array(':accession' => $accession, ':name' => $dbname));
     $cvterm = $result->fetchObject();
   }
   else {
-     // do nothing, we have the cvterm but we don't want to update
+    // do nothing, we have the cvterm but we don't want to update
   }
   // return the cvterm
   return $cvterm;
 }
 
+
 /**
  * TODO: deprecate this function
  *

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

@@ -70,14 +70,14 @@ function tripal_chado_publish_records($values, $job_id = NULL) {
   $select = "SELECT T.$pkey_field as record_id ";
   $from = "
     FROM {" . $table . "} T
-      LEFT JOIN {" . $chado_entity_table . "} CE on CE.record_id = T.$pkey_field
+      LEFT JOIN [" . $chado_entity_table . "] CE on CE.record_id = T.$pkey_field
   ";
 
   // For migration of Tripal v2 nodes to entities we want to include the
   // coresponding chado linker table.
   if ($sync_node && db_table_exists('chado_' . $table)) {
     $select = "SELECT T.$pkey_field as record_id, CT.nid ";
-    $from .= " INNER JOIN {chado_" . $table . "} CT ON CT.$pkey_field = T.$pkey_field";
+    $from .= " INNER JOIN [chado_" . $table . "] CT ON CT.$pkey_field = T.$pkey_field";
   }
   $where = " WHERE CE.record_id IS NULL ";
 

+ 5 - 2
tripal_chado/api/tripal_chado.custom_tables.api.inc

@@ -127,6 +127,9 @@ function chado_create_custom_table($table, $schema, $skip_if_exists = TRUE, $mvi
   $created = 0;
   $recreated = 0;
 
+  $chado_schema = tripal_get_schema_name('chado');
+  $chado_dot = $chado_schema . '.';
+
   $transaction = db_transaction();
   try {
     // see if the table entry already exists in the tripal_custom_tables table.
@@ -139,7 +142,7 @@ function chado_create_custom_table($table, $schema, $skip_if_exists = TRUE, $mvi
 
     // if the table does not exist then create it
     if (!$exists) {
-      $ret = db_create_table('chado.' . $table, $schema);
+      $ret = db_create_table($chado_dot . $table, $schema);
       $created = 1;
     }
 
@@ -154,7 +157,7 @@ function chado_create_custom_table($table, $schema, $skip_if_exists = TRUE, $mvi
       if (array_key_exists('referring_tables', $new_schema)) {
         unset($new_schema['referring_tables']);
       }
-      db_create_table('chado.' . $table, $new_schema);
+      db_create_table($chado_dot . $table, $new_schema);
       $recreated = 1;
     }
 

+ 94 - 14
tripal_chado/api/tripal_chado.query.api.inc

@@ -113,17 +113,19 @@ function chado_set_active($dbname = 'default') {
     $GLOBALS['chado_active_db'] = 'default';
   }
 
-  $previous_db = $GLOBALS['chado_active_db'];
-
+  $previous_db = $active_db = $GLOBALS['chado_active_db'];
+  $search_path = tripal_get_schema_name('drupal');
 
   // Change only if 'chado' has been specified.
+  // Notice that we leave the active_db set as chado but use the possibly user-altered
+  // schema name for the actual search path. This is to keep outward facing mentions of
+  // chado as "chado" while still allowing the user to alter the schema name used.
   if ($dbname == 'chado') {
     $active_db = 'chado';
-    $search_path = 'chado,public';
+    $search_path = tripal_get_schema_name('chado') . ',' . tripal_get_schema_name('drupal');
   }
   else {
     $active_db = $dbname;
-    $search_path = 'public';
   }
 
   $settings = array(
@@ -136,10 +138,10 @@ function chado_set_active($dbname = 'default') {
   // note: hooks can alter $active_db and $search_path.
   drupal_alter('chado_connection', $settings);
 
-  // Set chado_active_db to remember active db.
+  // set chado_active_db to remember active db
   $GLOBALS['chado_active_db'] = $active_db;
 
-  // Set PostgreSQL search_path.
+  // set PostgreSQL search_path
   db_query('SET search_path TO ' . $search_path);
 
   return $previous_db;
@@ -1613,7 +1615,7 @@ function chado_select_record_check_value_type(&$op, &$value, $type) {
  * @ingroup tripal_chado_query_api
  */
 function chado_query($sql, $args = array()) {
-  $is_local = $GLOBALS["chado_is_local"];
+  $is_local = isset($GLOBALS["chado_is_local"]) && $GLOBALS["chado_is_local"];
 
   // Args should be an array
   if (!is_array($args)) {
@@ -1634,15 +1636,26 @@ function chado_query($sql, $args = array()) {
     // Chado tables should be enclosed in curly brackets (ie: {feature} )
     // and Drupal tables should be enclosed in square brackets
     // (ie: [tripal_jobs] ).
-    // @todo: remove assumption that the chado schema is called 'chado' and the
-    // drupal schema is called 'public'.
-    $sql = preg_replace('/\{(.*?)\}/', 'chado.$1', $sql);
-    $sql = preg_replace('/\[(\w+)\]/', 'public.$1', $sql);
+    $chado_schema_name = tripal_get_schema_name('chado');
+    $drupal_schema_name = tripal_get_schema_name('drupal');
+    $sql = preg_replace('/\{(.*?)\}/', $chado_schema_name.'.$1', $sql);
+    $sql = preg_replace('/\[(\w+)\]/', $drupal_schema_name.'.$1', $sql);
+
+    // Add an alter hook to allow module developers to change the query right before it's
+    // executed. Since all queriying of chado by Tripal eventually goes through this
+    // function, we only need to provide an alter hook at this point in order to ensure
+    // developers have complete control over the query being executed. For example,
+    // a module developer might want to remove schema prefixing from queries and rely
+    // on the search path. This alter hook would allow them to do that by implementing
+    // mymodule_chado_query_alter($sql, $args) and using a regular expression to remove
+    // table prefixing from the query.
+    // @see hook_chado_query_alter().
+    drupal_alter('chado_query', $sql, $args);
 
     // The featureloc table has some indexes that use function that call other
     // functions and those calls do not reference a schema, therefore, any tables with featureloc
     // must automaticaly have the chado schema set as active to find
-    if (preg_match('/chado.featureloc/i', $sql) or preg_match('/chado.feature/i', $sql)) {
+    if (preg_match('/'.$chado_schema_name . '.featureloc/i', $sql) or preg_match('/' . $chado_schema_name . '.feature/i', $sql)) {
       $previous_db = chado_set_active('chado') ;
       try {
         $results = db_query($sql, $args);
@@ -1672,14 +1685,48 @@ function chado_query($sql, $args = array()) {
   // if Chado is not local to the Drupal database then we have to
   // switch to another database
   else {
-    $previous_db = chado_set_active('chado') ;
+    $previous_db = chado_set_active('chado');
     $results = db_query($sql, $args);
     chado_set_active($previous_db);
   }
 
   return $results;
 }
-
+/**
+ * This hook provides a way for module developers to alter any/all queries on the chado
+ * schema by Tripal.
+ *
+ * Example: a module developer might want to remove schema prefixing from queries and rely
+ * on the search path. This alter hook would allow them to do that by implementing
+ * mymodule_chado_query_alter($sql, $args) and using a regular expression to remove
+ * table prefixing from the query.
+ *
+ * @param $sql
+ *    A string describing the SQL query to be executed by Tripal. All parameters should be
+ *    indicated by :tokens with values being in the $args array and all tables should
+ *    be prefixed with the schema name described in tripal_get_schema_name().
+ * @param $args
+ *    An array of arguments where the key is the token used in $sql (for example, :value)
+ *    and the value is the value you would like substituted in.
+ */
+function hook_chado_query_alter(&$sql, &$args) {
+
+  // The following code is an example of how this alter function might be used.
+  // Say you would like only a portion of node => feature connections available
+  // for a period of time or under a specific condition. To "hide" the other connections
+  // you might create a temporary view of the chado_feature table that only includes
+  // the connections you would like to be available. In order to ensure this view
+  // is used rather than the original chado_feature table you could alter all Tripal
+  // queries referring to chado_feature to instead refer to your view.
+  if (preg_match('/(\w+)\.chado_feature/', $sql, $matches)) {
+
+    $sql = str_replace(
+        $matches[1] . '.chado_feature',
+        'chado_feature_view',
+        $sql
+    );
+  }
+}
 /**
  * Use this function instead of pager_query() when selecting a
  * subset of records from a Chado table.
@@ -1905,7 +1952,40 @@ function tripal_get_schema_name($schema = 'chado') {
 
   return $schema_name;
 }
+/**
+ * Alter the name of the schema housing Chado and/or Drupal.
+ *
+ * This example implementation shows a solution for the case where your chado database
+ * was well established in the "public" schema and you added Drupal later in a
+ * "drupal" schema. Please note that this has not been tested and while we can ensure
+ * that Tripal will work as expected, we have no control over whether Drupal is
+ * compatible with not being in the public schema. That's why we recommened the
+ * organization we have (ie: Chado in a "chado" schema and Drupal in the "public schema).
+ *
+ * @param $schema_name
+ *   The current name of the schema as known by Tripal. This is likely the default
+ *   set in tripal_get_schema_name() but in the case of multiple alter hooks, it might
+ *   be different.
+ * @param $context
+ *   This is an array of items to provide context.
+ *     - schema: this is the schema that was passed to tripal_get_schema_name() and will
+ *       be either "chado" or "drupal". This should be used to determine you are changing
+ *       the name of the correct schema.
+ */
+function hook_tripal_get_schema_name_alter($schema_name, $context) {
 
+  // First we check which schema was passed to chado_get_schema().
+  // Notice that we do not use $schema_name since it may already have
+  // been altered by another module.
+  if ($context['schema'] == 'chado') {
+    $schema_name = 'public';
+  }
+  // Notice that we use elseif to capture the second case rather than else. This
+  // avoids the assumption that there is only one chado and one drupal schema.
+  elseif ($context['schema'] == 'drupal') {
+    $schema_name = 'drupal';
+  }
+}
 /**
  * A replacment for db_select when querying Chado.
  *

+ 13 - 7
tripal_chado/api/tripal_chado.schema.api.inc

@@ -31,13 +31,15 @@
  * This function is necessary because Drupal's db_table_exists() function will
  * not look in any other schema but the one were Drupal is installed
  *
+ * @param $table
+ *   The name of the chado table whose existence should be checked.
+ *
  * @return
- *   TRUE/FALSE depending upon whether it exists
+ *   TRUE if the table exists in the chado schema and FALSE if it does not.
  *
  * @ingroup tripal_chado_schema_api
  */
 function chado_table_exists($table) {
-  global $databases;
 
   global $databases;
 
@@ -264,9 +266,9 @@ function chado_is_local() {
     FROM pg_namespace
     WHERE
       has_schema_privilege(nspname, 'USAGE') AND
-      nspname = 'chado'
+      nspname = :chado
   ";
-  $results = db_query($sql);
+  $results = db_query($sql, array(':chado' => tripal_get_schema_name('chado')));
   $name = $results->fetchObject();
   if ($name) {
     variable_set('chado_schema_exists', FALSE);
@@ -290,7 +292,7 @@ function chado_is_installed() {
   global $databases;
 
   // first check if chado is in the $databases variable of the settings.php file
-  if (array_key_exists('chado', $databases)) {
+  if (array_key_exists(tripal_get_schema_name('chado'), $databases)) {
     return TRUE;
   }
 
@@ -332,7 +334,7 @@ function chado_get_version($exact = FALSE, $warn_if_unsupported = FALSE) {
   if (!$chado_exists) {
     // if it's not in the drupal database check to see if it's specified in the $db_url
     // in the settings.php
-    if (!array_key_exists('chado', $databases)) {
+    if (!array_key_exists(tripal_get_schema_name('chado'), $databases)) {
       // if it's not in the drupal database or specified in the $db_url then
       // return uninstalled as the version
       return 'not installed';
@@ -344,7 +346,8 @@ function chado_get_version($exact = FALSE, $warn_if_unsupported = FALSE) {
   }
   else {
     $is_local = 1;
-    $prop_exists = chado_table_exists('chadoprop');
+    // @todo we need a chado aware db_table_exists.
+    $prop_exists = db_table_exists(tripal_get_schema_name('chado') . '.chadoprop');
   }
 
   // if the table doesn't exist then we don't know what version but we know
@@ -401,6 +404,9 @@ function chado_get_version($exact = FALSE, $warn_if_unsupported = FALSE) {
   if (preg_match('/^1\.2\d+$/', $effective_version)) {
     $effective_version = "1.2";
   }
+  else if (preg_match('/^1\.3\d+$/', $effective_version)) {
+    $effective_version = "1.3";
+  }
   if ($warn_if_unsupported and ($effective_version  < 1.11 and $effective_version != 'not installed')) {
     drupal_set_message(t("WARNING: The currently installed version of Chado, v$exact_version, is not fully compatible with Tripal."), 'warning');
   }

+ 3 - 3
tripal_chado/includes/TripalFields/chado_linker__contact/chado_linker__contact.inc

@@ -117,7 +117,7 @@ class chado_linker__contact extends ChadoField {
     $field_table = $this->instance['settings']['chado_table'];
     $field_column = $this->instance['settings']['chado_column'];
 
-    $type_term = tripal_get_chado_semweb_term('contact', 'type');
+    $type_term = tripal_get_chado_semweb_term('contact', 'type_id');
     $name_term = tripal_get_chado_semweb_term('contact', 'name');
     $description_term = tripal_get_chado_semweb_term('contact', 'description');
 
@@ -136,7 +136,7 @@ class chado_linker__contact extends ChadoField {
     $entity->{$field_name}['und'][0] = array(
       'value' => array(),
       'chado-' . $field_table . '__' . $pkey => '',
-      'chado-' . $field_table . '__' . $fkey_lcolumn => '',
+      'chado-' . $field_table . '__' . $fkey_lcolumn => $record->$fkey_lcolumn,
       'chado-' . $field_table . '__' . 'contact_id' => '',
       // Ignore the synonym_sgml column for now.
     );
@@ -169,7 +169,7 @@ class chado_linker__contact extends ChadoField {
           // Add elements that are not part of the values but used by
           // the chado storage back-end for saving values.
           'chado-' . $field_table . '__' . $pkey => $contact_linker->$pkey,
-          'chado-' . $field_table . '__' . $fkey_lcolumn => $contact_linker->$fkey_lcolumn->$fkey_lcolumn,
+          'chado-' . $field_table . '__' . $fkey_lcolumn => $record->$fkey_lcolumn,
           'chado-' . $field_table . '__' . 'contact_id' => $contact->contact_id
         );
 

+ 7 - 3
tripal_chado/includes/TripalFields/chado_linker__contact/chado_linker__contact_formatter.inc

@@ -24,6 +24,10 @@ class chado_linker__contact_formatter extends ChadoFieldFormatter {
     // Get the settings
     $settings = $display['settings'];
 
+    $type_term = tripal_get_chado_semweb_term('contact', 'type_id');
+    $name_term = tripal_get_chado_semweb_term('contact', 'name');
+    $description_term = tripal_get_chado_semweb_term('contact', 'description');
+
     $headers = array('Name', 'Description', 'Type');
     $rows = array();
 
@@ -34,9 +38,9 @@ class chado_linker__contact_formatter extends ChadoFieldFormatter {
       }
 
       // Get the field values
-      $contact_name = $contact['name'];
-      $description = $contact['description'];
-      $type = $contact['type'];
+      $contact_name = $contact[$name_term];
+      $description = $contact[$description_term];
+      $type = $contact[$type_term];
 
       // Add a link i there is an entity.
       if (array_key_exists('entity', $item['value']) and $item['value']['entity']) {

+ 45 - 49
tripal_chado/includes/TripalFields/chado_linker__contact/chado_linker__contact_widget.inc

@@ -15,53 +15,60 @@ class chado_linker__contact_widget extends ChadoFieldWidget {
     parent::form($widget, $form, $form_state, $langcode, $items, $delta, $element);
 
     $field_name = $this->field['field_name'];
+    $field_type = $this->field['type'];
+    $base_table = $this->instance['settings']['base_table'];
+    $chado_table = $this->instance['settings']['chado_table'];
+    $chado_column = $this->instance['settings']['chado_column'];
+    $instance = $this->instance;
 
     // Get the FK column that links to the base table.
-    $table_name = $this->instance['settings']['chado_table'];
-    $base_table = $this->instance['settings']['base_table'];
-    $schema = chado_get_schema($table_name);
+    $schema = chado_get_schema($chado_table);
     $pkey = $schema['primary key'][0];
-    $fkeys = array_values($schema['foreign keys'][$base_table]['columns']);
-    $fkey = $fkeys[0];
+    $lfkey_field = key($schema['foreign keys'][$base_table]['columns']);
 
     // Get the field defaults.
     $record_id = '';
-    $fkey_value = array_key_exists('#entity', $element) and $element['#entity'] ? $element['#entity']->chado_record_id : NULL;
+    $fk_value = array_key_exists('#entity', $element) and $element['#entity'] ? $element['#entity']->chado_record_id : NULL;
     $contact_id = '';
     $name = '';
+    $value = '';
+
 
     // If the field already has a value then it will come through the $items
     // array.  This happens when editing an existing record.
-    if (count($items) > 0 and array_key_exists($delta, $items)) {
-      $record_id = tripal_get_field_item_keyval($items, $delta, 'chado-' . $table_name . '__' . $pkey, $record_id);
-      $contact_id = tripal_get_field_item_keyval($items, $delta, 'chado-' . $table_name . '__contact_id', $contact_id);
-      if ($contact_id) {
-        $contact = chado_generate_var('contact', array('contact_id' => $contact_id));
-        $name = $contact->name;
+    if (count($items) > 0) {
+      // Check for element values that correspond to fields in the Chado table.
+      $fk_value = tripal_get_field_item_keyval($items, 0, 'chado-' . $chado_table . '__' . $lfkey_field, $fk_value);
+      if (array_key_exists($delta, $items)) {
+        $record_id = tripal_get_field_item_keyval($items, $delta, 'chado-' . $chado_table . '__' . $pkey, $record_id);
+        $contact_id = tripal_get_field_item_keyval($items, $delta, 'chado-' . $chado_table . '__contact_id', $contact_id);
       }
     }
 
-    $schema = chado_get_schema('contact');
+    // Check $form_state['values'] to see if an AJAX call set the values.
+    if (array_key_exists('values', $form_state) and array_key_exists($delta, $form_state['values'])) {
+      $record_id = $form_state['values'][$field_name]['und'][$delta]['chado-' . $chado_table . '__' . $pkey];
+      $fk_value = $form_state['values'][$field_name]['und'][$delta]['chado-' . $chado_table . '__' . $lfkey_field];
+      $contact_id = $form_state['values'][$field_name]['und'][$delta]['chado-' . $chado_table . '__contact_id'];
+    }
+
 
-    $widget['#table_name'] = $table_name;
-    $widget['#fkey_field'] = $fkey;
-    $widget['#prefix'] =  "<span id='$table_name-$delta'>";
-    $widget['#suffix'] =  "</span>";
+    $schema = chado_get_schema('contact');
 
     $widget['value'] = array(
       '#type' => 'value',
       '#value' => array_key_exists($delta, $items) ? $items[$delta]['value'] : '',
     );
 
-    $widget['chado-' . $table_name . '__' . $pkey] = array(
+    $widget['chado-' . $chado_table . '__' . $pkey] = array(
       '#type' => 'value',
       '#default_value' => $record_id,
     );
-    $widget['chado-' . $table_name . '__' . $fkey] = array(
+    $widget['chado-' . $chado_table . '__' . $lfkey_field] = array(
       '#type' => 'value',
-      '#default_value' => $fkey_value,
+      '#default_value' => $fk_value,
     );
-    $widget['chado-' . $table_name . '__contact_id'] = array(
+    $widget['chado-' . $chado_table . '__contact_id'] = array(
       '#type' => 'value',
       '#default_value' => $contact_id,
     );
@@ -73,7 +80,7 @@ class chado_linker__contact_widget extends ChadoFieldWidget {
       '#autocomplete_path' => 'admin/tripal/storage/chado/auto_name/contact',
       '#ajax' => array(
         'callback' => "chado_linker__contact_widget_form_ajax_callback",
-        'wrapper' => "$table_name-$delta",
+        'wrapper' => "$chado_table-$delta",
         'effect' => 'fade',
         'method' => 'replace'
       ),
@@ -87,41 +94,30 @@ class chado_linker__contact_widget extends ChadoFieldWidget {
    * @see TripalFieldWidget::submit()
    */
   public function submit($form, &$form_state, $entity_type, $entity, $langcode, $delta) {
-    // Get the FK column that links to the base table.
-    $table_name = $this->instance['settings']['chado_table'];
+    $field_name = $this->field['field_name'];
+    $field_type = $this->field['type'];
     $base_table = $this->instance['settings']['base_table'];
-    $schema = chado_get_schema($table_name);
+    $chado_table = $this->instance['settings']['chado_table'];
+    $chado_column = $this->instance['settings']['chado_column'];
+    $instance = $this->instance;
+    $schema = chado_get_schema($chado_table);
+
     $pkey = $schema['primary key'][0];
-    $fkeys = array_values($schema['foreign keys'][$base_table]['columns']);
-    $fkey = $fkeys[0];
-    $field_name = $this->field['field_name'];
+    $lfkey_field = key($schema['foreign keys'][$base_table]['columns']);
 
     // Get the field values.
-    $fkey_value = isset($form_state['values'][$field_name][$langcode][$delta]['value']) ? $form_state['values'][$field_name][$langcode][$delta]['value'] : '';
-    $contact_id = isset($form_state['values'][$field_name][$langcode][$delta]['chado-' . $table_name . '__contact_id']) ? $form_state['values'][$field_name][$langcode][$delta]['chado-' . $table_name . '__contact_id'] : '';
-    $name = isset($form_state['values'][$field_name][$langcode][$delta]['name']) ? $form_state['values'][$field_name][$langcode][$delta]['name'] : '';
+    $record_id = $form_state['values'][$field_name]['und'][$delta]['chado-' . $chado_table . '__' . $pkey];
+    $fk_value = $form_state['values'][$field_name]['und'][$delta]['chado-' . $chado_table . '__' . $lfkey_field];
+    $contact_id = $form_state['values'][$field_name]['und'][$delta]['chado-' . $chado_table . '__contact_id'];
+    $name = $form_state['values'][$field_name]['und'][$delta]['name'];
 
     // If the user provided a name then we want to set the foreign key
     // value to be the chado_record_id
-    if ($name and !$contact_id) {
+    if ($name) {
       $contact = chado_generate_var('contact', array('name' => $name));
-      $form_state['values'][$field_name][$langcode][$delta]['chado-' . $table_name . '__contact_id'] = $contact->contact_id;
-    }
-
-    // In the widgetForm function we automatically add the foreign key
-    // record.  But if the user did not provide a contact we want to take
-    // it out so that the Chado field_storage infrastructure won't try to
-    // write a record.
-    if (!$name and !$contact_id) {
-      $form_state['values'][$field_name][$langcode][$delta]['chado-' . $table_name . '__' . $fkey] = '';
-    }
-
-    // If the user removed the contact from the contact_name field
-    // then we want to clear out the rest of the hidden values.
-    // Leave the primary key so the record can be deleted.
-    if (!$name and $contact_id) {
-      $form_state['values'][$field_name][$langcode][$delta]['chado-' . $table_name . '__' . $fkey] = '';
-      $form_state['values'][$field_name][$langcode][$delta]['chado-' . $table_name . '__contact_id'] = '';
+      $form_state['values'][$field_name][$langcode][$delta]['chado-' . $chado_table . '__contact_id'] = $contact->contact_id;
+      $form_state['values'][$field_name][$langcode][$delta]['value'] = $name;
     }
+    dpm($form_state['values']);
   }
 }

+ 0 - 22
tripal_chado/includes/TripalFields/obi__organism/obi__organism.inc

@@ -30,28 +30,6 @@ class obi__organism extends ChadoField {
     'field_display_string' => '<i>[organism.genus] [organism.species]</i>',
   );
 
-  // In order for this field to integrate with Drupal Views, a set of
-  // handlers must be specififed.  These include handlers for
-  // the field, for the filter, and the sort.  Within this variable,
-  // the key must be one of: field, filter, sort; and the value
-  // is the settings for those handlers as would be provided by
-  // a hook_views_data().  The following defaults make a field visible
-  // using the default formatter of the field, allow for filtering using
-  // a string value and sortable.  in order for filters to work you
-  // must implement the query() function.
-  public static $default_view_handlers = array(
-    'field' => array(
-      'handler' => 'tripal_views_handler_field',
-      'click sortable' => TRUE,
-    ),
-    'filter' => array(
-      'handler' => 'tripal_views_handler_filter_string',
-    ),
-    'sort' => array(
-      'handler' => 'views_handler_sort',
-    ),
-  );
-
   // The default widget for this field.
   public static $default_widget = 'OBI__organism_widget';
 

+ 35 - 20
tripal_chado/includes/TripalImporter/FASTAImporter.inc

@@ -416,16 +416,18 @@ class FASTAImporter extends TripalImporter {
     }
 
     // Second, if there is a parent type then get that.
+    $parentcvterm = NULL;
     if ($parent_type) {
       $parentcvterm = chado_query($cvtermsql, array(':cvname' => 'sequence', ':name' => $parent_type,':synonym' => $parent_type))->fetchObject();
       if (!$parentcvterm) {
-        $this->logMessage("Cannot find the paretne term type: '!type'",
+        $this->logMessage("Cannot find the parent term type: '!type'",
           array('!type' => $parentcvterm), TRIPAL_ERROR);
         return 0;
       }
     }
 
     // Third, if there is a relationship type then get that.
+    $relcvterm = NULL;
     if ($rel_type) {
       $relcvterm = chado_query($cvtermsql, array(':cvname' => 'sequence',':name' => $rel_type,':synonym' => $rel_type))->fetchObject();
       if (!$relcvterm) {
@@ -465,6 +467,7 @@ class FASTAImporter extends TripalImporter {
         $defline = preg_replace("/^>/", '', $line);
 
         // Get the feature name if a regular expression is provided.
+        $name = "";
         if ($re_name) {
           if (!preg_match("/$re_name/", $defline, $matches)) {
             $this->logMessage("Regular expression for the feature name finds nothing. Line !line.",
@@ -497,6 +500,7 @@ class FASTAImporter extends TripalImporter {
         }
 
         // Get the feature uniquename if a regular expression is provided.
+        $uname = "";
         if ($re_uname) {
           if (!preg_match("/$re_uname/", $defline, $matches)) {
             $this->logMessage("Regular expression for the feature unique name finds nothing. Line !line.",
@@ -506,7 +510,7 @@ class FASTAImporter extends TripalImporter {
         }
         // If the match_type is name and no regular expression was provided
         // then use the first word as the name, otherwise, we don't set the
-        // unqiuename.
+        // uniquename.
         elseif (strcmp($match_type, 'Unique name') == 0) {
           if (preg_match("/^\s*(.*?)[\s\|].*$/", $defline, $matches)) {
             $uname = trim($matches[1]);
@@ -518,18 +522,25 @@ class FASTAImporter extends TripalImporter {
         }
 
         // Get the accession if a regular expression is provided.
-        preg_match("/$re_accession/", $defline, $matches);
-        if (strlen($matches[1]) > $dbxref_tbl['fields']['accession']['length']) {
-          $this->logMessage("Regular expression retrieves an accession too long for the feature name. " .
-            "Cannot add cross reference. Line !line.", array('!line' => $i), TRIPAL_WARNING);
-        }
-        else {
-          $accession = trim($matches[1]);
+        $accession = "";
+        if (!empty($re_accession)) {
+          preg_match("/$re_accession/", $defline, $matches);
+          if (strlen($matches[1]) > $dbxref_tbl['fields']['accession']['length']) {
+            tripal_report_error('trp-fasta', TRIPAL_WARNING, "WARNING: Regular expression retrieves an accession too long for the feature name. " .
+               "Cannot add cross reference. Line %line.", array('%line' => $i
+            ));
+          }
+          else {
+            $accession = trim($matches[1]);
+          }
         }
 
         // Get the relationship subject
-        preg_match("/$re_subject/", $line, $matches);
-        $subject = trim($matches[1]);
+         $subject = "";
+        if (!empty($re_subject)) {
+          preg_match("/$re_subject/", $line, $matches);
+          $subject = trim($matches[1]);
+        }
 
         // Add the details to the sequence.
         $seqs[$num_seqs] = array(
@@ -561,9 +572,10 @@ class FASTAImporter extends TripalImporter {
     $this->logMessage("Found !num_seqs sequence(s).", array('!num_seqs' => $num_seqs));
     $this->setTotalItems($num_seqs);
     $this->setItemsHandled(0);
-    for ($i = 0; $i < $num_seqs; $i++) {
-      $seq = $seqs[$i];
+    for ($j = 0; $j < $num_seqs; $j++) {
+      $seq = $seqs[$j];
       //$this->logMessage("Importing !seqname.", array('!seqname' => $seq['name']));
+      $source = NULL;
       $this->loadFastaFeature($fh, $seq['name'], $seq['uname'], $db_id,
           $seq['accession'], $seq['subject'], $rel_type, $parent_type,
           $analysis_id, $organism_id, $cvterm, $source, $method, $re_name,
@@ -619,7 +631,7 @@ class FASTAImporter extends TripalImporter {
       }
 
       // If the feature exists but this is an "insert only" then skip.
-      if ($feature and (strcmp($method, 'Insert only') == 0)) {
+      if (isset($feature) and (strcmp($method, 'Insert only') == 0)) {
         $this->logMessage("Feature already exists '!name' ('!uname') while matching on !type. Skipping insert.",
           array('!name' => $name,'!uname' => $uname,'!type' => drupal_strtolower($match_type)), TRIPAL_WARNING);
         return 0;
@@ -628,7 +640,7 @@ class FASTAImporter extends TripalImporter {
 
     // If we don't have a feature and we're doing an insert then do the insert.
     $inserted = 0;
-    if (!$feature and (strcmp($method, 'Insert only') == 0 or strcmp($method, 'Insert and update') == 0)) {
+    if (!isset($feature) and (strcmp($method, 'Insert only') == 0 or strcmp($method, 'Insert and update') == 0)) {
       // If we have a unique name but not a name then set them to be the same
       if (!$uname) {
         $uname = $name;
@@ -673,14 +685,14 @@ class FASTAImporter extends TripalImporter {
     }
 
     // if we don't have a feature and the user wants to do an update then fail
-    if (!$feature and (strcmp($method, 'Update only') == 0 or strcmp($method, 'Insert and update') == 0)) {
+    if (!isset($feature) and (strcmp($method, 'Update only') == 0 or strcmp($method, 'Insert and update') == 0)) {
       $this->logMessage("Failed to find feature '!name' ('!uname') while matching on " . drupal_strtolower($match_type) . ".",
           array('!name' => $name,'!uname' => $uname), TRIPAL_ERROR);
       return 0;
     }
 
     // if we do have a feature and this is an update then proceed with the update
-    if ($feature and !$inserted and (strcmp($method, 'Update only') == 0 or strcmp($method, 'Insert and update') == 0)) {
+    if (isset($feature) and !$inserted and (strcmp($method, 'Update only') == 0 or strcmp($method, 'Insert and update') == 0)) {
 
       // if the user wants to match on the Name field
       if (strcmp($match_type, 'Name') == 0) {
@@ -861,7 +873,7 @@ class FASTAImporter extends TripalImporter {
     fseek($fh, $seq_start, SEEK_SET);
     $chunk_size = 100000000;
     $chunk = '';
-    $seqlen = ($seq_end - $seq_start) + 1;
+    $seqlen = ($seq_end - $seq_start);
 
     $num_read = 0;
     $total_seq_size = 0;
@@ -873,9 +885,11 @@ class FASTAImporter extends TripalImporter {
     // Read in the lines until we reach the end of the sequence. Once we
     // get a specific bytes read then append the sequence to the one in the
     // database.
+    $partial_seq_size = 0;
     while ($line = fgets($fh)) {
       $num_read += strlen($line) + 1;
       $chunk_intv_read += strlen($line) + 1;
+      $partial_seq_size += strlen($line);
       $chunk .= trim($line);
 
       // If we've read in enough of the sequence then append it to the database.
@@ -894,7 +908,7 @@ class FASTAImporter extends TripalImporter {
         $chunk_intv_read = 0;
       }
 
-      // If we've reached the ned of the sequence then break out of the loop
+      // If we've reached the end of the sequence then break out of the loop
       if (ftell($fh) == $seq_end) {
         break;
       }
@@ -911,7 +925,8 @@ class FASTAImporter extends TripalImporter {
       if (!$success) {
         return FALSE;
       }
-      $total_seq_size += strlen($chunk);
+      $total_seq_size += $partial_seq_size;
+      $partial_seq_size = 0;
       $chunk = '';
       $chunk_intv_read = 0;
     }

+ 1 - 1
tripal_chado/includes/TripalImporter/OBOImporter.inc

@@ -925,7 +925,7 @@ class OBOImporter extends TripalImporter {
       'is_obsolete' => 0,
       'cv_name' => $defaultcv,
       'is_relationship' => TRUE,
-      'db_naame' => $default_db
+      'db_name' => $default_db
     );
     $relcvterm = tripal_insert_cvterm($term, array('update_existing' => FALSE));
 

+ 22 - 9
tripal_chado/includes/loaders/tripal_chado.pub_importer_AGL.inc

@@ -2,10 +2,10 @@
 /**
  * @file
  * This file provides support for importing and parsing of results from the
- * USDA National Agricultural Library (AGL) database.  The functions here are used by
- * both the publication importer setup form and the publication importer.
- *
- * The USDA AGL database uses a YAZ protocol for querying and retrieving records.
+ * USDA National Agricultural Library (AGL) database.  The functions here are
+ * used by both the publication importer setup form and the publication
+ * importer. The USDA AGL database uses a YAZ protocol for querying and
+ * retrieving records.
  *
  */
 
@@ -353,8 +353,10 @@ function tripal_pub_remote_search_AGL($search_array, $num_to_retrieve, $page) {
   // yaz_connect() prepares for a connection to a Z39.50 server. This function is non-blocking
   // and does not attempt to establish a connection - it merely prepares a connect to be
   // performed later when yaz_wait() is called.
-  //$yazc = yaz_connect('agricola.nal.usda.gov:7090/voyager'); // NAL Catalog
-  $yazc = yaz_connect('agricola.nal.usda.gov:7190/voyager');  // NAL Article Citation Database
+  // NAL Catalog
+  //$yazc = yaz_connect('agricola.nal.usda.gov:7090/voyager');
+  // NAL Article Citation Database
+  $yazc = yaz_connect('agricola.nal.usda.gov:7190/voyager');
 
   // use the USMARC record type.  But OPAC is also supported by Agricola
   yaz_syntax($yazc, "usmarc");
@@ -434,9 +436,9 @@ function tripal_pub_AGL_range($yazc, $search_str, $start, $num_to_retrieve, $tot
     }
     drupal_set_message("ERROR waiting on search at AGL: ($error_no) $error_msg", "error");
     watchdog('tpub_import', "ERROR waiting on search at AGL: (%error_no) %error_msg",
-    array('%error_no' => $error_no, '%error_msg' => $error_msg), WATCHDOG_ERROR);
+      array('%error_no' => $error_no, '%error_msg' => $error_msg), WATCHDOG_ERROR);
     return array(
-      'total_records' => $total_records,
+      'total_records' => 0,
       'search_str'    => $search_str,
       'pubs'          => array(),
     );
@@ -449,7 +451,18 @@ function tripal_pub_AGL_range($yazc, $search_str, $start, $num_to_retrieve, $tot
   for($i = $start; $i < $start + $num_to_retrieve; $i++) {
     // retrieve the XML results
     $pub_xml = yaz_record($yazc, $i + 1, 'xml; charset=marc-8,utf-8');
-
+    if (!$pub_xml) {
+      $error_no = yaz_errno($yazc);
+      $error_msg = yaz_error($yazc);
+      drupal_set_message("ERROR retrieving records from AGL: ($error_no) $error_msg", "error");
+      watchdog('tpub_import', "ERROR retrieving records from AGL: (%error_no) %error_msg",
+        array('%error_no' => $error_no, '%error_msg' => $error_msg), WATCHDOG_ERROR);
+      return array(
+        'total_records' => 0,
+        'search_str'    => $search_str,
+        'pubs'          => array(),
+      );
+    }
     // parse the pub XML
     $pub     = tripal_pub_AGL_parse_pubxml($pub_xml);
     $pubs[]  = $pub;

+ 2 - 2
tripal_chado/includes/loaders/tripal_chado.pub_importers.inc

@@ -169,9 +169,9 @@ function tripal_pub_importer_setup_page($action = 'new', $pub_import_id = NULL)
       $i = $page * $limit + 1;
       if (count($pubs) > 0) {
         foreach ($pubs as $pub) {
-          $citation = htmlspecialchars($pub['Citation']);
+          $citation = array_key_exists('Citation', $pub) ? htmlspecialchars($pub['Citation']) : 'Unable to generate citation';
           $raw_link = '';
-          if($pub['Publication Dbxref']) {
+          if(array_key_exists('Publication Dbxref', $pub) and $pub['Publication Dbxref']) {
             $raw_link = l('raw', 'admin/tripal/loaders/pub/raw/' . $pub['Publication Dbxref'], array('attributes' => array('target' => '_blank')));
           }
           $rows[] = array(

+ 2 - 5
tripal_chado/includes/tripal_chado.cv.inc

@@ -331,11 +331,8 @@ function tripal_cv_cvterm_edit_form($form, &$form_state) {
     $cv_id = $form_state['build_info']['args'][0];
     $cvterm_id = $form_state['build_info']['args'][1];
     if ($form_state['build_info']['args'][1]) {
-      $result = db_select('chado.cvterm','c')
-      ->fields('c', array('name'))
-      ->condition('c.cvterm_id',$cvterm_id)
-      ->execute();
-      $cvterm_name = $result->fetchObject()->name;
+      $cvterm_name = chado_query('SELECT name FROM {cvterm} WHERE cvterm_id = :id',
+          array(':id' => $cvterm_id))->fetchField();
       $step = 1;
     }
   }

+ 6 - 66
tripal_chado/includes/tripal_chado.entity.inc

@@ -199,73 +199,13 @@ function tripal_chado_tripal_default_title_format($bundle, $available_tokens) {
       'weight' => -5,
     );
   }
-  return $format;
-}
-
-/**
- * Implements hook_entity_property_info_alter().
- *
- * This is being implemented to ensure chado fields are exposed for search api
- * indexing. All fields are available for index by default but the getter
- * function set by default is not actually capable of getting the value from
- * chado. Thus we change the getter function to one that can :-).
- */
-function tripal_chado_entity_property_info_alter(&$info) {
-
-  // Get a list of fields with the chado storage backend.
-
-  // Loop through all of the bundles.
-  if (isset($info['TripalEntity']['bundles'])) {
-    foreach ($info['TripalEntity']['bundles'] as $bundle_id => $bundle) {
-      // Loop through each of the fields for a given bundle.
-      foreach ($bundle['properties'] as $field_name => $field_info) {
-        // If the field is a chado field, then change the callback.
-        // @todo check this properly.
-        if (preg_match('/(\w+)__(\w+)/', $field_name, $matches)) {
-          $info['TripalEntity']['bundles'][$bundle_id]['properties'][$field_name]['getter callback'] =
-          'tripal_chado_entity_property_get_value';
-        }
-      }
-    }
-  }
-
-}
-
-/**
- * Provides a way for the search api to grab the value of a chado field.
- *
- * @param $entity
- *   The fully-loaded entity object to be indexed.
- * @param $options
- *   Options that can be ued when retrieving the value.
- * @param $field_name
- *   The machine name of the field we want to retrieve.
- * @param $entity_type
- *   The type of entity (ie: TripalEntity).
- *
- * @return
- *   The rendered value of the field specified by $field_name.
- */
-function tripal_chado_entity_property_get_value($entity, $options, $field_name, $entity_type) {
-
-  $display = array(
-    'type' => '',
-    'label' => 'hidden',
-  );
-
-  $langcode = LANGUAGE_NONE;
-  $items = field_get_items($entity_type, $entity, $field_name);
-  if (count($items) == 1) {
-    $render_array = field_view_value($entity_type, $entity, $field_name, $items[0], $display, $langcode);
-  }
-  // @todo: handle fields with multiple values.
-  else {
-    $render_array = field_view_value($entity_type, $entity, $field_name, $items[0], $display, $langcode);
-    drupal_set_message('Tripal Chado currently only supports views integration ' .
-      'for single value fields. The first value has been shown.', 'warning');
+  if ($table == 'contact') {
+    $format[] = array(
+      'format' => '[schema__name]',
+      'weight' => -5,
+    );
   }
-
-  return drupal_render($render_array);
+  return $format;
 }
 
 /**

+ 9 - 8
tripal_chado/includes/tripal_chado.field_storage.inc

@@ -43,7 +43,7 @@ function tripal_chado_field_storage_write($entity_type, $entity, $op, $fields) {
 
   // Convert the fields into a key/value list of fields and their values.
   $field_vals = tripal_chado_field_storage_write_merge_fields($fields, $entity_type, $entity);
-
+dpm($field_vals);
   // First, write the record for the base table.  If we have a record id then
   // this is an update and we need to set the primary key.  If not, then this
   // is an insert and we need to set the type_id if the table supports it.
@@ -60,13 +60,14 @@ function tripal_chado_field_storage_write($entity_type, $entity, $op, $fields) {
   if ($op == FIELD_STORAGE_INSERT) {
     // Add the record to the proper chado entity table
     $chado_entity_table = chado_get_bundle_entity_table($bundle);
-    $record = array(
-      'entity_id' => $entity->id,
-      'record_id' => $base_record_id,
-    );
-    $success = drupal_write_record($chado_entity_table, $record);
-    if (!$success) {
-      drupal_set_message('Unable to insert new Chado entity.', 'error');
+    $record_id = db_insert($chado_entity_table)
+      ->fields(array(
+        'entity_id' => $entity->id,
+        'record_id' => $base_record_id
+      ))
+      ->execute();
+    if (!$record_id) {
+      throw new Exception('Unable to insert new Chado entity.');
     }
   }
 

+ 10 - 6
tripal_chado/includes/tripal_chado.install.inc

@@ -17,6 +17,7 @@ function tripal_chado_load_form($form, $form_state) {
   // get the effective version.  Pass true as second argument
   // to warn the user if the current version is not compatible
   $version = chado_get_version(FALSE, TRUE);
+
   if (array_key_exists('values', $form_state)) {
     if ($form_state['values']['action_to_do'] == "Upgrade Chado v1.2 to v1.3") {
       $tables_list = implode(', ', array('analysis_cvterm', 'analysis_dbxref', 'analysis_pub',
@@ -492,10 +493,8 @@ function tripal_chado_upgrade_chado_1_2_to_1_3_pre_alter() {
 function tripal_chado_upgrade_chado_1_11_to_1_2() {
 
   // Get the path to the schema diff and upgarde SQL files.
-  $schema_file = drupal_get_path('module', 'tripal_chado') .
-    '/chado_schema/default_schema-1.11-1.2-diff.sql';
-  $init_file = drupal_get_path('module', 'tripal_chado') .
-    '/chado_schema/upgrade-1.11-1.2.sql';
+  $schema_file = drupal_get_path('module', 'tripal_chado') . '/chado_schema/default_schema-1.11-1.2-diff.sql';
+  $init_file = drupal_get_path('module', 'tripal_chado') . '/chado_schema/upgrade-1.11-1.2.sql';
 
   $success = tripal_chado_install_sql($schema_file);
   if ($success) {
@@ -538,8 +537,13 @@ function tripal_chado_reset_chado_schema() {
     print "Dropping existing 'frange' schema\n";
     db_query("drop schema frange cascade");
   }
-  if (chado_dbschema_exists('chado')) {
-    print "Dropping existing 'chado' schema\n";
+  if (chado_dbschema_exists($chado_schema)) {
+    if ($chado_schema != 'chado') {
+      print "Dropping existing Chado ('$chado_schema') schema\n";
+    }
+    else {
+      print "Dropping existing 'chado' schema\n";
+    }
     db_query("drop schema $chado_schema cascade");
   }
 

+ 7 - 7
tripal_chado/includes/tripal_chado.migrate.inc

@@ -131,7 +131,7 @@ function tripal_chado_migrate_form($form, &$form_state) {
         $sql =
            "SELECT count(*)
             FROM {organism} O
-            INNER JOIN {chado_organism} CO ON O.organism_id = CO.organism_id
+            INNER JOIN [chado_organism] CO ON O.organism_id = CO.organism_id
           ";
         $org_count = chado_query($sql)->fetchField();
         if ($org_count > 0) {
@@ -147,7 +147,7 @@ function tripal_chado_migrate_form($form, &$form_state) {
         $sql =
         "SELECT count(*)
           FROM {analysis} A
-          INNER JOIN {chado_analysis} CA ON A.analysis_id = CA.analysis_id
+          INNER JOIN [chado_analysis] CA ON A.analysis_id = CA.analysis_id
          ";
         $ana_count = chado_query($sql)->fetchField();
         if ($ana_count > 0) {
@@ -163,7 +163,7 @@ function tripal_chado_migrate_form($form, &$form_state) {
         $sql =
           "SELECT count(*)
            FROM {project} P
-           INNER JOIN {chado_project} CP ON P.project_id = CP.project_id
+           INNER JOIN [chado_project] CP ON P.project_id = CP.project_id
           ";
         $proj_count = chado_query($sql)->fetchField();
         if ($proj_count > 0) {
@@ -179,7 +179,7 @@ function tripal_chado_migrate_form($form, &$form_state) {
         $sql =
           "SELECT count(*)
             FROM {featuremap} M
-            INNER JOIN {chado_featuremap} CM ON M.featuremap_id = CM.featuremap_id
+            INNER JOIN [chado_featuremap] CM ON M.featuremap_id = CM.featuremap_id
           ";
         $map_count = chado_query($sql)->fetchField();
         if ($map_count > 0) {
@@ -195,7 +195,7 @@ function tripal_chado_migrate_form($form, &$form_state) {
         $sql =
           "SELECT count(*)
            FROM {pub} P
-           INNER JOIN {chado_pub} CP ON P.pub_id = CP.pub_id
+           INNER JOIN [chado_pub] CP ON P.pub_id = CP.pub_id
          ";
         $proj_count = chado_query($sql)->fetchField();
         if ($proj_count > 0) {
@@ -212,7 +212,7 @@ function tripal_chado_migrate_form($form, &$form_state) {
         $sql =
             "SELECT V.name AS type, X.accession, db.name AS vocabulary , count(*) AS num
               FROM {" . $table . "} T
-              INNER JOIN {" . $tv2_content_type CT . "} ON T.$pkey = CT.$pkey
+              INNER JOIN [" . $tv2_content_type . "] CT ON T.$pkey = CT.$pkey
               INNER JOIN {cvterm} V ON V.cvterm_id = T.type_id
               INNER JOIN {dbxref} X ON X.dbxref_id = V.dbxref_id
               INNER JOIN {db} ON db.db_id = X.db_id
@@ -671,7 +671,7 @@ function tripal_chado_migrate_map_types($tv2_content_types) {
       $sql = "
         SELECT V.name AS type, X.accession, db.name AS vocabulary
         FROM {" . $table . "} T
-          INNER JOIN {" . $tv2_content_type . "} CT ON T.$pkey = CT.$pkey
+          INNER JOIN [" . $tv2_content_type . "] CT ON T.$pkey = CT.$pkey
           INNER JOIN {cvterm} V ON V.cvterm_id = T.type_id
           INNER JOIN {dbxref} X ON X.dbxref_id = V.dbxref_id
           INNER JOIN {db} ON db.db_id = X.db_id

+ 13 - 13
legacy/tripal_feature/includes/tripal_feature.seq_extract.inc → tripal_chado/includes/tripal_chado.seq_extract.inc

@@ -7,9 +7,9 @@
 /**
  * The page allowing users to download feature sequences
  *
- * @ingroup tripal_feature
+ * @ingroup tripal_chado_feature
  */
-function tripal_feature_seq_extract_download() {
+function tripal_chado_feature_seq_extract_download() {
 
   if (!array_key_exists('tripal_feature_seq_extract', $_SESSION)) {
     drupal_goto('find/sequences');
@@ -73,9 +73,9 @@ function tripal_feature_seq_extract_download() {
 /**
  * Form to choose which features to extract sequence for
  *
- * @ingroup tripal_feature
+ * @ingroup tripal_chado_feature
  */
-function tripal_feature_seq_extract_form($form, &$form_state) {
+function tripal_chado_feature_seq_extract_form($form, &$form_state) {
 
   $form['#true'] = TRUE;
 
@@ -180,7 +180,7 @@ function tripal_feature_seq_extract_form($form, &$form_state) {
     '#multiple'      => FALSE,
     '#description'   => t('The organism\'s genus. If specified, features for all organism with this genus will be retrieved.'),
     '#ajax' => array(
-      'callback'    => 'tripal_feature_seq_extract_form_ajax_callback',
+      'callback'    => 'tripal_chado_feature_seq_extract_form_ajax_callback',
       'wrapper' => 'tripal-feature-seq-extract-form',
       'event'   => 'change',
       'method'  => 'replace',
@@ -209,7 +209,7 @@ function tripal_feature_seq_extract_form($form, &$form_state) {
     '#multiple'      => FALSE,
     '#description'   => t('The organism\'s species name. If specified, features for all organisms with this species will be retrieved.  Please first select a genus'),
     '#ajax' => array(
-      'callback'    => 'tripal_feature_seq_extract_form_ajax_callback',
+      'callback'    => 'tripal_chado_feature_seq_extract_form_ajax_callback',
       'wrapper' => 'tripal-feature-seq-extract-form',
       'event'   => 'change',
       'method'  => 'replace',
@@ -363,9 +363,9 @@ function tripal_feature_seq_extract_form($form, &$form_state) {
 /**
  * Theme the Form to choose which features to extract sequence for
  *
- * @ingroup tripal_feature
+ * @ingroup tripal_chado_feature
  */
-function theme_tripal_feature_seq_extract_form(&$variables) {
+function theme_tripal_chado_feature_seq_extract_form(&$variables) {
   $form = $variables['form'];
 
   $headers = array();
@@ -423,16 +423,16 @@ function theme_tripal_feature_seq_extract_form(&$variables) {
 /**
  * Ajax function which returns the form via ajax
  */
-function tripal_feature_seq_extract_form_ajax_callback($form, &$form_state) {
+function tripal_chado_feature_seq_extract_form_ajax_callback($form, &$form_state) {
   return $form;
 }
 
 /**
  * Validate the extract sequence form
  *
- * @ingroup tripal_feature
+ * @ingroup tripal_chado_feature
  */
-function tripal_feature_seq_extract_form_validate($form, &$form_state) {
+function tripal_chado_feature_seq_extract_form_validate($form, &$form_state) {
   $genus      = $form_state['values']['genus'];
   $species    = $form_state['values']['species'];
   $analysis   = $form_state['values']['analysis'];
@@ -467,9 +467,9 @@ function tripal_feature_seq_extract_form_validate($form, &$form_state) {
 /**
  * Submit the extract sequence form
  *
- * @ingroup tripal_feature
+ * @ingroup tripal_chado_feature
  */
-function tripal_feature_seq_extract_form_submit($form, &$form_state) {
+function tripal_chado_feature_seq_extract_form_submit($form, &$form_state) {
   $genus      = $form_state['values']['genus'];
   $species    = $form_state['values']['species'];
   $analysis   = $form_state['values']['analysis'];

+ 154 - 21
tripal_chado/tripal_chado.module

@@ -357,26 +357,6 @@ function tripal_chado_menu() {
     'type' => MENU_NORMAL_ITEM,
     'weight' => 6
   );
-//   $items['admin/tripal/loaders/fasta_loader'] = array(
-//     'title' => 'Chado FASTA File Loader',
-//     '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'),
-//     'file' => 'includes/loaders/tripal_chado.fasta_loader.inc',
-//     'file path' => drupal_get_path('module', 'tripal_chado'),
-//     'type' => MENU_NORMAL_ITEM,
-//   );
-//   $items['admin/tripal/loaders/gff3_load'] = array(
-//     'title' => 'Chado GFF3 File Loader',
-//     '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'),
-//     'file' => 'includes/loaders/tripal_chado.gff_loader.inc',
-//     'file path' => drupal_get_path('module', 'tripal_chado'),
-//     'type' => MENU_NORMAL_ITEM,
-//   );
   $items['admin/tripal/loaders/ncbi_taxonomy_loader'] = array(
     'title' => 'Chado NCBI Taxonomy Loader',
     'description' => 'Loads taxonomic details about installed organisms.',
@@ -684,6 +664,37 @@ function tripal_chado_menu() {
     'type' => MENU_CALLBACK,
   );
 
+  //////////////////////////////////////////////////////////////////////////////
+  //                           FEATURES
+  //////////////////////////////////////////////////////////////////////////////
+  // the menu link for addressing any feature (by name, uniquename, synonym)
+  $items['feature/%'] = array(
+    'page callback' => 'tripal_feature_match_features_page',
+    'page arguments' => array(1),
+    'access arguments' => array('access chado_feature content'),
+    'type' => MENU_LOCAL_TASK,
+  );
+
+  // the administative settings menu
+  $items['find/sequences'] = array(
+    'title' => 'Sequence Retrieval',
+    'description' => 'Download a file of sequences',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('tripal_chado_feature_seq_extract_form'),
+    'access arguments' => array('access chado_feature content'),
+    'file' =>  'includes/tripal_chado.seq_extract.inc',
+    'file path' => drupal_get_path('module', 'tripal_chado'),
+    'type' => MENU_CALLBACK,
+  );
+
+  $items['find/sequences/download'] = array(
+    'page callback' => 'tripal_chado_feature_seq_extract_download',
+    'access arguments' => array('access chado_feature content'),
+    'file' =>  'includes/tripal_chado.seq_extract.inc',
+    'file path' => drupal_get_path('module', 'tripal_chado'),
+    'type' => MENU_CALLBACK,
+  );
+
   return $items;
 }
 
@@ -721,6 +732,10 @@ function tripal_chado_permission() {
  */
 function tripal_chado_theme($existing, $type, $theme, $path) {
   $themes = array(
+    // Themed Forms
+    'tripal_chado_feature_seq_extract_form' => array(
+      'render element' => 'form',
+    ),
 
     'tripal_chado_date_combo' => array(
       'render element' => 'element',
@@ -832,7 +847,7 @@ function tripal_chado_exclude_type_by_default() {
 /**
  * Implements hook_job_describe_args().
  *
- * Describes the arguements for the tripal_populate_mview job to allow for
+ * Describes the arguments for the tripal_populate_mview job to allow for
  * greater readability in the jobs details pages.
  *
  * @param $callback
@@ -901,4 +916,122 @@ function tripal_chado_form_field_ui_field_edit_form_alter(&$form, &$form_state,
   }
 
   // TODO: don't the the maximum length be larger than the field size.
+}
+
+
+/**
+ * Uses the value provided in the $id argument to find all features that match
+ * that ID by name, featurename or synonym.  If it matches uniquenly to a single
+ * feature it will redirect to that feature page, otherwise, a list of matching
+ * features is shown.
+ *
+ * @ingroup tripal_feature
+ */
+function tripal_feature_match_features_page($id) {
+
+  // first check to see if the URL (e.g. /feature/$id) is already
+  // assigned to a node. If so, then just go there.  Otherwise,
+  // try to find the feature.
+  $sql = "
+    SELECT source
+    FROM {url_alias}
+    WHERE alias = :alias
+  ";
+  $match = db_query($sql, array(':alias' => "feature/$id"))->fetchObject();
+  if ($match) {
+    drupal_goto($match->source);
+    return;
+  }
+  $sql = "
+    SELECT
+      F.name, F.uniquename, F.feature_id,
+      O.genus, O.species, O.organism_id,
+      CVT.cvterm_id, CVT.name as type_name,
+      array_agg(S.name) as synonyms
+    FROM {feature} F
+      INNER JOIN {organism} O on F.organism_id = O.organism_id
+      INNER JOIN {cvterm} CVT on CVT.cvterm_id = F.type_id
+      LEFT JOIN {feature_synonym} FS on FS.feature_id = F.feature_id
+      LEFT JOIN {synonym} S on S.synonym_id = FS.synonym_id
+    WHERE
+      F.uniquename = :uname or
+      F.name = :fname or
+      S.name = :sname
+    GROUP BY F.name, F.uniquename, F.feature_id, O.genus, O.species,
+      O.organism_id, CVT.cvterm_id, CVT.name
+  ";
+
+  $args = array(':uname' => $id, ':fname' => $id, ':sname' => $id);
+  $results = chado_query($sql, $args);
+
+  $num_matches = $results->rowCount();
+
+  // If there are no matches then just return a friendly message.
+  if ($num_matches == 0) {
+    drupal_set_message("No features matched the given name '$id'", 'warning');
+    return "No matches found";
+  }
+  // if we have more than one match then generate the table, otherwise, redirect
+  // to the matched feature
+  elseif ($num_matches == 1) {
+    $curr_match = $results->fetchObject();
+    $entity_id = chado_get_record_entity_by_table('feature', $curr_match->feature_id);
+    if ($entity_id) {
+      drupal_goto("bio_data/" . $entity_id);
+      return;
+    }
+    // If we are here it's because we couldn't find the entity. Check if a node
+    // exists (Tv2 backwards compatibility).
+    if (module_exists(tripal_feature)) {
+      $nid = chado_get_nid_from_id('feature', $curr_match->feature_id);
+      drupal_goto("node/" . $nid);
+      return;
+    }
+    // If we are here it's because we couldn't find an entity_id or an nid
+    drupal_set_message("No published features matched the given name '$id'", 'warning');
+    return "No matches found";
+
+  }
+  elseif ($num_matches > 1) {
+    // iterate through the matches and build the table for showing matches
+    $header = array('Uniquename', 'Name', 'Type', 'Species', 'Synonyms');
+    $rows = array();
+    $curr_match;
+    while ($match = $results->fetchObject()) {
+      $curr_match = $match;
+      $synonyms = $match->synonyms;
+      $synonyms = preg_replace('/[\"\{\}]/', '', $synonyms);
+
+      // Build the link to this page.
+      $entity_id = chado_get_record_entity_by_table('feature', $curr_match->feature_id);
+      $link = '';
+      if ($entity_id) {
+        $link = "bio_data/" . $entity_id;
+      }
+      // If we didn't find an entity ID we need to check nodes for
+      // backwards compatibility with Tv2.
+      if (!$entity_id and module_exists(tripal_feature)) {
+        $nid = chado_get_nid_from_id('feature', $curr_match->feature_id);
+        $link = "node/" . $nid;
+      }
+      if (!$link) {
+        continue;
+      }
+
+      $rows[] = array(
+        $match->uniquename,
+        l($match->name, $link),
+        $match->type_name,
+        '<i>' . $match->genus . ' ' . $match->species . '</i>',
+        $synonyms,
+      );
+      $num_matches++;
+    }
+    $table_attrs = array('class' => 'tripal-data-table');
+    $output = "<p>The following features match the name '$id'.</p>";
+    $output .= theme_table($header, $rows, $table_attrs, $caption);
+    return $output;
+  }
+
+
 }

+ 1 - 1
tripal_chado/tripal_chado.views_default.inc

@@ -881,7 +881,7 @@ function tripal_chado_defaultview_admin_db_listing() {
   $handler->display->display_options['title'] = 'Databases';
   $handler->display->display_options['use_more_always'] = FALSE;
   $handler->display->display_options['access']['type'] = 'perm';
-  $handler->display->display_options['access']['perm'] = 'access chado_db content';
+  $handler->display->display_options['access']['perm'] = 'administer db cross-references';
   $handler->display->display_options['cache']['type'] = 'none';
   $handler->display->display_options['query']['type'] = 'views_query';
   $handler->display->display_options['exposed_form']['type'] = 'input_required';

+ 27 - 4
tripal_chado_views/tripal_chado_views.views.inc

@@ -117,6 +117,9 @@ function tripal_chado_views_views_data() {
   // Manually integrate the drupal.tripal_views* tables
   $data = tripal_chado_views_views_data_tripal_views_tables($data);
 
+  // Determine the name of the chado schema
+  $chado_schema = tripal_get_schema_name('chado');
+
   // MAKE SURE ALL CHADO TABLES ARE INTEGRATED
   tripal_chado_views_integrate_all_chado_tables();
 
@@ -218,8 +221,28 @@ function tripal_chado_views_views_data() {
       foreach ($fields as $column => $attrs) {
         $base_fields[$column] = array(
           'column_name' => $column,
+          // Add a default for type since module developers may sometimes need to use a
+          // PostgreSQL-specific type.
           'type' => (isset($attrs['type'])) ? $attrs['type'] : 'text',
         );
+        // If PostgreSQL-specifc types are needed the module developer should be given
+        // a way to set the most closely matching type for views. They should also be
+        // allowed to override the type for views. This can be done by adding a views_type
+        // to the schema definition :-).
+        if (isset($attrs['views_type'])) {
+          $base_fields[$column]['type'] = $attrs['views_type'];
+        }
+        // Tell admin about this feature and warn them that we made an assumption for them.
+        if (!isset($attrs['type']) AND !isset($attrs['views_type'])) {
+          tripal_report_error(
+              'tripal_views',
+              TRIPAL_WARNING,
+              "Unable to determine the type for %column thus we have defaulted to type 'text'.
+              Tip: This may be due to setting a  postgresql-specific type. Solution: Add a
+              'views_type' to your schema definition to specify what type should be used.",
+              array('%column' => $column)
+          );
+        }
       }
 
       // get the field name and descriptions
@@ -239,7 +262,7 @@ function tripal_chado_views_views_data() {
         'group' => "$tvi_row->name",
         'title' => "$tvi_row->name",
         'help'  => $tvi_row->comment,
-        'search_path' => 'chado'
+        'search_path' => $chado_schema
       );
     }
     else {
@@ -247,7 +270,7 @@ function tripal_chado_views_views_data() {
         'group' => "$tvi_row->name",
         'title' => "$tvi_row->name",
         'help'  => $tvi_row->comment,
-        'search_path' => 'chado'
+        'search_path' => $chado_schema
       );
     }
 
@@ -264,7 +287,7 @@ function tripal_chado_views_views_data() {
 
         tripal_report_error(
           'tripal_chado_views',
-          TRIPAL_WARNING,
+          TRIPAL_DEBUG,
           "The name and help were not set for %table.%column. As a consequence the column
             name has been used... You should ensure that the 'name' and 'help' keys for
             this field are set in the integration array (priority = %priority)",
@@ -305,7 +328,7 @@ function tripal_chado_views_views_data() {
       if ($num_handlers == 0) {
         tripal_report_error(
           'tripal_chado_views',
-          TRIPAL_WARNING,
+          TRIPAL_DEBUG,
           "No handlers were registered for %table.%column. This means there is no views
             functionality for this column. To register handlers, make sure the 'handlers'
             key for this field is set in the integration array (priority = %priority).

+ 15 - 14
tripal_chado_views/views/handlers/tripal_views_handler_filter_select_cvterm.inc

@@ -7,8 +7,8 @@
 /**
  * This Handler provides a select list for the type field
  *
- *  NOTE: This handler only works when applied to the type_id field in the base_table of
- *  this view.
+ *  NOTE: This handler only works when applied to the type_id field in the
+ *  base_table of this view.
  *
  * @ingroup tripal_views
  */
@@ -19,7 +19,8 @@ class tripal_views_handler_filter_select_cvterm extends tripal_views_handler_fil
    * Override this function in extended handlers to easily change option list.
    *
    * @return
-   *   An array of options where the key is the value of this field in the database
+   *   An array of options where the key is the value of this field in the
+   *   database
    */
   function get_select_options() {
 
@@ -36,7 +37,7 @@ class tripal_views_handler_filter_select_cvterm extends tripal_views_handler_fil
 
         $return = $this->get_select_option_where($this->table);
         $where_clauses = $return['where_clauses'];
-        $arguements = $return['arguements'];
+        $arguments = $return['arguments'];
         $base_where = '';
         if (!empty($where_clauses)) {
           $base_where = implode(' AND ', $where_clauses);
@@ -69,7 +70,7 @@ class tripal_views_handler_filter_select_cvterm extends tripal_views_handler_fil
         // show these exact types.
         $return = $this->get_select_option_where('cvterm');
         $where_clauses = $return['where_clauses'];
-        $cvterm_args = $return['arguements'];
+        $cvterm_args = $return['arguments'];
         $cvterm_where = '';
         if (!empty($where_clauses)) {
           $cvterm_where = implode(' AND ', $where_clauses);
@@ -78,13 +79,13 @@ class tripal_views_handler_filter_select_cvterm extends tripal_views_handler_fil
         // have been used.
         $return = $this->get_select_option_where($this->table);
         $where_clauses = $return['where_clauses'];
-        $base_args = $return['arguements'];
+        $base_args = $return['arguments'];
         $base_where = '';
         if (!empty($where_clauses)) {
           $base_where = implode(' AND ', $where_clauses);
         }
-        // We only supply one set or arguements those so merge the two.
-        $arguements = array_merge($cvterm_args, $base_args);
+        // We only supply one set or arguments those so merge the two.
+        $arguments = array_merge($cvterm_args, $base_args);
 
         // Using a "Loose Index Scan" to get a list of all the cvs used
         // in the table the drop-down filter is from.
@@ -110,7 +111,7 @@ class tripal_views_handler_filter_select_cvterm extends tripal_views_handler_fil
             ORDER BY cvterm.name ASC";
         $sql = format_string($sql, array('!table' => $this->table, '!field' => $this->field));
       }
-      $resource = chado_query($sql, $arguements);
+      $resource = chado_query($sql, $arguments);
 
       // Now actually gerenate the select list
       // based on the results from the above query.
@@ -130,7 +131,7 @@ class tripal_views_handler_filter_select_cvterm extends tripal_views_handler_fil
       // show these exact types.
       $return = $this->get_select_option_where('cvterm');
       $where_clauses = $return['where_clauses'];
-      $cvterm_args = $return['arguements'];
+      $cvterm_args = $return['arguments'];
       $cvterm_where = '';
       if (!empty($where_clauses)) {
         $cvterm_where = implode(' AND ', $where_clauses);
@@ -139,13 +140,13 @@ class tripal_views_handler_filter_select_cvterm extends tripal_views_handler_fil
       // have been used.
       $return = $this->get_select_option_where($this->table);
       $where_clauses = $return['where_clauses'];
-      $base_args = $return['arguements'];
+      $base_args = $return['arguments'];
       $base_where = '';
       if (!empty($where_clauses)) {
         $base_where = implode(' AND ', $where_clauses);
       }
-      // We only supply one set or arguements those so merge the two.
-      $arguements = array_merge($cvterm_args, $base_args);
+      // We only supply one set or arguments those so merge the two.
+      $arguments = array_merge($cvterm_args, $base_args);
 
       // Using a "Loose Index Scan" to get a list of all the cvterms used
       // in the base table. See https://wiki.postgresql.org/wiki/Loose_indexscan
@@ -167,7 +168,7 @@ class tripal_views_handler_filter_select_cvterm extends tripal_views_handler_fil
           ORDER BY cvterm.name ASC";
       $sql = format_string($sql, array('!table' => $this->table, '!field' => $this->field));
 
-      $resource = chado_query($sql, $arguements);
+      $resource = chado_query($sql, $arguments);
       $cvterms = array();
 
       // Add an "- Any - " option to allow a type to not be set by default.

+ 5 - 5
tripal_chado_views/views/handlers/tripal_views_handler_filter_select_id.inc

@@ -1,7 +1,7 @@
 <?php
 /**
  * @file
- * Contains tripal_views_handler_filter_select_cvterm
+ * Contains tripal_views_handler_filter_select_id
  */
 
 /**
@@ -48,10 +48,10 @@ class tripal_views_handler_filter_select_id extends tripal_views_handler_filter_
     if (isset($this->options['show_all']) AND $this->options['show_all'] == TRUE) {
 
       // We still want to use any hidden fitlers on the parent table
-      // but the arguements will need to be field names rather than
+      // but the arguments will need to be field names rather than
       // generic placeholders so we need to tell get_select_option_where() that.
       $return = $this->get_select_option_where($this->parent_table, FALSE);
-      $args = $return['arguements'];
+      $args = $return['arguments'];
 
       // Simply grab all the values from the table referenced by
       // the foreign key constraint. Since we use the id as the key of
@@ -67,7 +67,7 @@ class tripal_views_handler_filter_select_id extends tripal_views_handler_filter_
 
       $return = $this->get_select_option_where($this->parent_table);
       $where_clauses = $return['where_clauses'];
-      $arguements = $return['arguements'];
+      $arguments = $return['arguments'];
       $where = '';
       if (!empty($where_clauses)) {
         $where = implode(' AND ', $where_clauses);
@@ -102,7 +102,7 @@ class tripal_views_handler_filter_select_id extends tripal_views_handler_filter_
         '!name_field' => $name_field
       ));
 
-      $resource = chado_query($sql, $arguements);
+      $resource = chado_query($sql, $arguments);
       $options = array();
 
       if ($this->options['select_optional']) {

+ 3 - 3
tripal_chado_views/views/handlers/tripal_views_handler_filter_select_string.inc

@@ -88,7 +88,7 @@ class tripal_views_handler_filter_select_string extends views_handler_filter_str
 
     $return = $this->get_select_option_where();
     $where_clauses = $return['where_clauses'];
-    $arguements = $return['arguements'];
+    $arguments = $return['arguments'];
     $where = '';
     if (!empty($where_clauses)) {
       $where = ' WHERE ' . implode(' AND ', $where_clauses);
@@ -96,7 +96,7 @@ class tripal_views_handler_filter_select_string extends views_handler_filter_str
 
     // get the values from the table
     $sql = 'SELECT ' . $this->real_field . ' FROM {' . $this->table . '} ' . $where . ' ORDER BY ' . $this->field . ' ASC';
-    $results = chado_query($sql, $arguements);
+    $results = chado_query($sql, $arguments);
 
     // Build the select box options
     $max_length = (isset($this->options['max_length'])) ? $this->options['max_length'] : 40;
@@ -177,7 +177,7 @@ class tripal_views_handler_filter_select_string extends views_handler_filter_str
 
     return array(
       'where_clauses' => $where,
-      'arguements' => $values
+      'arguments' => $values
     );
   }
 

+ 1 - 1
tripal_daemon/TripalDaemon.inc

@@ -204,7 +204,7 @@ class TripalDaemon extends DrushDaemon {
     drush_invoke_process(
       '@self',                               // Obviously run on the current site.
       'trp-run-jobs',                        // Run the tripal job launcher.
-      array(),                               // No arguements (only options below).
+      array(),                               // No arguments (only options below).
       array(
         'job_id' => $job_id,                 // The job to be run.
         'username' => $username,             // The user to run it as.

Niektoré súbory nie sú zobrazené, pretože je v týchto rozdielových dátach zmenené mnoho súborov